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