App Widget getting hijacked by Google Sound Search? - widget

So I'm seeing some bizarre behavior in an appwidget that I wrote.
The widget itself is quite simple - it reads a few values from persistent storage and then displays them as text. Nothing fancy in the layout - just a FrameLayout root element with some Linear Layout and TextView children.
The widget has a simple configuration activity associated with it.
The bizarre behavior is that the widget will initially show "Problem Loading Widget" after the user closes the configuration activity, and then after a few seconds it shows a "Google Sound Search" button (and clicking on the button actually does launch Google Sound Search). Then, after a few more seconds, it finally shows the expected display.
I am away from my code right now, so I'll have to wait until tonight to post code snippets. However, in the meantime, can anyone provide some insight into how such a thing could happen? Has anyone else ever experienced this? How could another widget "hijack" mine?
Thanks,
-Ron
Here are some screenshots:

There are a couple of issues with your widget and there are answers to all of them (although you didn't post any code so some of my statements are based on assumptions):
"Problem loading widget": this is the default view Android uses before the widget is initialized and the layout updated. Simply add the following line to your widget xml configuration (to show a loading message instead of the problem message):
android:initialLayout="#layout/my_cool_widget_loading_message"
If the widget shows the wrong layout then you probably have an issue in the widget's onReceive method. onReceive is called for all the widgets no matter whether the broadcast is for that specific widget. Android's AppWidgetProvider filters the broadcasts by appwidget Id and dispatches to the other methods (like onUpdate).
See also: https://developer.android.com/reference/android/appwidget/AppWidgetProvider.html#onReceive(android.content.Context, android.content.Intent).
If you override onReceive (which I assume you do), you need to call through to super.onReceive(Context, Intent) to make sure your other methods don't get calls meant for other widgets.
Now for the configuration of the widget. If you follow the Google documentation then it will all work nicely. The only improvement I'd do is what my other answer that you reference suggests (https://stackoverflow.com/a/14991479/534471). This will NOT send out two broadcasts. The setResult()/finish() part does only terminate the config Activity and let Android know whether to actually add the widget or not (depending on whether the result is RESULT_CANCELED or RESULT_OK.
From your own answer I can see why your code wouldn't work. The code is:
Intent intent = new Intent();
intent.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, new int[] {mAppWidgetId});
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, mAppWidgetId);
setResult(RESULT_OK, intent);
sendBroadcast(intent);
finish();
First of all there's no need to add the appWidgetId twice, use the AppWidgetManager.EXTRA_APPWIDGET_IDS version and you're good. Second you're using the same Intent to return as a result for the Activity. AFAIK it's not documented what happens when you do set an action on that Intent but my experience with Android widgets is that you need to stick exactly to the documentation or you'll end up having strange issues (like the ones you encounter). So please use two different Intents.
Activity result:
Intent resultValue = new Intent();
resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, mAppWidgetId);
setResult(RESULT_OK, resultValue);
finish();
Broadcast:
Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE, null, this, MyWidget.class);
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, new int[] {mAppWidgetId});
sendBroadcast(intent);

ok, so I figured it out. Posting here in case anyone else runs into this. I think that the Android Developer docs are a little misleading here.
The problem was that in my configuration Activity, I had this code at the end:
Intent intent = new Intent();
intent.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, new int[] {mAppWidgetId});
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, mAppWidgetId);
setResult(RESULT_OK, intent);
sendBroadcast(intent);
finish();
Providing an intent with the extra EXTRA_APPWIDGET_ID is recommended by the documentation provided by google.
However, that same document says that you have to update the widget's view by creating a RemoteView and calling AppWidgetManager.updateAppWidget() like so:
RemoteViews views = new RemoteViews(context.getPackageName(),
R.layout.example_appwidget);
appWidgetManager.updateAppWidget(mAppWidgetId, views);
I didn't like the idea of placing the presentation logic in both the configuration activity and the widget class, so I instead decided to broadcast an intent at the end of the configuration activity to tell the widget to redraw itself. That's why I have setResult() AND sendBroadcast() at the end of the activity. The documentation further states that the onUpdate() callback will not be called when using a configuration activity. So this seemed neccessary. I added the ACTION_APPWIDGET_UPDATE and the EXTRA_APPWIDGET_IDS to the intent so that it would trigger the onUpdate() method. This practice was recommended by this SO answer (albeit without being included in the activity result intent - but I tried separating the two and it had no effect).
Now I'm not certain exactly how the "Google Sound Search" widget got in there, nor do I fully understand the mechanics of how the intents interacted to produce the observed results. However, as soon as I replaced my code above with the code stated in the docs, the widget was updated properly.
Intent resultIntent = new Intent();
resultIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, mAppWidgetId);
setResult(RESULT_OK, resultIntent);
finish();
This seems to contradict the documentation's statement that the configuration activity must update the widget's view. Simply providing the configuration activity result as below triggers the onUpdate() method in the widget, thus allowing the widget to redraw itself. I confirmed the behavior on an emulator running API 23 and also on a Samsung device running Samsung's android flavor.

Related

Mysterious ES6 templates side effects whilst debugging [duplicate]

I am currently reading Async Javascript by Trevor Burnham. This has been a great book so far.
He talks about this snippet and console.log being 'async' in the Safari and Chrome console. Unfortunately I can't replicate this. Here is the code:
var obj = {};
console.log(obj);
obj.foo = 'bar';
// my outcome: Object{}; 'bar';
// The book outcome: {foo:bar};
If this was async, I would anticipate the outcome to be the books outcome. console.log() is put in the event queue until all code is executed, then it is ran and it would have the bar property.
It appears though it is running synchronously.
Am I running this code wrong? Is console.log actually async?
console.log is not standardized, so the behavior is rather undefined, and can be changed easily from release to release of the developer tools. Your book is likely to be outdated, as might my answer soon.
To our code, it does not make any difference whether console.log is async or not, it does not provide any kind of callback or so; and the values you pass are always referenced and computed at the time you call the function.
We don't really know what happens then (OK, we could, since Firebug, Chrome Devtools and Opera Dragonfly are all open source). The console will need to store the logged values somewhere, and it will display them on the screen. The rendering will happen asynchronously for sure (being throttled to rate-limit updates), as will future interactions with the logged objects in the console (like expanding object properties).
So the console might either clone (serialize) the mutable objects that you did log, or it will store references to them. The first one doesn't work well with deep/large objects. Also, at least the initial rendering in the console will probably show the "current" state of the object, i.e. the one when it got logged - in your example you see Object {}.
However, when you expand the object to inspect its properties further, it is likely that the console will have only stored a reference to your object and its properties, and displaying them now will then show their current (already mutated) state. If you click on the +, you should be able to see the bar property in your example.
Here's a screenshot that was posted in the bug report to explain their "fix":
So, some values might be referenced long after they have been logged, and the evaluation of these is rather lazy ("when needed"). The most famous example of this discrepancy is handled in the question Is Chrome's JavaScript console lazy about evaluating arrays?
A workaround is to make sure to log serialized snapshots of your objects always, e.g. by doing console.log(JSON.stringify(obj)). This will work for non-circular and rather small objects only, though. See also How can I change the default behavior of console.log in Safari?.
The better solution is to use breakpoints for debugging, where the execution completely stops and you can inspect the current values at each point. Use logging only with serialisable and immutable data.
This isn't really an answer to the question, but it might be handy to someone who stumbled on this post, and it was too long to put in a comment:
window.console.logSync = (...args) => {
try {
args = args.map((arg) => JSON.parse(JSON.stringify(arg)));
console.log(...args);
} catch (error) {
console.log('Error trying to console.logSync()', ...args);
}
};
This creates a pseudo-synchronous version of console.log, but with the same caveats as mentioned in the accepted answer.
Since it seems like, at the moment, most browsers' console.log's are asynchronous in some manner, you may want to use a function like this in certain scenarios.
When using console.log:
a = {}; a.a=1;console.log(a);a.b=function(){};
// without b
a = {}; a.a=1;a.a1=1;a.a2=1;a.a3=1;a.a4=1;a.a5=1;a.a6=1;a.a7=1;a.a8=1;console.log(a);a.b=function(){};
// with b, maybe
a = {}; a.a=function(){};console.log(a);a.b=function(){};
// with b
in the first situation the object is simple enough, so console can 'stringify' it then present to you; but in the other situations, a is too 'complicated' to 'stringify' so console will show you the in memory object instead, and yes, when you look at it b has already be attached to a.

gtkmm's answer to gdk_threads_enter() or SwingUtilities.invokeLater()

I am writing a gtkmm3 application and I need to create and show new GUI elements from a non-GUI thread. Specifically, I am trying to add a tab to a notebook.
I create the notebook in the gui thread like so:
Glib::RefPtr<Gtk::Application> app = Gtk::Application::create(argc, argv, "org.gtkmm.examples.base");
if(!Glib::thread_supported()) Glib::thread_init();
Gtk::Window window;
notebook = new Gtk::Notebook();
window.add(*notebook);
notebook -> show();
Worker bee;
bee.start();
return app->run(window);
and the I create and add a new tab like so:
Gtk::Label label("label");
Gtk::Label child("child");
notebook -> append_page(child, label);
notebook -> show_all();
If I insert the tab creation code before notebook->show() it works fine. But if I put the tab creation code into its own worker thread, the new tab never shows.
I'm guessing that the failure has to do with the fact that the new tab is created on the worker thread and that violates gtkmm's GUI stuff on the GUI thread convention.
The trouble is that the worker thread is responsible for creating new tabs, and I don't know how many tabs to create at compile time.
In APIs like Swing, and gtk+ there are mechanisms to handle this case. In Swing there is an invokeLater method that allows me to pass a lambda to the GUI thread for invokation, and gtk+ uses gdk_threads_enter/leave to ensure that only one thread is playing the GUI at once.
What is gtkmm's answer to this issue?
In general you should just avoid ever using GTK+ (or gtkmm) UI API from anything but the main thread. It's not meant to work.
You need to let the main thread respond when the other thread says that it should, instead of actually doing the UI work in the other thread. People like to use Glib::Dispatcher for this with gtkmm: https://developer.gnome.org/gtkmm-tutorial/stable/sec-using-glib-dispatcher.html.en .
But also think hard about whether you really need another thread at all. It might be fine to do the work in an idle handler: https://developer.gnome.org/gtkmm-tutorial/stable/sec-idle-functions.html.en

Passing back value from Browse-Child VM chain to caller

MVVMCross
Windows Store
Android
I have a VM that browses a hierarchy (BrowseVm) and supports forward navigation via
ShowViewModel<LeafDetailVM>
to a leaf detail ViewModel (LeafDetailVM).
When the user is on the LeafDetail View they should be able to say "I want this one" and they will be returned to the View that initiated BrowseVm.
I cannot simply Forward Navigate to the Initiator because that would leave me with an invalid back stack. I cannot have the BrowseVM view as a NoHistory page as I need it be in the back stack to support going back from the LeafDetail view.
My plan is to have the initiator start BrowseVm with a GUID. BrowseVm will pass that GUID onto LeafDetailVM.
In the "I want this one" command I will raise a Message, containing the GUID, that both BrowseVM and the initiator are subscribed to. Then I will close LeafDetailVM.
When BrowseVM receives the notification of the message it will compare the GUID and if it matches it will close itself.
When the initiator receives the notification it will deal with the now chosen data.
Does this make sense? Have I missed a much simpler way of doing this?
This is similar to How to pass a parameter from a viewmodel to its parent viewmodel but that does not deal with the back stack.
Thanks
I suggest you try stop mentally coupling how the views work on a platform to the view-models.
With the custom presenter mechanism in MvvmCross, in the app (platform specific code) you can handle navigation to a certain view-model in different ways, including closing views, modify backstack, etc.
You can interpret navigation to a view-model in whatever way you want \ need.
You can for example pass from view-model some parameters in the ShowViewModel request which the view-presenter (IMvxViewPresenter) can interpret in different ways in the Show() to display a view-model.
In your case, you can actually navigate to initiator VM passing the selected info. In the view presenter, you can modify the backstack in the way you need.
On Android, make sure you read and know about all LaunchMode flags, for example LaunchMode.SingleTask which allows you bring the initiator activity to front without creating a new one.
It's not clear to me, is BrowseVm a parent view-model to the LeafDetailVM?
More info would be needed to understand exactly your scenario.

What is the difference between the BU and ZK OK codes in SAP macro

I am trying the post an invoice to SAP using the F-47 transaction and using SHDB to record the transaction and learn how it works. I see there that sometimes BU and ZK BDC OK codes are used. I would like to understand the difference between them, but could not find any official documentation. Please, explain the difference between the two?
I found the meaning of some of the status codes. I post it here, so I can remember:
/00. Enter
/AB Go to overview
=ZK Go to additional information
=ENTE Enter (don't know exactly what is difference between /00)
=PI select cursor location
=STER Go to taxes
=DELZ delete cursor
=GO continue
=BU post (save)
/EEND end processing
=Yes select "yes" from message box
=BP park (save)
=ENTR Enter (don't know exactly what is difference between =ENTE or /00)
=AE save when changing document
=BK change document header (parking or posting parked document)
=P+ next page
=BL delete parked document
A BDC_OKCODE indicates which action is (will) be executed on a screen (things like save, back, exit etc). The BU code is used for a SAVE function (like in MM01 transaction). Sorry but I cannot recall to which function ZK maps to. Obviously their difference lies in the fact that they map to different functions. You can still find out which function each button utilizes by using System->Status->GUI status.
By the way, BTCI transactions are not fully robust- minor changes in GUI flow let your program break. Error handling / analysis is tedious.... DId you have a look to posting methods more preferably? E.g. like BAPI_* function modules? With the help of LSMW you can browse for different input methods and use them later standalone. Or you can use transaction BAPI directly.

Is it possible to know whether Windows widget totally covered by other windows?

We want to create a Windows desktop version of our weather widget
There are 2 special things about the widget.
It consumes a lot of processor time
while active - it displays an
animated picture (Flash without GPU acceleration, unfortunately).
It updates the weather from our
server (frequent server requests from all widget users).
When the user does not look at the widget there is no need for animation and weather loading.
So I have an idea of putting my widget to sleep when it is not visible and hense not used.
Is it possible to detect whether the widget is used or not.
Speaking precisely I need to know whether the widget is covered by other windows?
I mostly interested in Vista/7 gadgets engine, however I also would like to know if this problem is solved in these widget engines
Yahoo widgets
Google desktop
Hope to find some desktop widget guru here.
Pasha
If you InvalidateRect and don't get a subsequent WM_PAINT message, than your window is hidden. You can call UpdateWindow after InvalidateRect to force the WM_PAINT message to happen (or not happen) right away.
So you could do something like this
request server data (and cancel request timer if any)
when data arrives InvalidateRect
when WM_PAINT message arrives, draw the data and set a timer for next request
when timer arrives, goto 1
When you stop getting WM_PAINT messages, you stop re-setting your timer, and you therefor stop requesting updates from the server. When the WM_PAINT message happens (because you are no longer covered). You start requesting data again.