summaryrefslogtreecommitdiff
path: root/services/java/com/android/server/AppWidgetService.java
diff options
context:
space:
mode:
authorWinson Chung <winsonc@google.com>2011-02-21 13:57:45 -0800
committerWinson Chung <winsonc@google.com>2011-02-25 14:06:47 -0800
commit84bbb020217adcdfe0694c44ccab57e208ffde16 (patch)
tree35b5e3e319a134a82ed526742ce3e8ac8d91a329 /services/java/com/android/server/AppWidgetService.java
parente4ce73763de01a6d3e0281ad90f6eca08d455f10 (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.java86
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) {