blob: 41e026af7c7283bd2a835b841328edc9cfa5b0f2 [file] [log] [blame]
Amin Shaikhfd6402e2019-03-28 16:23:49 -04001/*
2 * Copyright (C) 2019 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package com.android.systemui.theme;
17
18import android.content.om.OverlayInfo;
19import android.content.om.OverlayManager;
20import android.os.UserHandle;
21import android.util.ArrayMap;
22import android.util.Log;
23
24import androidx.annotation.VisibleForTesting;
25
Amin Shaikhb56b29c2019-04-11 07:26:03 -040026import com.google.android.collect.Lists;
Amin Shaikhfd6402e2019-03-28 16:23:49 -040027import com.google.android.collect.Sets;
28
29import java.util.ArrayList;
Amin Shaikhb56b29c2019-04-11 07:26:03 -040030import java.util.HashSet;
Amin Shaikhfd6402e2019-03-28 16:23:49 -040031import java.util.List;
32import java.util.Map;
33import java.util.Set;
Amin Shaikh96e60d72019-04-24 13:47:57 -040034import java.util.concurrent.Executor;
Amin Shaikhfd6402e2019-03-28 16:23:49 -040035import java.util.stream.Collectors;
36
37class ThemeOverlayManager {
38 private static final String TAG = "ThemeOverlayManager";
39 private static final boolean DEBUG = false;
40
41 @VisibleForTesting
42 static final String ANDROID_PACKAGE = "android";
43 @VisibleForTesting
44 static final String SETTINGS_PACKAGE = "com.android.settings";
45 @VisibleForTesting
46 static final String SYSUI_PACKAGE = "com.android.systemui";
47
48 @VisibleForTesting
49 static final String OVERLAY_CATEGORY_COLOR = "android.theme.customization.accent_color";
50 @VisibleForTesting
51 static final String OVERLAY_CATEGORY_FONT = "android.theme.customization.font";
52 @VisibleForTesting
53 static final String OVERLAY_CATEGORY_SHAPE =
54 "android.theme.customization.adaptive_icon_shape";
55 @VisibleForTesting
56 static final String OVERLAY_CATEGORY_ICON_ANDROID =
57 "android.theme.customization.icon_pack.android";
58 @VisibleForTesting
59 static final String OVERLAY_CATEGORY_ICON_SYSUI =
60 "android.theme.customization.icon_pack.systemui";
61 @VisibleForTesting
62 static final String OVERLAY_CATEGORY_ICON_SETTINGS =
63 "android.theme.customization.icon_pack.settings";
64 @VisibleForTesting
65 static final String OVERLAY_CATEGORY_ICON_LAUNCHER =
66 "android.theme.customization.icon_pack.launcher";
Amin Shaikh0974b882019-04-23 17:14:56 -040067 @VisibleForTesting
68 static final String OVERLAY_CATEGORY_ICON_THEME_PICKER =
69 "android.theme.customization.icon_pack.themepicker";
Amin Shaikhfd6402e2019-03-28 16:23:49 -040070
Amin Shaikhb56b29c2019-04-11 07:26:03 -040071 /*
72 * All theme customization categories used by the system, in order that they should be applied,
73 * starts with launcher and grouped by target package.
74 */
75 static final List<String> THEME_CATEGORIES = Lists.newArrayList(
76 OVERLAY_CATEGORY_ICON_LAUNCHER,
Amin Shaikhfd6402e2019-03-28 16:23:49 -040077 OVERLAY_CATEGORY_SHAPE,
Amin Shaikhb56b29c2019-04-11 07:26:03 -040078 OVERLAY_CATEGORY_FONT,
79 OVERLAY_CATEGORY_COLOR,
Amin Shaikhfd6402e2019-03-28 16:23:49 -040080 OVERLAY_CATEGORY_ICON_ANDROID,
81 OVERLAY_CATEGORY_ICON_SYSUI,
Amin Shaikh0974b882019-04-23 17:14:56 -040082 OVERLAY_CATEGORY_ICON_SETTINGS,
83 OVERLAY_CATEGORY_ICON_THEME_PICKER);
Amin Shaikhfd6402e2019-03-28 16:23:49 -040084
85 /* Categories that need to applied to the current user as well as the system user. */
86 @VisibleForTesting
87 static final Set<String> SYSTEM_USER_CATEGORIES = Sets.newHashSet(
88 OVERLAY_CATEGORY_COLOR,
89 OVERLAY_CATEGORY_FONT,
90 OVERLAY_CATEGORY_SHAPE,
91 OVERLAY_CATEGORY_ICON_ANDROID,
92 OVERLAY_CATEGORY_ICON_SYSUI);
93
94 /* Allowed overlay categories for each target package. */
95 private final Map<String, Set<String>> mTargetPackageToCategories = new ArrayMap<>();
96 /* Target package for each overlay category. */
97 private final Map<String, String> mCategoryToTargetPackage = new ArrayMap<>();
98 private final OverlayManager mOverlayManager;
Amin Shaikh96e60d72019-04-24 13:47:57 -040099 private final Executor mExecutor;
Amin Shaikhfd6402e2019-03-28 16:23:49 -0400100 private final String mLauncherPackage;
Amin Shaikh0974b882019-04-23 17:14:56 -0400101 private final String mThemePickerPackage;
Amin Shaikhfd6402e2019-03-28 16:23:49 -0400102
Amin Shaikh96e60d72019-04-24 13:47:57 -0400103 ThemeOverlayManager(OverlayManager overlayManager, Executor executor,
Amin Shaikh0974b882019-04-23 17:14:56 -0400104 String launcherPackage, String themePickerPackage) {
Amin Shaikhfd6402e2019-03-28 16:23:49 -0400105 mOverlayManager = overlayManager;
Amin Shaikh96e60d72019-04-24 13:47:57 -0400106 mExecutor = executor;
Amin Shaikhfd6402e2019-03-28 16:23:49 -0400107 mLauncherPackage = launcherPackage;
Amin Shaikh0974b882019-04-23 17:14:56 -0400108 mThemePickerPackage = themePickerPackage;
Amin Shaikhfd6402e2019-03-28 16:23:49 -0400109 mTargetPackageToCategories.put(ANDROID_PACKAGE, Sets.newHashSet(
110 OVERLAY_CATEGORY_COLOR, OVERLAY_CATEGORY_FONT,
111 OVERLAY_CATEGORY_SHAPE, OVERLAY_CATEGORY_ICON_ANDROID));
112 mTargetPackageToCategories.put(SYSUI_PACKAGE,
113 Sets.newHashSet(OVERLAY_CATEGORY_ICON_SYSUI));
114 mTargetPackageToCategories.put(SETTINGS_PACKAGE,
115 Sets.newHashSet(OVERLAY_CATEGORY_ICON_SETTINGS));
116 mTargetPackageToCategories.put(mLauncherPackage,
117 Sets.newHashSet(OVERLAY_CATEGORY_ICON_LAUNCHER));
Amin Shaikh0974b882019-04-23 17:14:56 -0400118 mTargetPackageToCategories.put(mThemePickerPackage,
119 Sets.newHashSet(OVERLAY_CATEGORY_ICON_THEME_PICKER));
Amin Shaikhfd6402e2019-03-28 16:23:49 -0400120 mCategoryToTargetPackage.put(OVERLAY_CATEGORY_COLOR, ANDROID_PACKAGE);
121 mCategoryToTargetPackage.put(OVERLAY_CATEGORY_FONT, ANDROID_PACKAGE);
122 mCategoryToTargetPackage.put(OVERLAY_CATEGORY_SHAPE, ANDROID_PACKAGE);
123 mCategoryToTargetPackage.put(OVERLAY_CATEGORY_ICON_ANDROID, ANDROID_PACKAGE);
124 mCategoryToTargetPackage.put(OVERLAY_CATEGORY_ICON_SYSUI, SYSUI_PACKAGE);
125 mCategoryToTargetPackage.put(OVERLAY_CATEGORY_ICON_SETTINGS, SETTINGS_PACKAGE);
126 mCategoryToTargetPackage.put(OVERLAY_CATEGORY_ICON_LAUNCHER, mLauncherPackage);
Amin Shaikh0974b882019-04-23 17:14:56 -0400127 mCategoryToTargetPackage.put(OVERLAY_CATEGORY_ICON_THEME_PICKER, mThemePickerPackage);
Amin Shaikhfd6402e2019-03-28 16:23:49 -0400128 }
129
130 /**
131 * Apply the set of overlay packages to the set of {@code UserHandle}s provided. Overlays that
132 * affect sysui will also be applied to the system user.
133 */
134 void applyCurrentUserOverlays(
135 Map<String, String> categoryToPackage, Set<UserHandle> userHandles) {
Amin Shaikhfd6402e2019-03-28 16:23:49 -0400136 // Disable all overlays that have not been specified in the user setting.
Amin Shaikhb56b29c2019-04-11 07:26:03 -0400137 final Set<String> overlayCategoriesToDisable = new HashSet<>(THEME_CATEGORIES);
138 overlayCategoriesToDisable.removeAll(categoryToPackage.keySet());
139 final Set<String> targetPackagesToQuery = overlayCategoriesToDisable.stream()
Amin Shaikhfd6402e2019-03-28 16:23:49 -0400140 .map(category -> mCategoryToTargetPackage.get(category))
Amin Shaikhb56b29c2019-04-11 07:26:03 -0400141 .collect(Collectors.toSet());
142 final List<OverlayInfo> overlays = new ArrayList<>();
143 targetPackagesToQuery.forEach(targetPackage -> overlays.addAll(mOverlayManager
144 .getOverlayInfosForTarget(targetPackage, UserHandle.SYSTEM)));
145 final Map<String, String> overlaysToDisable = overlays.stream()
Amin Shaikhfd6402e2019-03-28 16:23:49 -0400146 .filter(o ->
147 mTargetPackageToCategories.get(o.targetPackageName).contains(o.category))
148 .filter(o -> overlayCategoriesToDisable.contains(o.category))
149 .filter(o -> o.isEnabled())
Amin Shaikhb56b29c2019-04-11 07:26:03 -0400150 .collect(Collectors.toMap((o) -> o.category, (o) -> o.packageName));
Amin Shaikhfd6402e2019-03-28 16:23:49 -0400151
Amin Shaikhb56b29c2019-04-11 07:26:03 -0400152 // Toggle overlays in the order of THEME_CATEGORIES.
153 for (String category : THEME_CATEGORIES) {
154 if (categoryToPackage.containsKey(category)) {
155 setEnabled(categoryToPackage.get(category), category, userHandles, true);
156 } else if (overlaysToDisable.containsKey(category)) {
157 setEnabled(overlaysToDisable.get(category), category, userHandles, false);
158 }
159 }
Amin Shaikhfd6402e2019-03-28 16:23:49 -0400160 }
161
162 private void setEnabled(
163 String packageName, String category, Set<UserHandle> handles, boolean enabled) {
164 for (UserHandle userHandle : handles) {
Amin Shaikh96e60d72019-04-24 13:47:57 -0400165 setEnabledAsync(packageName, userHandle, enabled);
Amin Shaikhfd6402e2019-03-28 16:23:49 -0400166 }
167 if (!handles.contains(UserHandle.SYSTEM) && SYSTEM_USER_CATEGORIES.contains(category)) {
Amin Shaikh96e60d72019-04-24 13:47:57 -0400168 setEnabledAsync(packageName, UserHandle.SYSTEM, enabled);
Amin Shaikhfd6402e2019-03-28 16:23:49 -0400169 }
170 }
171
Amin Shaikh96e60d72019-04-24 13:47:57 -0400172 private void setEnabledAsync(String pkg, UserHandle userHandle, boolean enabled) {
173 mExecutor.execute(() -> {
174 if (DEBUG) Log.d(TAG, String.format("setEnabled: %s %s %b", pkg, userHandle, enabled));
Amin Shaikh44a0e1c2019-06-24 13:36:45 -0400175 try {
176 if (enabled) {
177 mOverlayManager.setEnabledExclusiveInCategory(pkg, userHandle);
178 } else {
179 mOverlayManager.setEnabled(pkg, false, userHandle);
180 }
181 } catch (IllegalStateException e) {
182 Log.e(TAG,
183 String.format("setEnabled failed: %s %s %b", pkg, userHandle, enabled), e);
Amin Shaikh96e60d72019-04-24 13:47:57 -0400184 }
185 });
Amin Shaikhfd6402e2019-03-28 16:23:49 -0400186 }
187}