From 07676012f7e4060faa0d23dc6068e9dcdd4a4106 Mon Sep 17 00:00:00 2001 From: Paul Westbrook Date: Mon, 9 Jan 2012 11:36:16 -0800 Subject: [PATCH] Fix widget updates Fix widgets that stop updating. If the Launcher got killed, the Email widget service gets unbound. When this happens the cursor loader for the widget is stopped. Since widget is relying on the loader to update the data, when the loader is stopped, the widget would never update. Now when email recognizes a change, it will send a broadcast intent, which will cause the widget service to be started, if it isn't. Bug: 5811810 Change-Id: Ia840e58f10e780b94440119662c2e48e7785c507 --- AndroidManifest.xml | 3 +++ .../android/email/provider/EmailProvider.java | 23 +++++++++++++++++++ .../email/provider/WidgetProvider.java | 16 +++++++++++++ src/com/android/email/widget/EmailWidget.java | 4 ++++ 4 files changed, 46 insertions(+) diff --git a/AndroidManifest.xml b/AndroidManifest.xml index a6407a6a6..8a449c3a8 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -486,6 +486,9 @@ + + + diff --git a/src/com/android/email/provider/EmailProvider.java b/src/com/android/email/provider/EmailProvider.java index 798bfb050..bbedfdb26 100644 --- a/src/com/android/email/provider/EmailProvider.java +++ b/src/com/android/email/provider/EmailProvider.java @@ -23,6 +23,7 @@ import android.content.ContentProviderResult; import android.content.ContentResolver; import android.content.ContentUris; import android.content.ContentValues; +import android.content.Intent; import android.content.Context; import android.content.OperationApplicationException; import android.content.UriMatcher; @@ -86,6 +87,14 @@ public class EmailProvider extends ContentProvider { public static final String ATTACHMENT_UPDATED_EXTRA_FLAGS = "com.android.email.ATTACHMENT_UPDATED_FLAGS"; + /** + * Notifies that changes happened. Certain UI components, e.g., widgets, can register for this + * {@link android.content.Intent} and update accordingly. However, this can be very broad and + * is NOT the preferred way of getting notification. + */ + public static final String ACTION_NOTIFY_MESSAGE_LIST_DATASET_CHANGED = + "com.android.email.MESSAGE_LIST_DATASET_CHANGED"; + public static final String EMAIL_MESSAGE_MIME_TYPE = "vnd.android.cursor.item/email-message"; public static final String EMAIL_ATTACHMENT_MIME_TYPE = @@ -2345,6 +2354,20 @@ outer: } else { resolver.notifyChange(baseUri, null); } + + // We want to send the message list changed notification if baseUri is Message.NOTIFIER_URI. + if (baseUri.equals(Message.NOTIFIER_URI)) { + sendMessageListDataChangedNotification(); + } + } + + private void sendMessageListDataChangedNotification() { + final Context context = getContext(); + final Intent intent = new Intent(ACTION_NOTIFY_MESSAGE_LIST_DATASET_CHANGED); + // Ideally this intent would contain information about which account changed, to limit the + // updates to that particular account. Unfortunately, that information is not available in + // sendNotifierChange(). + context.sendBroadcast(intent); } @Override diff --git a/src/com/android/email/provider/WidgetProvider.java b/src/com/android/email/provider/WidgetProvider.java index 9f7fc8512..0f6731b8b 100644 --- a/src/com/android/email/provider/WidgetProvider.java +++ b/src/com/android/email/provider/WidgetProvider.java @@ -19,12 +19,14 @@ package com.android.email.provider; import android.app.Service; import android.appwidget.AppWidgetManager; import android.appwidget.AppWidgetProvider; +import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.util.Log; import android.widget.RemoteViewsService; import com.android.email.Email; +import com.android.email.R; import com.android.email.widget.EmailWidget; import com.android.email.widget.WidgetManager; import com.android.emailcommon.Logging; @@ -74,6 +76,20 @@ public class WidgetProvider extends AppWidgetProvider { Log.d(EmailWidget.TAG, "onReceive"); } super.onReceive(context, intent); + + if (EmailProvider.ACTION_NOTIFY_MESSAGE_LIST_DATASET_CHANGED.equals(intent.getAction())) { + // Retrieve the list of current widgets. + final AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context); + final ComponentName component = new ComponentName(context, WidgetProvider.class); + final int[] widgetIds = appWidgetManager.getAppWidgetIds(component); + + // Ideally, this would only call notify AppWidgetViewDataChanged for the widgets, where + // the account had the change, but the current intent doesn't include this information. + + // Calling notifyAppWidgetViewDataChanged will cause onDataSetChanged() to be called + // on the RemoteViewsService.RemoteViewsFactory, starting the service if necessary. + appWidgetManager.notifyAppWidgetViewDataChanged(widgetIds, R.id.message_list); + } } /** diff --git a/src/com/android/email/widget/EmailWidget.java b/src/com/android/email/widget/EmailWidget.java index 3f6a5c0c6..67a82f570 100644 --- a/src/com/android/email/widget/EmailWidget.java +++ b/src/com/android/email/widget/EmailWidget.java @@ -505,6 +505,10 @@ public class EmailWidget implements RemoteViewsService.RemoteViewsFactory, @Override public void onDataSetChanged() { + // Note: we are not doing anything special in onDataSetChanged(). Since this service has + // a reference to a loader that will keep itself updated, if the service is running, it + // shouldn't be necessary to for the query to be run again. If the service hadn't been + // running, the act of starting the service will also start the loader. } public void onDeleted() {