diff options
author | Winson Chung <winsonc@google.com> | 2011-02-21 13:57:45 -0800 |
---|---|---|
committer | Winson Chung <winsonc@google.com> | 2011-02-25 14:06:47 -0800 |
commit | 84bbb020217adcdfe0694c44ccab57e208ffde16 (patch) | |
tree | 35b5e3e319a134a82ed526742ce3e8ac8d91a329 /services/java/com/android/server/AppWidgetService.java | |
parent | e4ce73763de01a6d3e0281ad90f6eca08d455f10 (diff) |
Fixing issue where RemoteViewsService.onDestroy() was never being called.
Change-Id: I15ad04eee18bc3e09d4846c7f2f2d2d8d168e518
Diffstat (limited to 'services/java/com/android/server/AppWidgetService.java')
-rw-r--r-- | services/java/com/android/server/AppWidgetService.java | 86 |
1 files changed, 81 insertions, 5 deletions
diff --git a/services/java/com/android/server/AppWidgetService.java b/services/java/com/android/server/AppWidgetService.java index ad256571afc7..62b26c46c7f5 100644 --- a/services/java/com/android/server/AppWidgetService.java +++ b/services/java/com/android/server/AppWidgetService.java @@ -22,7 +22,6 @@ import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.PrintWriter; -import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; @@ -57,7 +56,6 @@ import android.content.res.XmlResourceParser; import android.net.Uri; import android.os.Binder; import android.os.Bundle; -import android.os.Handler; import android.os.IBinder; import android.os.Process; import android.os.RemoteException; @@ -69,11 +67,13 @@ import android.util.Slog; import android.util.TypedValue; import android.util.Xml; import android.widget.RemoteViews; +import android.widget.RemoteViewsService; import com.android.internal.appwidget.IAppWidgetHost; import com.android.internal.appwidget.IAppWidgetService; import com.android.internal.util.FastXmlSerializer; import com.android.internal.widget.IRemoteViewsAdapterConnection; +import com.android.internal.widget.IRemoteViewsFactory; class AppWidgetService extends IAppWidgetService.Stub { @@ -153,9 +153,12 @@ class AppWidgetService extends IAppWidgetService.Stub } } - // Manages connections to RemoteViewsServices + // Manages active connections to RemoteViewsServices private final HashMap<Pair<Integer, FilterComparison>, ServiceConnection> mBoundRemoteViewsServices = new HashMap<Pair<Integer,FilterComparison>,ServiceConnection>(); + // Manages persistent references to RemoteViewsServices from different App Widgets + private final HashMap<FilterComparison, HashSet<Integer>> + mRemoteViewsServicesAppWidgets = new HashMap<FilterComparison, HashSet<Integer>>(); Context mContext; Locale mLocale; @@ -429,6 +432,7 @@ class AppWidgetService extends IAppWidgetService.Stub } } + // Binds to a specific RemoteViewsService public void bindRemoteViewsService(int appWidgetId, Intent intent, IBinder connection) { synchronized (mAppWidgetIds) { AppWidgetId id = lookupAppWidgetIdLocked(appWidgetId); @@ -452,8 +456,8 @@ class AppWidgetService extends IAppWidgetService.Stub // that first. (This does not allow multiple connections to the same service under // the same key) ServiceConnectionProxy conn = null; - Pair<Integer, FilterComparison> key = Pair.create(appWidgetId, - new FilterComparison(intent)); + FilterComparison fc = new FilterComparison(intent); + Pair<Integer, FilterComparison> key = Pair.create(appWidgetId, fc); if (mBoundRemoteViewsServices.containsKey(key)) { conn = (ServiceConnectionProxy) mBoundRemoteViewsServices.get(key); conn.disconnect(); @@ -471,9 +475,15 @@ class AppWidgetService extends IAppWidgetService.Stub } finally { Binder.restoreCallingIdentity(token); } + + // Add it to the mapping of RemoteViewsService to appWidgetIds so that we can determine + // when we can call back to the RemoteViewsService later to destroy associated + // factories. + WidgetRemoteViewsServiceBinding(appWidgetId, fc); } } + // Unbinds from a specific RemoteViewsService public void unbindRemoteViewsService(int appWidgetId, Intent intent) { synchronized (mAppWidgetIds) { // Unbind from the RemoteViewsService (which will trigger a callback to the bound @@ -500,6 +510,7 @@ class AppWidgetService extends IAppWidgetService.Stub } } + // Unbinds from a RemoteViewsService when we delete an app widget private void unbindAppWidgetRemoteViewsServicesLocked(AppWidgetId id) { int appWidgetId = id.appWidgetId; // Unbind all connections to Services bound to this AppWidgetId @@ -515,6 +526,71 @@ class AppWidgetService extends IAppWidgetService.Stub it.remove(); } } + + // Check if we need to destroy any services (if no other app widgets are + // referencing the same service) + decrementAppWidgetServiceRefCount(appWidgetId); + } + + // Destroys the cached factory on the RemoteViewsService's side related to the specified intent + private void destroyRemoteViewsService(final Intent intent) { + final ServiceConnection conn = new ServiceConnection() { + @Override + public void onServiceConnected(ComponentName name, IBinder service) { + final IRemoteViewsFactory cb = + IRemoteViewsFactory.Stub.asInterface(service); + try { + cb.onDestroy(intent); + } catch (RemoteException e) { + e.printStackTrace(); + } + mContext.unbindService(this); + } + @Override + public void onServiceDisconnected(android.content.ComponentName name) { + // Do nothing + } + }; + + // Bind to the service and remove the static intent->factory mapping in the + // RemoteViewsService. + final long token = Binder.clearCallingIdentity(); + try { + mContext.bindService(intent, conn, Context.BIND_AUTO_CREATE); + } finally { + Binder.restoreCallingIdentity(token); + } + } + + // Adds to the ref-count for a given RemoteViewsService intent + private void incrementAppWidgetServiceRefCount(int appWidgetId, FilterComparison fc) { + HashSet<Integer> appWidgetIds = null; + if (mRemoteViewsServicesAppWidgets.containsKey(fc)) { + appWidgetIds = mRemoteViewsServicesAppWidgets.get(fc); + } else { + appWidgetIds = new HashSet<Integer>(); + mRemoteViewsServicesAppWidgets.put(fc, appWidgetIds); + } + appWidgetIds.add(appWidgetId); + } + + // Subtracts from the ref-count for a given RemoteViewsService intent, prompting a delete if + // the ref-count reaches zero. + private void decrementAppWidgetServiceRefCount(int appWidgetId) { + Iterator<FilterComparison> it = + mRemoteViewsServicesAppWidgets.keySet().iterator(); + while (it.hasNext()) { + final FilterComparison key = it.next(); + final HashSet<Integer> ids = mRemoteViewsServicesAppWidgets.get(key); + if (ids.remove(appWidgetId)) { + // If we have removed the last app widget referencing this service, then we + // should destroy it and remove it from this set + if (ids.isEmpty()) { + destroyRemoteViewsService(key.getIntent()); + it.remove(); + } + } + } } public AppWidgetProviderInfo getAppWidgetInfo(int appWidgetId) { |