OSDN Git Service

Deleting any ghost widget from system service:
authorSunny Goyal <sunnygoyal@google.com>
Thu, 6 Apr 2017 22:02:52 +0000 (15:02 -0700)
committerSunny Goyal <sunnygoyal@google.com>
Mon, 17 Apr 2017 22:28:39 +0000 (15:28 -0700)
> A one-time DB update for removing any existing ghost widgets
> Handling widget cleanup when we bulk delete workspace items during loader
> Simplifying external delete

Bug: 35634653
Change-Id: Id0c520f57aee6d75d9c0e7bcd5786a464bf9f39f

src/com/android/launcher3/LauncherModel.java
src/com/android/launcher3/LauncherProvider.java
src/com/android/launcher3/LauncherSettings.java

index f8c591c..579352d 100644 (file)
@@ -1249,6 +1249,10 @@ public class LauncherModel extends BroadcastReceiver
                         sBgDataModel.folders.remove(folderId);
                         sBgDataModel.itemsIdMap.remove(folderId);
                     }
+
+                    // Remove any ghost widgets
+                    LauncherSettings.Settings.call(contentResolver,
+                            LauncherSettings.Settings.METHOD_REMOVE_GHOST_WIDGETS);
                 }
 
                 // Unpin shortcuts that don't exist on the workspace.
index 6302744..7d85ac1 100644 (file)
@@ -47,7 +47,6 @@ import android.os.UserHandle;
 import android.os.UserManager;
 import android.text.TextUtils;
 import android.util.Log;
-import android.view.ViewGroup;
 
 import com.android.launcher3.AutoInstallsLayout.LayoutParserCallback;
 import com.android.launcher3.LauncherSettings.Favorites;
@@ -67,10 +66,11 @@ import com.android.launcher3.util.Thunk;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
+import java.lang.reflect.Method;
 import java.net.URISyntaxException;
 import java.util.ArrayList;
 import java.util.Collections;
-import java.util.Locale;
+import java.util.HashSet;
 
 public class LauncherProvider extends ContentProvider {
     private static final String TAG = "LauncherProvider";
@@ -85,7 +85,7 @@ public class LauncherProvider extends ContentProvider {
      * overtime. These must be backwards compatible, else we risk breaking old devices during
      * restore or binary version downgrade.
      */
-    private static final int DATA_VERSION = 2;
+    private static final int DATA_VERSION = 3;
 
     private static final String PREF_KEY_DATA_VERISON = "provider_data_version";
 
@@ -262,10 +262,11 @@ public class LauncherProvider extends ContentProvider {
 
             if (cn != null) {
                 try {
-                    int appWidgetId = new AppWidgetHost(getContext(), Launcher.APPWIDGET_HOST_ID)
-                            .allocateAppWidgetId();
+                    AppWidgetHost widgetHost = mOpenHelper.newLauncherWidgetHost();
+                    int appWidgetId = widgetHost.allocateAppWidgetId();
                     values.put(LauncherSettings.Favorites.APPWIDGET_ID, appWidgetId);
                     if (!appWidgetManager.bindAppWidgetIdIfAllowed(appWidgetId,cn)) {
+                        widgetHost.deleteAppWidgetId(appWidgetId);
                         return false;
                     }
                 } catch (RuntimeException e) {
@@ -347,23 +348,7 @@ public class LauncherProvider extends ContentProvider {
 
         if (Binder.getCallingPid() != Process.myPid()
                 && Favorites.TABLE_NAME.equalsIgnoreCase(args.table)) {
-            String widgetSelection = TextUtils.isEmpty(args.where) ? "1=1" : args.where;
-            widgetSelection = String.format(Locale.ENGLISH, "%1$s = %2$d AND ( %3$s )",
-                    Favorites.ITEM_TYPE, Favorites.ITEM_TYPE_APPWIDGET, widgetSelection);
-            try (Cursor c = db.query(Favorites.TABLE_NAME, new String[] { Favorites.APPWIDGET_ID },
-                    widgetSelection, args.args, null, null, null)) {
-                AppWidgetHost host = new AppWidgetHost(getContext(), Launcher.APPWIDGET_HOST_ID);
-                while (c.moveToNext()) {
-                    int widgetId = c.getInt(0);
-                    if (widgetId != AppWidgetManager.INVALID_APPWIDGET_ID) {
-                        try {
-                            host.deleteAppWidgetId(widgetId);
-                        } catch (RuntimeException e) {
-                            Log.e(TAG, "Error deleting widget id " + widgetId, e);
-                        }
-                    }
-                }
-            }
+            mOpenHelper.removeGhostWidgets(mOpenHelper.getWritableDatabase());
         }
         int count = db.delete(args.table, args.where, args.args);
         if (count > 0) {
@@ -441,6 +426,10 @@ public class LauncherProvider extends ContentProvider {
                 loadDefaultFavoritesIfNecessary();
                 return null;
             }
+            case LauncherSettings.Settings.METHOD_REMOVE_GHOST_WIDGETS: {
+                mOpenHelper.removeGhostWidgets(mOpenHelper.getWritableDatabase());
+                return null;
+            }
         }
         return null;
     }
@@ -509,7 +498,7 @@ public class LauncherProvider extends ContentProvider {
         if (sp.getBoolean(EMPTY_DATABASE_CREATED, false)) {
             Log.d(TAG, "loading default workspace");
 
-            AppWidgetHost widgetHost = new AppWidgetHost(getContext(), Launcher.APPWIDGET_HOST_ID);
+            AppWidgetHost widgetHost = mOpenHelper.newLauncherWidgetHost();
             AutoInstallsLayout loader = createWorkspaceLoaderFromAppRestriction(widgetHost);
             if (loader == null) {
                 loader = AutoInstallsLayout.get(getContext(),widgetHost, mOpenHelper);
@@ -659,7 +648,7 @@ public class LauncherProvider extends ContentProvider {
         protected void onEmptyDbCreated() {
             // Database was just created, so wipe any previous widgets
             if (mWidgetHostResetHandler != null) {
-                new AppWidgetHost(mContext, Launcher.APPWIDGET_HOST_ID).deleteHost();
+                newLauncherWidgetHost().deleteHost();
                 mWidgetHostResetHandler.sendEmptyMessage(
                         ChangeListenerWrapper.MSG_APP_WIDGET_HOST_RESET);
             }
@@ -765,6 +754,8 @@ public class LauncherProvider extends ContentProvider {
                     }
                 }
                 case 2:
+                    removeGhostWidgets(db);
+                case 3:
                     // data updated
                     return;
             }
@@ -906,6 +897,47 @@ public class LauncherProvider extends ContentProvider {
         }
 
         /**
+         * Removes widgets which are registered to the Launcher's host, but are not present
+         * in our model.
+         */
+        public void removeGhostWidgets(SQLiteDatabase db) {
+            // Get all existing widget ids.
+            final AppWidgetHost host = newLauncherWidgetHost();
+            final int[] allWidgets;
+            try {
+                Method getter = AppWidgetHost.class.getDeclaredMethod("getAppWidgetIds");
+                getter.setAccessible(true);
+                allWidgets = (int[]) getter.invoke(host);
+            } catch (Exception e) {
+                Log.e(TAG, "getAppWidgetIds not supported", e);
+                return;
+            }
+            try {
+                Cursor c = db.query(Favorites.TABLE_NAME,
+                        new String[] {Favorites.APPWIDGET_ID },
+                        "itemType=" + Favorites.ITEM_TYPE_APPWIDGET, null, null, null, null);
+                HashSet<Integer> validWidgets = new HashSet<>();
+                while (c.moveToNext()) {
+                    validWidgets.add(c.getInt(0));
+                }
+                c.close();
+
+                for (int widgetId : allWidgets) {
+                    if (!validWidgets.contains(widgetId)) {
+                        try {
+                            FileLog.d(TAG, "Deleting invalid widget " + widgetId);
+                            host.deleteAppWidgetId(widgetId);
+                        } catch (RuntimeException e) {
+                            // Ignore
+                        }
+                    }
+                }
+            } catch (SQLException ex) {
+                Log.w(TAG, "Error getting widgets list", ex);
+            }
+        }
+
+        /**
          * Replaces all shortcuts of type {@link Favorites#ITEM_TYPE_SHORTCUT} which have a valid
          * launcher activity target with {@link Favorites#ITEM_TYPE_APPLICATION}.
          */
@@ -1074,6 +1106,10 @@ public class LauncherProvider extends ContentProvider {
             return mMaxItemId;
         }
 
+        public AppWidgetHost newLauncherWidgetHost() {
+            return new AppWidgetHost(mContext, Launcher.APPWIDGET_HOST_ID);
+        }
+
         @Override
         public long insertAndCheck(SQLiteDatabase db, ContentValues values) {
             return dbInsertAndCheck(this, db, Favorites.TABLE_NAME, null, values);
index af2c102..b25b256 100644 (file)
@@ -299,6 +299,8 @@ public class LauncherSettings {
         public static final String EXTRA_EXTRACTED_COLORS = "extra_extractedColors";
         public static final String EXTRA_WALLPAPER_ID = "extra_wallpaperId";
 
+        public static final String METHOD_REMOVE_GHOST_WIDGETS = "remove_ghost_widgets";
+
         public static final String EXTRA_VALUE = "value";
 
         public static Bundle call(ContentResolver cr, String method) {