diff options
author | Ryan Mitchell <rtmitchell@google.com> | 2021-07-19 17:05:53 -0700 |
---|---|---|
committer | Ryan Mitchell <rtmitchell@google.com> | 2021-07-29 16:02:54 +0000 |
commit | 0bf76b6296e7095ab98ea175452e5697e9afcc66 (patch) | |
tree | 697dc4d0e21a29f1bfe67317ff3280ac1650028a | |
parent | b827a8ac8354ad87aed758922291c22ee0504d85 (diff) |
Apply overlay updates to widget provider info
When Runtime Resource Overlays (RROs) are applied to an application,
the ApplicationInfo of the app in package manager is updated to have
overlay paths. Widgets create the context used to inflate their
remote views using a snapshot of the ApplicationInfo of the widget
provider. This snapshot is taken when the widget RemoteView is
initially created and sent to system server.
This change updates the snapshot of the widget provider ApplicationInfo
with the new overlay paths and notifies apps hosting widgets to
re-inflate their remote views in order to have RROs apply to widgets
correctly.
Bug: 193866093
Test: Repeatedly change wallpaper & style color to a "basic" color
and go back to launcher to observe overlay correct color is
applied
Change-Id: I0b9b8c0d32d83a52e9ea5bc8ba1635cf99e4b921
4 files changed, 101 insertions, 0 deletions
diff --git a/core/java/android/appwidget/AppWidgetManagerInternal.java b/core/java/android/appwidget/AppWidgetManagerInternal.java index 5694ca860453..266e33af0e22 100644 --- a/core/java/android/appwidget/AppWidgetManagerInternal.java +++ b/core/java/android/appwidget/AppWidgetManagerInternal.java @@ -19,6 +19,8 @@ package android.appwidget; import android.annotation.Nullable; import android.util.ArraySet; +import java.util.Set; + /** * App widget manager local system service interface. * @@ -42,4 +44,16 @@ public abstract class AppWidgetManagerInternal { * @param userId The user that is being unlocked. */ public abstract void unlockUser(int userId); + + /** + * Updates all widgets, applying changes to Runtime Resource Overlay affecting the specified + * target packages. + * + * @param packageNames The names of all target packages for which an overlay was modified + * @param userId The user for which overlay modifications occurred. + * @param updateFrameworkRes Whether or not an overlay affected the values of framework + * resources. + */ + public abstract void applyResourceOverlaysToWidgets(Set<String> packageNames, int userId, + boolean updateFrameworkRes); } diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java index e827f0a31bfd..91fc5a56d979 100644 --- a/core/java/android/widget/RemoteViews.java +++ b/core/java/android/widget/RemoteViews.java @@ -5824,6 +5824,25 @@ public class RemoteViews implements Parcelable, Filter { return false; } + /** @hide */ + public void updateAppInfo(@NonNull ApplicationInfo info) { + if (mApplication != null && mApplication.sourceDir.equals(info.sourceDir)) { + // Overlay paths are generated against a particular version of an application. + // The overlays paths of a newly upgraded application are incompatible with the + // old version of the application. + mApplication = info; + } + if (hasSizedRemoteViews()) { + for (RemoteViews layout : mSizedRemoteViews) { + layout.updateAppInfo(info); + } + } + if (hasLandscapeAndPortraitLayouts()) { + mLandscape.updateAppInfo(info); + mPortrait.updateAppInfo(info); + } + } + private Context getContextForResources(Context context) { if (mApplication != null) { if (context.getUserId() == UserHandle.getUserId(mApplication.uid) diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java index 5aec6aa99c12..a56b1db1494c 100644 --- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java +++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java @@ -3285,6 +3285,57 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku } } + private void applyResourceOverlaysToWidgetsLocked(Set<String> packageNames, int userId, + boolean updateFrameworkRes) { + for (int i = 0, N = mProviders.size(); i < N; i++) { + Provider provider = mProviders.get(i); + if (provider.getUserId() != userId) { + continue; + } + + final String packageName = provider.id.componentName.getPackageName(); + if (!updateFrameworkRes && !packageNames.contains(packageName)) { + continue; + } + + ApplicationInfo newAppInfo = null; + try { + newAppInfo = mPackageManager.getApplicationInfo(packageName, + PackageManager.GET_SHARED_LIBRARY_FILES, userId); + } catch (RemoteException e) { + Slog.w(TAG, "Failed to retrieve app info for " + packageName + + " userId=" + userId, e); + } + if (newAppInfo == null) { + continue; + } + ApplicationInfo oldAppInfo = provider.info.providerInfo.applicationInfo; + if (!newAppInfo.sourceDir.equals(oldAppInfo.sourceDir)) { + // Overlay paths are generated against a particular version of an application. + // The overlays paths of a newly upgraded application are incompatible with the + // old version of the application. + continue; + } + + // Isolate the changes relating to RROs. The app info must be copied to prevent + // affecting other parts of system server that may have cached this app info. + oldAppInfo = new ApplicationInfo(oldAppInfo); + oldAppInfo.overlayPaths = newAppInfo.overlayPaths.clone(); + oldAppInfo.resourceDirs = newAppInfo.resourceDirs.clone(); + provider.info.providerInfo.applicationInfo = oldAppInfo; + + for (int j = 0, M = provider.widgets.size(); j < M; j++) { + Widget widget = provider.widgets.get(j); + if (widget.views != null) { + widget.views.updateAppInfo(oldAppInfo); + } + if (widget.maskedViews != null) { + widget.maskedViews.updateAppInfo(oldAppInfo); + } + } + } + } + /** * Updates all providers with the specified package names, and records any providers that were * pruned. @@ -4875,5 +4926,14 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku public void unlockUser(int userId) { handleUserUnlocked(userId); } + + @Override + public void applyResourceOverlaysToWidgets(Set<String> packageNames, int userId, + boolean updateFrameworkRes) { + synchronized (mLock) { + applyResourceOverlaysToWidgetsLocked(new HashSet<>(packageNames), userId, + updateFrameworkRes); + } + } } } diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 0d35bb180514..a03d147df9ec 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -193,6 +193,7 @@ import android.app.usage.UsageEvents.Event; import android.app.usage.UsageStatsManager; import android.app.usage.UsageStatsManagerInternal; import android.appwidget.AppWidgetManager; +import android.appwidget.AppWidgetManagerInternal; import android.content.AttributionSource; import android.content.AutofillOptions; import android.content.BroadcastReceiver; @@ -16588,6 +16589,13 @@ public class ActivityManagerService extends IActivityManager.Stub if (updateFrameworkRes) { ParsingPackageUtils.readConfigUseRoundIcon(null); } + + AppWidgetManagerInternal widgets = LocalServices.getService(AppWidgetManagerInternal.class); + if (widgets != null) { + widgets.applyResourceOverlaysToWidgets(new HashSet<>(packagesToUpdate), userId, + updateFrameworkRes); + } + mProcessList.updateApplicationInfoLOSP(packagesToUpdate, userId, updateFrameworkRes); if (updateFrameworkRes) { |