Notify the change in collection items by passing the old RemoteViews

Also tuning the meta parameter a bit to mitigate the parcel exception

Bug: 245950570
Test: Manual
Change-Id: I1c34e8cf1b30f8a24dddafeed0eec50415457d0b
diff --git a/core/java/android/appwidget/AppWidgetManager.java b/core/java/android/appwidget/AppWidgetManager.java
index eb672dc..b159321 100644
--- a/core/java/android/appwidget/AppWidgetManager.java
+++ b/core/java/android/appwidget/AppWidgetManager.java
@@ -48,9 +48,11 @@
 import com.android.internal.appwidget.IAppWidgetService;
 import com.android.internal.os.BackgroundThread;
 
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 import java.util.Objects;
+import java.util.concurrent.CompletableFuture;
 
 /**
  * Updates AppWidget state; gets information about installed AppWidget providers and other
@@ -785,7 +787,25 @@
             return;
         }
         try {
-            mService.notifyAppWidgetViewDataChanged(mPackageName, appWidgetIds, viewId);
+            if (RemoteViews.isAdapterConversionEnabled()) {
+                List<CompletableFuture<Void>> updateFutures = new ArrayList<>();
+                for (int i = 0; i < appWidgetIds.length; i++) {
+                    final int widgetId = appWidgetIds[i];
+                    updateFutures.add(CompletableFuture.runAsync(() -> {
+                        try {
+                            RemoteViews views = mService.getAppWidgetViews(mPackageName, widgetId);
+                            if (views.replaceRemoteCollections(viewId)) {
+                                updateAppWidget(widgetId, views);
+                            }
+                        } catch (Exception e) {
+                            Log.e(TAG, "Error notifying changes in RemoteViews", e);
+                        }
+                    }));
+                }
+                CompletableFuture.allOf(updateFutures.toArray(CompletableFuture[]::new)).join();
+            } else {
+                mService.notifyAppWidgetViewDataChanged(mPackageName, appWidgetIds, viewId);
+            }
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index d9e76fe..a2f95fa 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -786,6 +786,42 @@
         }
     }
 
+    /**
+     * @hide
+     * @return True if there is a change
+     */
+    public boolean replaceRemoteCollections(int viewId) {
+        boolean isActionReplaced = false;
+        if (mActions != null) {
+            for (int i = 0; i < mActions.size(); i++) {
+                Action action = mActions.get(i);
+                if (action instanceof SetRemoteCollectionItemListAdapterAction itemsAction
+                        && itemsAction.viewId == viewId
+                        && itemsAction.mServiceIntent != null) {
+                    mActions.set(i, new SetRemoteCollectionItemListAdapterAction(itemsAction.viewId,
+                            itemsAction.mServiceIntent));
+                    isActionReplaced = true;
+                } else if (action instanceof ViewGroupActionAdd groupAction
+                        && groupAction.mNestedViews != null) {
+                    isActionReplaced |= groupAction.mNestedViews.replaceRemoteCollections(viewId);
+                }
+            }
+        }
+        if (mSizedRemoteViews != null) {
+            for (int i = 0; i < mSizedRemoteViews.size(); i++) {
+                isActionReplaced |= mSizedRemoteViews.get(i).replaceRemoteCollections(viewId);
+            }
+        }
+        if (mLandscape != null) {
+            isActionReplaced |= mLandscape.replaceRemoteCollections(viewId);
+        }
+        if (mPortrait != null) {
+            isActionReplaced |= mPortrait.replaceRemoteCollections(viewId);
+        }
+
+        return isActionReplaced;
+    }
+
     private static void visitIconUri(Icon icon, @NonNull Consumer<Uri> visitor) {
         if (icon != null && (icon.getType() == Icon.TYPE_URI
                 || icon.getType() == Icon.TYPE_URI_ADAPTIVE_BITMAP)) {
@@ -1059,18 +1095,21 @@
 
     private class SetRemoteCollectionItemListAdapterAction extends Action {
         private @NonNull CompletableFuture<RemoteCollectionItems> mItemsFuture;
+        final Intent mServiceIntent;
 
         SetRemoteCollectionItemListAdapterAction(@IdRes int id,
                 @NonNull RemoteCollectionItems items) {
             viewId = id;
             items.setHierarchyRootData(getHierarchyRootData());
             mItemsFuture = CompletableFuture.completedFuture(items);
+            mServiceIntent = null;
         }
 
         SetRemoteCollectionItemListAdapterAction(@IdRes int id, Intent intent) {
             viewId = id;
             mItemsFuture = getItemsFutureFromIntentWithTimeout(intent);
             setHierarchyRootData(getHierarchyRootData());
+            mServiceIntent = intent;
         }
 
         private static CompletableFuture<RemoteCollectionItems> getItemsFutureFromIntentWithTimeout(
@@ -1119,6 +1158,7 @@
             viewId = parcel.readInt();
             mItemsFuture = CompletableFuture.completedFuture(
                     new RemoteCollectionItems(parcel, getHierarchyRootData()));
+            mServiceIntent = parcel.readTypedObject(Intent.CREATOR);
         }
 
         @Override
@@ -1148,6 +1188,7 @@
             dest.writeInt(viewId);
             RemoteCollectionItems items = getCollectionItemsFromFuture(mItemsFuture);
             items.writeToParcel(dest, flags, /* attached= */ true);
+            dest.writeTypedObject(mServiceIntent, flags);
         }
 
         @Override
@@ -4765,9 +4806,7 @@
      *            providing data to the RemoteViewsAdapter
      */
     public void setRemoteAdapter(@IdRes int viewId, Intent intent) {
-        if (AppGlobals.getIntCoreSetting(
-                SystemUiDeviceConfigFlags.REMOTEVIEWS_ADAPTER_CONVERSION,
-                SystemUiDeviceConfigFlags.REMOTEVIEWS_ADAPTER_CONVERSION_DEFAULT ? 1 : 0) == 1) {
+        if (isAdapterConversionEnabled()) {
             addAction(new SetRemoteCollectionItemListAdapterAction(viewId, intent));
             return;
         }
@@ -4775,6 +4814,16 @@
     }
 
     /**
+     * @hide
+     * @return True if the remote adapter conversion is enabled
+     */
+    public static boolean isAdapterConversionEnabled() {
+        return AppGlobals.getIntCoreSetting(
+                SystemUiDeviceConfigFlags.REMOTEVIEWS_ADAPTER_CONVERSION,
+                SystemUiDeviceConfigFlags.REMOTEVIEWS_ADAPTER_CONVERSION_DEFAULT ? 1 : 0) == 1;
+    }
+
+    /**
      * Creates a simple Adapter for the viewId specified. The viewId must point to an AdapterView,
      * ie. {@link ListView}, {@link GridView}, {@link StackView} or {@link AdapterViewAnimator}.
      * This is a simpler but less flexible approach to populating collection widgets. Its use is