From 3c67173eb2cdd74eed15cf7e7392617cebb914ef Mon Sep 17 00:00:00 2001 From: Lucas Dupin Date: Wed, 24 Feb 2021 23:54:05 -0800 Subject: [PATCH] Only enable overlay where package is installed We cannot try to enable icon overlay on managed users because neither launcher nor the wallpaper picker is installed on managed profiles. Trying to do so will result in a SecurityException. Fixes: 180461062 Test: manual Test: atest ThemeOverlayApplierTest ThemeOverlayControllerTest Change-Id: I25a07f7a6aa41b6c92c8928091219c4b0fb22770 --- .../systemui/theme/ThemeOverlayApplier.java | 42 ++++++++---- .../theme/ThemeOverlayController.java | 44 ++++++++---- .../theme/ThemeOverlayApplierTest.java | 68 +++++++------------ .../theme/ThemeOverlayControllerTest.java | 6 +- 4 files changed, 88 insertions(+), 72 deletions(-) diff --git a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayApplier.java b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayApplier.java index 9effc6728bab4..bbb2f1a5259a2 100644 --- a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayApplier.java +++ b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayApplier.java @@ -161,10 +161,10 @@ public class ThemeOverlayApplier implements Dumpable { void applyCurrentUserOverlays( Map categoryToPackage, FabricatedOverlay[] pendingCreation, - Set userHandles) { + int currentUser, + Set managedProfiles) { // Disable all overlays that have not been specified in the user setting. final Set overlayCategoriesToDisable = new HashSet<>(THEME_CATEGORIES); - overlayCategoriesToDisable.removeAll(categoryToPackage.keySet()); final Set targetPackagesToQuery = overlayCategoriesToDisable.stream() .map(category -> mCategoryToTargetPackage.get(category)) .collect(Collectors.toSet()); @@ -175,6 +175,7 @@ public class ThemeOverlayApplier implements Dumpable { .filter(o -> mTargetPackageToCategories.get(o.targetPackageName).contains(o.category)) .filter(o -> overlayCategoriesToDisable.contains(o.category)) + .filter(o -> !categoryToPackage.containsValue(new OverlayIdentifier(o.packageName))) .filter(o -> o.isEnabled()) .map(o -> new Pair<>(o.category, o.packageName)) .collect(Collectors.toList()); @@ -186,17 +187,18 @@ public class ThemeOverlayApplier implements Dumpable { } } - // Toggle overlays in the order of THEME_CATEGORIES. + for (Pair packageToDisable : overlaysToDisable) { + OverlayIdentifier overlayInfo = new OverlayIdentifier(packageToDisable.second); + setEnabled(transaction, overlayInfo, packageToDisable.first, currentUser, + managedProfiles, false); + } + for (String category : THEME_CATEGORIES) { if (categoryToPackage.containsKey(category)) { OverlayIdentifier overlayInfo = categoryToPackage.get(category); - setEnabled(transaction, overlayInfo, category, userHandles, true); + setEnabled(transaction, overlayInfo, category, currentUser, managedProfiles, true); } } - for (Pair packageToDisable : overlaysToDisable) { - OverlayIdentifier overlayInfo = new OverlayIdentifier(packageToDisable.second); - setEnabled(transaction, overlayInfo, packageToDisable.first, userHandles, false); - } mExecutor.execute(() -> { try { @@ -213,18 +215,30 @@ public class ThemeOverlayApplier implements Dumpable { } private void setEnabled(OverlayManagerTransaction.Builder transaction, - OverlayIdentifier identifier, String category, Set handles, - boolean enabled) { + OverlayIdentifier identifier, String category, int currentUser, + Set managedProfiles, boolean enabled) { if (DEBUG) { Log.d(TAG, "setEnabled: " + identifier.getPackageName() + " category: " + category + ": " + enabled); } - for (UserHandle userHandle : handles) { - transaction.setEnabled(identifier, enabled, userHandle.getIdentifier()); - } - if (!handles.contains(UserHandle.SYSTEM) && SYSTEM_USER_CATEGORIES.contains(category)) { + + transaction.setEnabled(identifier, enabled, currentUser); + if (currentUser != UserHandle.SYSTEM.getIdentifier() + && SYSTEM_USER_CATEGORIES.contains(category)) { transaction.setEnabled(identifier, enabled, UserHandle.SYSTEM.getIdentifier()); } + + // Do not apply Launcher or Theme picker overlays to managed users. Apps are not + // installed in there. + OverlayInfo overlayInfo = mOverlayManager.getOverlayInfo(identifier, UserHandle.SYSTEM); + if (overlayInfo == null || overlayInfo.targetPackageName.equals(mLauncherPackage) + || overlayInfo.targetPackageName.equals(mThemePickerPackage)) { + return; + } + + for (UserHandle userHandle : managedProfiles) { + transaction.setEnabled(identifier, enabled, userHandle.getIdentifier()); + } } /** diff --git a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java index 028cbd084677b..5d028454a4177 100644 --- a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java +++ b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java @@ -55,14 +55,13 @@ import com.android.systemui.statusbar.FeatureFlags; import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.util.settings.SecureSettings; -import com.google.android.collect.Sets; - import org.json.JSONException; import org.json.JSONObject; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.Collection; +import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.concurrent.Executor; @@ -151,7 +150,7 @@ public class ThemeOverlayController extends SystemUI implements Dumpable { @Override public void onReceive(Context context, Intent intent) { if (DEBUG) Log.d(TAG, "Updating overlays for user switch / profile added."); - updateThemeOverlays(); + reevaluateSystemTheme(true /* forceReload */); } }, filter, mBgExecutor, UserHandle.ALL); mSecureSettings.registerContentObserverForUser( @@ -163,7 +162,7 @@ public class ThemeOverlayController extends SystemUI implements Dumpable { int userId) { if (DEBUG) Log.d(TAG, "Overlay changed for user: " + userId); if (ActivityManager.getCurrentUser() == userId) { - updateThemeOverlays(); + reevaluateSystemTheme(true /* forceReload */); } } }, @@ -180,7 +179,7 @@ public class ThemeOverlayController extends SystemUI implements Dumpable { mLockColors = lockColors; } mSystemColors = systemColor; - reevaluateSystemTheme(); + reevaluateSystemTheme(false /* forceReload */); }); }); if (USE_LOCK_SCREEN_WALLPAPER) { @@ -192,7 +191,7 @@ public class ThemeOverlayController extends SystemUI implements Dumpable { } // It's possible that the user has a lock screen wallpaper. On this case we'll // end up with different colors after unlocking. - reevaluateSystemTheme(); + reevaluateSystemTheme(false /* forceReload */); } }); } @@ -209,11 +208,11 @@ public class ThemeOverlayController extends SystemUI implements Dumpable { Log.d(TAG, "got new lock colors: " + wallpaperColors + " where: " + which); } } - reevaluateSystemTheme(); + reevaluateSystemTheme(false /* forceReload */); }, null, UserHandle.USER_ALL); } - private void reevaluateSystemTheme() { + private void reevaluateSystemTheme(boolean forceReload) { WallpaperColors currentColors = mKeyguardStateController.isShowing() && mLockColors != null ? mLockColors : mSystemColors; @@ -228,7 +227,8 @@ public class ThemeOverlayController extends SystemUI implements Dumpable { accentCandidate = getAccentColor(currentColors); } - if (mMainWallpaperColor == mainColor && mWallpaperAccentColor == accentCandidate) { + if (mMainWallpaperColor == mainColor && mWallpaperAccentColor == accentCandidate + && !forceReload) { return; } @@ -309,6 +309,16 @@ public class ThemeOverlayController extends SystemUI implements Dumpable { } catch (NumberFormatException e) { Log.w(TAG, "Invalid color definition: " + systemPalette.getPackageName()); } + } else if (!mIsMonetEnabled && systemPalette != null) { + try { + // It's possible that we flipped the flag off and still have a @ColorInt in the + // setting. We need to sanitize the input, otherwise the overlay transaction will + // fail. + Integer.parseInt(systemPalette.getPackageName().toLowerCase(), 16); + categoryToPackage.remove(OVERLAY_CATEGORY_SYSTEM_PALETTE); + } catch (NumberFormatException e) { + // This is a package name. All good, let's continue + } } // Same for accent color. @@ -322,6 +332,13 @@ public class ThemeOverlayController extends SystemUI implements Dumpable { } catch (NumberFormatException e) { Log.w(TAG, "Invalid color definition: " + accentPalette.getPackageName()); } + } else if (!mIsMonetEnabled && accentPalette != null) { + try { + Integer.parseInt(accentPalette.getPackageName().toLowerCase(), 16); + categoryToPackage.remove(OVERLAY_CATEGORY_ACCENT_COLOR); + } catch (NumberFormatException e) { + // This is a package name. All good, let's continue + } } // Compatibility with legacy themes, where full packages were defined, instead of just @@ -337,10 +354,10 @@ public class ThemeOverlayController extends SystemUI implements Dumpable { categoryToPackage.put(OVERLAY_CATEGORY_ACCENT_COLOR, mSecondaryOverlay.getIdentifier()); } - Set userHandles = Sets.newHashSet(UserHandle.of(currentUser)); + Set managedProfiles = new HashSet<>(); for (UserInfo userInfo : mUserManager.getEnabledProfiles(currentUser)) { if (userInfo.isManagedProfile()) { - userHandles.add(userInfo.getUserHandle()); + managedProfiles.add(userInfo.getUserHandle()); } } if (DEBUG) { @@ -352,9 +369,10 @@ public class ThemeOverlayController extends SystemUI implements Dumpable { mNeedsOverlayCreation = false; mThemeManager.applyCurrentUserOverlays(categoryToPackage, new FabricatedOverlay[] { mPrimaryOverlay, mSecondaryOverlay, mNeutralOverlay - }, userHandles); + }, currentUser, managedProfiles); } else { - mThemeManager.applyCurrentUserOverlays(categoryToPackage, null, userHandles); + mThemeManager.applyCurrentUserOverlays(categoryToPackage, null, currentUser, + managedProfiles); } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayApplierTest.java b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayApplierTest.java index e798207c69478..6067b42e0ef84 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayApplierTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayApplierTest.java @@ -32,7 +32,6 @@ import static com.android.systemui.theme.ThemeOverlayApplier.SYSUI_PACKAGE; import static com.android.systemui.theme.ThemeOverlayApplier.THEME_CATEGORIES; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.mock; @@ -88,7 +87,9 @@ public class ThemeOverlayApplierTest extends SysuiTestCase { private static final String THEMEPICKER_PACKAGE = "com.android.wallpaper"; private static final String LAUNCHER_PACKAGE = "com.android.launcher3"; private static final UserHandle TEST_USER = UserHandle.of(5); - private static final Set TEST_USER_HANDLES = Sets.newHashSet(TEST_USER); + private static final UserHandle TEST_USER_MANAGED_PROFILE = UserHandle.of(6); + private static final Set TEST_USER_HANDLES = + Sets.newHashSet(TEST_USER_MANAGED_PROFILE); @Mock OverlayManager mOverlayManager; @@ -159,13 +160,19 @@ public class ThemeOverlayApplierTest extends SysuiTestCase { THEMEPICKER_PACKAGE, OVERLAY_CATEGORY_ICON_THEME_PICKER, false), createOverlayInfo(TEST_ENABLED_PREFIX + OVERLAY_CATEGORY_ICON_THEME_PICKER, THEMEPICKER_PACKAGE, OVERLAY_CATEGORY_ICON_THEME_PICKER, true))); + + OverlayInfo launcherTargetInfo = new OverlayInfo("packageName", LAUNCHER_PACKAGE, + null, null, "/", 0, 0, 0, false); + when(mOverlayManager.getOverlayInfo(any(OverlayIdentifier.class), any())) + .thenReturn(launcherTargetInfo); clearInvocations(mOverlayManager); verify(mDumpManager).registerDumpable(any(), any()); } @Test public void allCategoriesSpecified_allEnabledExclusively() { - mManager.applyCurrentUserOverlays(ALL_CATEGORIES_MAP, null, TEST_USER_HANDLES); + mManager.applyCurrentUserOverlays(ALL_CATEGORIES_MAP, null, TEST_USER.getIdentifier(), + TEST_USER_HANDLES); verify(mOverlayManager).commit(any()); for (OverlayIdentifier overlayPackage : ALL_CATEGORIES_MAP.values()) { @@ -176,7 +183,8 @@ public class ThemeOverlayApplierTest extends SysuiTestCase { @Test public void allCategoriesSpecified_sysuiCategoriesAlsoAppliedToSysuiUser() { - mManager.applyCurrentUserOverlays(ALL_CATEGORIES_MAP, null, TEST_USER_HANDLES); + mManager.applyCurrentUserOverlays(ALL_CATEGORIES_MAP, null, TEST_USER.getIdentifier(), + TEST_USER_HANDLES); for (Map.Entry entry : ALL_CATEGORIES_MAP.entrySet()) { if (SYSTEM_USER_CATEGORIES.contains(entry.getKey())) { @@ -192,48 +200,39 @@ public class ThemeOverlayApplierTest extends SysuiTestCase { @Test public void allCategoriesSpecified_enabledForAllUserHandles() { Set userHandles = Sets.newHashSet(TEST_USER_HANDLES); - UserHandle newUserHandle = UserHandle.of(10); - userHandles.add(newUserHandle); - mManager.applyCurrentUserOverlays(ALL_CATEGORIES_MAP, null, userHandles); + mManager.applyCurrentUserOverlays(ALL_CATEGORIES_MAP, null, TEST_USER.getIdentifier(), + userHandles); for (OverlayIdentifier overlayPackage : ALL_CATEGORIES_MAP.values()) { verify(mTransactionBuilder).setEnabled(eq(overlayPackage), eq(true), eq(TEST_USER.getIdentifier())); - verify(mTransactionBuilder).setEnabled(eq(overlayPackage), eq(true), - eq(newUserHandle.getIdentifier())); + // Not enabled for work profile because the target package is LAUNCHER_PACKAGE + verify(mTransactionBuilder, never()).setEnabled(eq(overlayPackage), eq(true), + eq(TEST_USER_MANAGED_PROFILE.getIdentifier())); } } @Test public void applyCurrentUserOverlays_createsPendingOverlays() { - Set userHandles = Sets.newHashSet(TEST_USER_HANDLES); - UserHandle newUserHandle = UserHandle.of(10); - userHandles.add(newUserHandle); - FabricatedOverlay[] pendingCreation = new FabricatedOverlay[] { + FabricatedOverlay[] pendingCreation = new FabricatedOverlay[]{ mock(FabricatedOverlay.class) }; - mManager.applyCurrentUserOverlays(ALL_CATEGORIES_MAP, pendingCreation, userHandles); + mManager.applyCurrentUserOverlays(ALL_CATEGORIES_MAP, pendingCreation, + TEST_USER.getIdentifier(), TEST_USER_HANDLES); for (FabricatedOverlay overlay : pendingCreation) { verify(mTransactionBuilder).registerFabricatedOverlay(eq(overlay)); } } - @Test - public void allCategoriesSpecified_overlayManagerNotQueried() { - mManager.applyCurrentUserOverlays(ALL_CATEGORIES_MAP, null, TEST_USER_HANDLES); - - verify(mOverlayManager, never()) - .getOverlayInfosForTarget(anyString(), any(UserHandle.class)); - } - @Test public void someCategoriesSpecified_specifiedEnabled_unspecifiedDisabled() { Map categoryToPackage = new HashMap<>(ALL_CATEGORIES_MAP); categoryToPackage.remove(OVERLAY_CATEGORY_ICON_SETTINGS); categoryToPackage.remove(OVERLAY_CATEGORY_ICON_ANDROID); - mManager.applyCurrentUserOverlays(categoryToPackage, null, TEST_USER_HANDLES); + mManager.applyCurrentUserOverlays(categoryToPackage, null, TEST_USER.getIdentifier(), + TEST_USER_HANDLES); for (OverlayIdentifier overlayPackage : categoryToPackage.values()) { verify(mTransactionBuilder).setEnabled(eq(overlayPackage), eq(true), @@ -249,7 +248,8 @@ public class ThemeOverlayApplierTest extends SysuiTestCase { @Test public void zeroCategoriesSpecified_allDisabled() { - mManager.applyCurrentUserOverlays(Maps.newArrayMap(), null, TEST_USER_HANDLES); + mManager.applyCurrentUserOverlays(Maps.newArrayMap(), null, TEST_USER.getIdentifier(), + TEST_USER_HANDLES); for (String category : THEME_CATEGORIES) { verify(mTransactionBuilder).setEnabled( @@ -263,7 +263,8 @@ public class ThemeOverlayApplierTest extends SysuiTestCase { Map categoryToPackage = new HashMap<>(ALL_CATEGORIES_MAP); categoryToPackage.put("blah.category", new OverlayIdentifier("com.example.blah.category")); - mManager.applyCurrentUserOverlays(categoryToPackage, null, TEST_USER_HANDLES); + mManager.applyCurrentUserOverlays(categoryToPackage, null, TEST_USER.getIdentifier(), + TEST_USER_HANDLES); verify(mTransactionBuilder, never()).setEnabled( eq(new OverlayIdentifier("com.example.blah.category")), eq(false), @@ -273,23 +274,6 @@ public class ThemeOverlayApplierTest extends SysuiTestCase { eq(TEST_USER.getIdentifier())); } - @Test - public void overlayManagerOnlyQueriedForUnspecifiedPackages() { - Map categoryToPackage = new HashMap<>(ALL_CATEGORIES_MAP); - categoryToPackage.remove(OVERLAY_CATEGORY_ICON_SETTINGS); - - mManager.applyCurrentUserOverlays(categoryToPackage, null, TEST_USER_HANDLES); - - verify(mOverlayManager).getOverlayInfosForTarget(SETTINGS_PACKAGE, UserHandle.SYSTEM); - verify(mOverlayManager, never()).getOverlayInfosForTarget(ANDROID_PACKAGE, - UserHandle.SYSTEM); - verify(mOverlayManager, never()).getOverlayInfosForTarget(SYSUI_PACKAGE, UserHandle.SYSTEM); - verify(mOverlayManager, never()).getOverlayInfosForTarget(LAUNCHER_PACKAGE, - UserHandle.SYSTEM); - verify(mOverlayManager, never()).getOverlayInfosForTarget(THEMEPICKER_PACKAGE, - UserHandle.SYSTEM); - } - private static OverlayInfo createOverlayInfo(String packageName, String targetPackageName, String category, boolean enabled) { return new OverlayInfo(packageName, null, targetPackageName, null, category, "", diff --git a/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java index aa385effa931d..d80c40fcd07b9 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java @@ -143,7 +143,7 @@ public class ThemeOverlayControllerTest extends SysuiTestCase { ArgumentCaptor.forClass(Map.class); verify(mThemeOverlayApplier) - .applyCurrentUserOverlays(themeOverlays.capture(), any(), any()); + .applyCurrentUserOverlays(themeOverlays.capture(), any(), anyInt(), any()); // Assert that we received the colors that we were expecting assertThat(themeOverlays.getValue().get(OVERLAY_CATEGORY_SYSTEM_PALETTE)) @@ -175,7 +175,7 @@ public class ThemeOverlayControllerTest extends SysuiTestCase { ArgumentCaptor.forClass(Map.class); verify(mThemeOverlayApplier) - .applyCurrentUserOverlays(themeOverlays.capture(), any(), any()); + .applyCurrentUserOverlays(themeOverlays.capture(), any(), anyInt(), any()); // Assert that we received the colors that we were expecting assertThat(themeOverlays.getValue().get(OVERLAY_CATEGORY_SYSTEM_PALETTE)) @@ -198,7 +198,7 @@ public class ThemeOverlayControllerTest extends SysuiTestCase { ArgumentCaptor.forClass(Map.class); verify(mThemeOverlayApplier) - .applyCurrentUserOverlays(themeOverlays.capture(), any(), any()); + .applyCurrentUserOverlays(themeOverlays.capture(), any(), anyInt(), any()); // Assert that we received the colors that we were expecting assertThat(themeOverlays.getValue().get(OVERLAY_CATEGORY_SYSTEM_PALETTE))