I have a really simple appwidget (two text views and a button). I've tested it on a Touchpad, Droid 1, and a Droid Razr. It works on everything except the Razr. When I add the widget to the homescreen it doesn't display; it's just invisible. If I hold down on the spot where it would be it selects a widget and if I move it around I see other widgets move out of the way but it's completely invisible.
I put some Toasts in the onReceive and onEnabled methods and the Toast displays all the right information (ie intent action and extras).
Anybody have any experience with this?
EDIT: Please keep in mind this is just for debugging and does not follow best practices
public class GoogleTalkWidget extends AppWidgetProvider {
Button sendMessage;
#Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "Received Intent Action = " +
intent.getAction(), Toast.LENGTH_SHORT).show();
if(intent.getAction().equals(Utils.RECEIVED_MESSAGE_WIDGET)){
RemoteViews views = new RemoteViews(context.getPackageName(),
R.layout.main_widget);
views.setTextViewText(R.id.widget_message,
(CharSequence)intent.getStringExtra("MESSAGE"));
views.setTextViewText(R.id.widget_sender,
(CharSequence)intent.getStringExtra("SENDER"));
Toast.makeText(context, "Received " +
intent.getStringExtra("MESSAGE") + " FROM " +
intent.getStringExtra("SENDER"), Toast.LENGTH_SHORT).show();
ComponentName cn = new ComponentName(context,
GoogleTalkWidget.class);
AppWidgetManager.getInstance(context).updateAppWidget(cn, views);
}
super.onReceive(context, intent);
}
#Override
public void onEnabled(final Context context){
super.onEnabled(context);
Toast.makeText(context, "Enabled", Toast.LENGTH_SHORT).show();
}
}
The best thing I can think of (supposed there isn't a bug or other problem with the launcher of the Razr) is that your resources aren't configured correctly. Maybe the Razr has a different dpi density and there aren't resources for that density in your project.
Try for example to move all of the drawables that make up your widget to the folder res\drawable-nodpi and see how it's going.
EDIT: I saw something strange in your code
In your GoogleTalkWidget class onReceive method, your widget is only updated when the message Utils.RECEIVED_MESSAGE_WIDGET is received. I don't know what this message is for but an app-widget, the first time is added on the home screen, it receives the android.appwidget.action.APPWIDGET_UPDATE and any other intent filters are registered in the manifest file and they are broadcasted by the system at that time (and the sticky broadcasts intents of course).
If I was in your position I would change the onReceive method as follows:
#Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "Received Intent Action = " +
intent.getAction(), Toast.LENGTH_SHORT).show();
super.onReceive(context, intent);
String msg = "No messages yet";
RemoteViews views = new RemoteViews(context.getPackageName(),
R.layout.main_widget);
if(intent.getAction().equals(Utils.RECEIVED_MESSAGE_WIDGET)){
msg = intent.getStringExtra("MESSAGE");
views.setTextViewText(R.id.widget_sender,
(CharSequence)intent.getStringExtra("SENDER"));
Toast.makeText(context, "Received " +
intent.getStringExtra("MESSAGE") + " FROM " +
intent.getStringExtra("SENDER"), Toast.LENGTH_SHORT).show();
ComponentName cn = new ComponentName(context,
GoogleTalkWidget.class);
}
views.setTextViewText(R.id.widget_message, msg);
AppWidgetManager.getInstance(context).updateAppWidget(cn, views);
}
and see what happens.
If your widget fails to appear then it could be a problem with Razr but this is unlike because I suppose that a whole bunch of other widgets works fine.
Furthermore, although your code is for debugging only, your approach is a little bit problematic. The best place to update your widget views is in the onUpdate method of the AppWidgetProvider and not in the onReceive. Android provides the onUpdate method for that purpose and the onReceive to inform you that a registered broadcast has arrived. The basic difference is that in onUpdate method, Android has extracted all the needed parameters for you from the received Intent extras. One more thing about widget updates is that you should provide an android:updatePeriodMillis value other than 0 (2100000 is a good value) in your widget xml file even if you don't want periodic updates for your widget. I saw somewhere that the onReceive method may not be called if this value is 0.
Keep in mind also that AppWidgetProvider as a Broadcast Receiver lives only as long as the onReceive method does its job, after that is is destroyed thus it is not a good place for "interactive" code like UI listeners etc. I am telling you this because you have a Button declaration (Button sendMessage;) in the top of your GoogleTalkWidget class.
Hope this helps...
Related
We are having trouble with local broadcasts. For some reason in 2 androids(my own phone + boss's phone) it works fine. On another phone(galaxy s3 mini like my boss) and on boss's tablet it however crash. Program crash if the tmp.sendBroadcast command is but not right away(it still does bit after that). However it never gets to receiver.
public class UpdaterIntent extends IntentService {
...
Intent intent = new Intent("my-event");
intent.putExtra("action", "update_workplaces");
intent.putExtra("parameters", time);
LocalBroadcastManager'tmp=LocalBroadcastManager.getInstance(myInst);
if(tmp!=null) {
tmp.sendBroadcast(intent);
}
I have registered receiver like this:
LocalBroadcastManager.getInstance(this).registerReceiver(mMessageReceiver,
new IntentFilter("my-event"));
Receiver is this:
private BroadcastReceiver mMessageReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(myContext, "received message", Toast.LENGTH_SHORT).show();
}
}
};
I have tried to search for some reason why it might be so. Thought it might have been too long parameters as putExtra but even after trimming it to two strings(one seen in code, one is just a date that comes from server like "2014-03-28 12:20:02" etc so now there shouldn't be danger of exceeding some hard coded limit.
Any suggestions? Don't like any workarounds to this that I have come up with being clumsy as hell.
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
I'm creating a fairly common use case of AppWidget on Android.
AppWidgetProvider calls onAppWidgetOptionsChanged() (stretchable widget) and onUpdate() (timed)
From those methods I start an IntentService. Case coming from options changed I pass the new size in the Intent.
The service contacts a web-service, builds the RemoteViews and calls updateAppWidget()
my main test device is a Nexus 7 (2012) running stock 4.3 (stock Launcher)
The widget does not use RemoteViewFactory and does not user AlarmManager. It's a static view with a constant time defined in XML.
It works most of the times, but sometimes the call to updateAppWidget() is completely ignored by the Launcher and no update happens on the screen. If I force close the launcher, clear it caches and re-size the widget (forcing an update) then it updates.
I believe there's something to do with frequency of update because I tricked up some stuff in the IntentService to, whenever it's resizing, only call to the last intent (when the user stops messing with the widget) and it soften a bit the issue.
Let's show some simplified code (it's very standard, i believe):
public class AlbumWidgetService extends WidgetUpdateIntentService {
#Override
protected void onHandleIntent(Intent intent) {
// get's widgetID or array of IDs and pass to 'doTheJob'
}
private void doTheJob(int appWidgetId, int heightInDp, int widthInDp) {
// ...
// here goes code with pre calculations and get data
// ...
// create Intent and PendingIntent with some extras
Intent intent = ... etc
PendingIntent pi = PendingIntent.getActivity( ... etc
// get url for some images
List<String> imageFilenames = getImagesFilename(albumId, totalImages);
// Create the remote view
RemoteViews views = new RemoteViews(getPackageName(), R.layout.album_widget);
// ...
// here goes a bunch of code that load bitmaps from the URLs
// set text and colors in the remote view
// put ImageViews into the remote view, etc
// ...
try {
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(this);
appWidgetManager.updateAppWidget(appWidgetId, views);
Log.d(this, "Updating the widget id " + appWidgetId);
} catch (Exception e) {
// this exception happens if the RemoteView is too big, have too many bitmaps.
// I'm already minizing this to happen with the pre calculations, but better safe than sorry
Log.e(this, "Failed to update the widget id " + appWidgetId, e);
}
}
as I said, the thing mostly works (I can see the Log and I can see the on-screen result. But every once in a while it does not update after a resize, even thou I can see the Log and it did not crashes or anything.
ideas?
My widget gets data from the internet every 3 minutes, some are displayed directly on the widget and others are stored in SharedPreferences so when the user taps on the widget that information appears as a dialog. When having more than one widget running, no matter which widget I click the log says the appWidgetId comes from one of them always
My problem seems to be the way I'm declaring the widget's setOnClickPendingIntent(). I'm doing this inside the service, right before fetching the data and since the same service is run by every (widget) AlarmManager, every widget gets the PendingIntent from the last service ran.
public class WidgetService extends Service
{
#Override
public void onStart(Intent intent, int startId)
{
Intent intentUmbrales = new Intent(context, LaunchUmbralesDialog.class);
intentUmbrales.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
PendingIntent pendingIntentUmbrales = PendingIntent.getActivity(context,0,intentUmbrales,0);
// Get the layout for the App Widget and attach an on-click listener to the button
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget);
// views.setOnClickPendingIntent(R.id.energia_widget, pendingIntentImei);
views.setOnClickPendingIntent(R.id.imageLogo_widget, pendingIntentUmbrales);
//..then I fetch data, store the rest in SharedPreferences and update widget remoteViews
}
}
How can I avoid this? How can I make an individual "button" for each widget with getting them overlapped? Also note that I've already tried to declare those PendingIntents in the AppWidgetProvider's onUpdate() method (inside a loop for every appWidgetId from the array given by the method)
Thanks in advance!
Regards, Rodrigo.
When declaring the .setOnClickPendingIntent() first add to the Intent
Uri data = Uri.withAppendedPath(
Uri.parse(URI_SCHEME + "://widget/id/")
,String.valueOf(appWidgetId));
intent.setData(data);
so that each widget gets a unique ID and they don't get messed up!
EDIT: I found the solution, see below
My first post on StackOverFlow. However I have been reading about this problem for a while without a solution that works.
What I would like to do is register the following Intent: android.nfc.action.TAG_DISCOVERED
I am doing the following in my Code:
IntentFilter filter = new IntentFilter();
filter.addAction("android.nfc.action.TAG_DISCOVERED");
filter.addCategory("android.intent.category.DEFAULT");
Log.d(TAG, "Created the new filter");
reciever = new NFCBroadcastReciever(this);
Log.d(TAG, "Created the new Broadcast Reciever");
this.registerReceiver(reciever, filter);
Log.d(TAG, "Registered new reciever");
The BroadCastReciever is defined as follows:
public class NFCBroadcastReciever extends BroadcastReceiver {
private Screen screen;
public static String TAG = "NFCBroadcastReciever";
NFCBroadcastReciever(Screen _screen){
screen = _screen;
}
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
Log.d(TAG, "Action recieved: "+action);
if(action != null && NfcAdapter.ACTION_TAG_DISCOVERED.equals(action)){
paymentScreen.onNewIntent(intent);
}
}
}
However I get an exception that the intent being fired from a tag read has no corresponding Activity. I would like to be able to only start listening for NFC events at a certain point in my application.
Thanks in advance for your help.
I found the solution to the problem actually, the key to getting NFC events to occur only on a specific activity while it is active and not when other activities are running. The sample in the Android SDK explains it: http://developer.android.com/resources/samples/ApiDemos/src/com/example/android/apis/nfc/ForegroundDispatch.html
I found the solution to the problem actually, the key to getting NFC events to occur only on a specific activity while it is active and not when other activities are running. The sample in the Android SDK explains it: http://developer.android.com/resources/samples/ApiDemos/src/com/example/android/apis/nfc/ForegroundDispatch.html
Is your intention to start an activity when the broadcast is received? It doesn't seem to me that paymentScreen.onNewIntent(intent); is going to accomplish that. Instead, you will likely need to build an intent that you can use with startActivity() and you'll likely want to include the relevant data from your broadcast receiver's intent into your activity intent in the form of extras.
I've made an Android home screen widget which displays some text and has 2 click listeners which I have working under normal operation, no problems. That is until HTC sense/launcher decides to reload, which it does most days. After the reload one of the click listeners stops working and can cause the widget to Force Close.
onClickListener 1 = starts an activity and passes it some text strings
onClickListener 2 = Triggers FORCE_WIDGET_UPDATE
After a launcher reload, the activity still trigures fine, but the widget update fails.
Here is the essence of the update code.
public static String updateString = "org.software.appname.FORCE_WIDGET_UPDATE";
public void onReceive(Context ctx, Intent intent){
showIntent=intent.getAction();
Log.d(TAG, showIntent);
if (updateString.equals(intent.getAction())){
Log.d(TAG, "onReceive, Force");
AppName.updateViews = new RemoteViews( ctx.getPackageName(),R.layout.main );
<Code to update text, update widget view and load new intents>
ComponentName me = new ComponentName( ctx, AppName.class );
AppWidgetManager.getInstance( ctx ).updateAppWidget( me, updateViews );
} else super.onReceive(ctx, intent);
I've tried moving the onRecieve call to the super class inside the if statement, but this causes the app to force close as soon you the widget is dropped onto the home screen.
I don't see anything in logcat when clicking the button, when I normally would, sometimes it force closes sometimes it doesn't. I can re-create the problem in the desktop simulator by force closing the stock launcher in application setting.
Thanks in advance for your help! :-)
Edit:
I've tried changing things around by passing appWidgetIds[] in the intent and then triggering the onUpdate within onReceive, but this doesn't seem to do anything. I get the message in logcat to say it's registering the click, but it doens't seem to be triggering onUpdate.
public void onReceive(Context ctx, Intent intent){
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(ctx);
int[] appWidgetIds = intent.getIntArrayExtra("appWidgetIds");
onUpdate(ctx, appWidgetManager, appWidgetIds);
Log.d(TAG, "onReceive log");
}