Move most of the functions in LauncherAppWidgetHost to LauncherWidgetHolder

Test: N/A
Bug: 235358918
Change-Id: I343419376491203a195154f2766b12e5def38879
diff --git a/src/com/android/launcher3/LauncherProvider.java b/src/com/android/launcher3/LauncherProvider.java
index 58e85fe..a6731a5 100644
--- a/src/com/android/launcher3/LauncherProvider.java
+++ b/src/com/android/launcher3/LauncherProvider.java
@@ -22,7 +22,6 @@
 
 import android.annotation.TargetApi;
 import android.app.backup.BackupManager;
-import android.appwidget.AppWidgetHost;
 import android.appwidget.AppWidgetManager;
 import android.content.ComponentName;
 import android.content.ContentProvider;
@@ -55,6 +54,8 @@
 import android.util.Log;
 import android.util.Xml;
 
+import androidx.annotation.NonNull;
+
 import com.android.launcher3.AutoInstallsLayout.LayoutParserCallback;
 import com.android.launcher3.LauncherSettings.Favorites;
 import com.android.launcher3.config.FeatureFlags;
@@ -70,7 +71,6 @@
 import com.android.launcher3.util.NoLocaleSQLiteHelper;
 import com.android.launcher3.util.PackageManagerHelper;
 import com.android.launcher3.util.Thunk;
-import com.android.launcher3.widget.LauncherAppWidgetHost;
 
 import org.xmlpull.v1.XmlPullParser;
 
@@ -255,17 +255,20 @@
                     values.getAsString(Favorites.APPWIDGET_PROVIDER));
 
             if (cn != null) {
+                LauncherWidgetHolder widgetHolder = mOpenHelper.newLauncherWidgetHolder();
                 try {
-                    AppWidgetHost widgetHost = mOpenHelper.newLauncherWidgetHost();
-                    int appWidgetId = widgetHost.allocateAppWidgetId();
+                    int appWidgetId = widgetHolder.allocateAppWidgetId();
                     values.put(LauncherSettings.Favorites.APPWIDGET_ID, appWidgetId);
                     if (!appWidgetManager.bindAppWidgetIdIfAllowed(appWidgetId,cn)) {
-                        widgetHost.deleteAppWidgetId(appWidgetId);
+                        widgetHolder.deleteAppWidgetId(appWidgetId);
                         return false;
                     }
                 } catch (RuntimeException e) {
                     Log.e(TAG, "Failed to initialize external widget", e);
                     return false;
+                } finally {
+                    // Necessary to destroy the holder to free up possible activity context
+                    widgetHolder.destroy();
                 }
             } else {
                 return false;
@@ -533,10 +536,10 @@
         if (sp.getBoolean(mOpenHelper.getKey(EMPTY_DATABASE_CREATED), false)) {
             Log.d(TAG, "loading default workspace");
 
-            AppWidgetHost widgetHost = mOpenHelper.newLauncherWidgetHost();
-            AutoInstallsLayout loader = createWorkspaceLoaderFromAppRestriction(widgetHost);
+            LauncherWidgetHolder widgetHolder = mOpenHelper.newLauncherWidgetHolder();
+            AutoInstallsLayout loader = createWorkspaceLoaderFromAppRestriction(widgetHolder);
             if (loader == null) {
-                loader = AutoInstallsLayout.get(getContext(),widgetHost, mOpenHelper);
+                loader = AutoInstallsLayout.get(getContext(), widgetHolder, mOpenHelper);
             }
             if (loader == null) {
                 final Partner partner = Partner.get(getContext().getPackageManager());
@@ -545,7 +548,7 @@
                     int workspaceResId = partnerRes.getIdentifier(Partner.RES_DEFAULT_LAYOUT,
                             "xml", partner.getPackageName());
                     if (workspaceResId != 0) {
-                        loader = new DefaultLayoutParser(getContext(), widgetHost,
+                        loader = new DefaultLayoutParser(getContext(), widgetHolder,
                                 mOpenHelper, partnerRes, workspaceResId);
                     }
                 }
@@ -553,7 +556,7 @@
 
             final boolean usingExternallyProvidedLayout = loader != null;
             if (loader == null) {
-                loader = getDefaultLayoutParser(widgetHost);
+                loader = getDefaultLayoutParser(widgetHolder);
             }
 
             // There might be some partially restored DB items, due to buggy restore logic in
@@ -565,9 +568,10 @@
                 // Unable to load external layout. Cleanup and load the internal layout.
                 mOpenHelper.createEmptyDB(mOpenHelper.getWritableDatabase());
                 mOpenHelper.loadFavorites(mOpenHelper.getWritableDatabase(),
-                        getDefaultLayoutParser(widgetHost));
+                        getDefaultLayoutParser(widgetHolder));
             }
             clearFlagEmptyDbCreated();
+            widgetHolder.destroy();
         }
     }
 
@@ -576,7 +580,8 @@
      *
      * @return the loader if the restrictions are set and the resource exists; null otherwise.
      */
-    private AutoInstallsLayout createWorkspaceLoaderFromAppRestriction(AppWidgetHost widgetHost) {
+    private AutoInstallsLayout createWorkspaceLoaderFromAppRestriction(
+            LauncherWidgetHolder widgetHolder) {
         Context ctx = getContext();
         final String authority;
         if (!TextUtils.isEmpty(mProviderAuthority)) {
@@ -602,7 +607,7 @@
             parser.setInput(new StringReader(layout));
 
             Log.d(TAG, "Loading layout from " + authority);
-            return new AutoInstallsLayout(ctx, widgetHost, mOpenHelper,
+            return new AutoInstallsLayout(ctx, widgetHolder, mOpenHelper,
                     ctx.getPackageManager().getResourcesForApplication(pi.applicationInfo),
                     () -> parser, AutoInstallsLayout.TAG_WORKSPACE);
         } catch (Exception e) {
@@ -621,7 +626,7 @@
                 .build();
     }
 
-    private DefaultLayoutParser getDefaultLayoutParser(AppWidgetHost widgetHost) {
+    private DefaultLayoutParser getDefaultLayoutParser(LauncherWidgetHolder widgetHolder) {
         InvariantDeviceProfile idp = LauncherAppState.getIDP(getContext());
         int defaultLayout = mUseTestWorkspaceLayout
                 ? TEST_WORKSPACE_LAYOUT_RES_XML : idp.defaultLayoutId;
@@ -631,7 +636,7 @@
             defaultLayout = idp.demoModeLayoutId;
         }
 
-        return new DefaultLayoutParser(getContext(), widgetHost,
+        return new DefaultLayoutParser(getContext(), widgetHolder,
                 mOpenHelper, getContext().getResources(), defaultLayout);
     }
 
@@ -932,40 +937,46 @@
          */
         public void removeGhostWidgets(SQLiteDatabase db) {
             // Get all existing widget ids.
-            final AppWidgetHost host = newLauncherWidgetHost();
-            final int[] allWidgets;
+            final LauncherWidgetHolder holder = newLauncherWidgetHolder();
             try {
-                // Although the method was defined in O, it has existed since the beginning of time,
-                // so it might work on older platforms as well.
-                allWidgets = host.getAppWidgetIds();
-            } catch (IncompatibleClassChangeError e) {
-                Log.e(TAG, "getAppWidgetIds not supported", e);
-                return;
-            }
-            final IntSet validWidgets = IntSet.wrap(LauncherDbUtils.queryIntArray(false, db,
-                    Favorites.TABLE_NAME, Favorites.APPWIDGET_ID,
-                    "itemType=" + Favorites.ITEM_TYPE_APPWIDGET, null, null));
-            boolean isAnyWidgetRemoved = false;
-            for (int widgetId : allWidgets) {
-                if (!validWidgets.contains(widgetId)) {
-                    try {
-                        FileLog.d(TAG, "Deleting invalid widget " + widgetId);
-                        host.deleteAppWidgetId(widgetId);
-                        isAnyWidgetRemoved = true;
-                    } catch (RuntimeException e) {
-                        // Ignore
+                final int[] allWidgets;
+                try {
+                    // Although the method was defined in O, it has existed since the beginning of
+                    // time, so it might work on older platforms as well.
+                    allWidgets = holder.getAppWidgetIds();
+                } catch (IncompatibleClassChangeError e) {
+                    Log.e(TAG, "getAppWidgetIds not supported", e);
+                    // Necessary to destroy the holder to free up possible activity context
+                    holder.destroy();
+                    return;
+                }
+                final IntSet validWidgets = IntSet.wrap(LauncherDbUtils.queryIntArray(false, db,
+                        Favorites.TABLE_NAME, Favorites.APPWIDGET_ID,
+                        "itemType=" + Favorites.ITEM_TYPE_APPWIDGET, null, null));
+                boolean isAnyWidgetRemoved = false;
+                for (int widgetId : allWidgets) {
+                    if (!validWidgets.contains(widgetId)) {
+                        try {
+                            FileLog.d(TAG, "Deleting invalid widget " + widgetId);
+                            holder.deleteAppWidgetId(widgetId);
+                            isAnyWidgetRemoved = true;
+                        } catch (RuntimeException e) {
+                            // Ignore
+                        }
                     }
                 }
-            }
-            if (isAnyWidgetRemoved) {
-                final String allWidgetsIds = Arrays.stream(allWidgets).mapToObj(String::valueOf)
-                        .collect(Collectors.joining(",", "[", "]"));
-                final String validWidgetsIds = Arrays.stream(
-                        validWidgets.getArray().toArray()).mapToObj(String::valueOf)
-                        .collect(Collectors.joining(",", "[", "]"));
-                FileLog.d(TAG, "One or more widgets was removed. db_path=" + db.getPath()
-                        + " allWidgetsIds=" + allWidgetsIds
-                        + ", validWidgetsIds=" + validWidgetsIds);
+                if (isAnyWidgetRemoved) {
+                    final String allWidgetsIds = Arrays.stream(allWidgets).mapToObj(String::valueOf)
+                            .collect(Collectors.joining(",", "[", "]"));
+                    final String validWidgetsIds = Arrays.stream(
+                                    validWidgets.getArray().toArray()).mapToObj(String::valueOf)
+                            .collect(Collectors.joining(",", "[", "]"));
+                    FileLog.d(TAG, "One or more widgets was removed. db_path=" + db.getPath()
+                            + " allWidgetsIds=" + allWidgetsIds
+                            + ", validWidgetsIds=" + validWidgetsIds);
+                }
+            } finally {
+                holder.destroy();
             }
         }
 
@@ -1066,8 +1077,12 @@
             return mMaxItemId;
         }
 
-        public AppWidgetHost newLauncherWidgetHost() {
-            return new LauncherAppWidgetHost(mContext);
+        /**
+         * @return A new {@link LauncherWidgetHolder} based on the current context
+         */
+        @NonNull
+        public LauncherWidgetHolder newLauncherWidgetHolder() {
+            return new LauncherWidgetHolder(mContext);
         }
 
         @Override