• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
5  * except in compliance with the License. You may obtain a copy of the License at
6  *
7  *      http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software distributed under the
10  * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
11  * KIND, either express or implied. See the License for the specific language governing
12  * permissions and limitations under the License.
13  */
14 package com.android.settings.display;
15 
16 
17 import android.app.settings.SettingsEnums;
18 import android.content.Context;
19 import android.content.om.IOverlayManager;
20 import android.content.om.OverlayInfo;
21 import android.content.pm.PackageInfo;
22 import android.content.pm.PackageManager;
23 import android.content.pm.PackageManager.NameNotFoundException;
24 import android.os.RemoteException;
25 import android.os.ServiceManager;
26 import android.os.UserHandle;
27 import android.text.TextUtils;
28 
29 import androidx.annotation.VisibleForTesting;
30 import androidx.preference.ListPreference;
31 import androidx.preference.Preference;
32 
33 import com.android.settings.R;
34 import com.android.settings.core.PreferenceControllerMixin;
35 import com.android.settings.overlay.FeatureFactory;
36 import com.android.settingslib.core.AbstractPreferenceController;
37 import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
38 
39 import java.util.ArrayList;
40 import java.util.List;
41 import java.util.Objects;
42 
43 public class ThemePreferenceController extends AbstractPreferenceController implements
44         PreferenceControllerMixin, Preference.OnPreferenceChangeListener {
45 
46     private static final String KEY_THEME = "theme";
47 
48     private final MetricsFeatureProvider mMetricsFeatureProvider;
49     private final IOverlayManager mOverlayService;
50     private final PackageManager mPackageManager;
51 
ThemePreferenceController(Context context)52     public ThemePreferenceController(Context context) {
53         this(context, IOverlayManager.Stub
54                 .asInterface(ServiceManager.getService(Context.OVERLAY_SERVICE)));
55     }
56 
57     @VisibleForTesting
ThemePreferenceController(Context context, IOverlayManager overlayManager)58     ThemePreferenceController(Context context, IOverlayManager overlayManager) {
59         super(context);
60         mOverlayService = overlayManager;
61         mPackageManager = context.getPackageManager();
62         mMetricsFeatureProvider = FeatureFactory.getFactory(context).getMetricsFeatureProvider();
63     }
64 
65     @Override
getPreferenceKey()66     public String getPreferenceKey() {
67         return KEY_THEME;
68     }
69 
70     @Override
handlePreferenceTreeClick(Preference preference)71     public boolean handlePreferenceTreeClick(Preference preference) {
72         if (KEY_THEME.equals(preference.getKey())) {
73             mMetricsFeatureProvider.action(mContext, SettingsEnums.ACTION_THEME);
74         }
75         return false;
76     }
77 
78     @Override
updateState(Preference preference)79     public void updateState(Preference preference) {
80         ListPreference pref = (ListPreference) preference;
81         String[] pkgs = getAvailableThemes(false /* currentThemeOnly */);
82         CharSequence[] labels = new CharSequence[pkgs.length];
83         for (int i = 0; i < pkgs.length; i++) {
84             try {
85                 labels[i] = mPackageManager.getApplicationInfo(pkgs[i], 0)
86                         .loadLabel(mPackageManager);
87             } catch (NameNotFoundException e) {
88                 labels[i] = pkgs[i];
89             }
90         }
91         pref.setEntries(labels);
92         pref.setEntryValues(pkgs);
93         String theme = getCurrentTheme();
94         CharSequence themeLabel = null;
95 
96         for (int i = 0; i < pkgs.length; i++) {
97             if (TextUtils.equals(pkgs[i], theme)) {
98                 themeLabel = labels[i];
99                 break;
100             }
101         }
102 
103         if (TextUtils.isEmpty(themeLabel)) {
104             themeLabel = mContext.getString(R.string.default_theme);
105         }
106 
107         pref.setSummary(themeLabel);
108         pref.setValue(theme);
109     }
110 
111     @Override
onPreferenceChange(Preference preference, Object newValue)112     public boolean onPreferenceChange(Preference preference, Object newValue) {
113         String current = getCurrentTheme();
114         if (Objects.equals(newValue, current)) {
115             return true;
116         }
117         try {
118             mOverlayService.setEnabledExclusiveInCategory((String) newValue, UserHandle.myUserId());
119         } catch (RemoteException re) {
120             throw re.rethrowFromSystemServer();
121         }
122         return true;
123     }
124 
isTheme(OverlayInfo oi)125     private boolean isTheme(OverlayInfo oi) {
126         if (!OverlayInfo.CATEGORY_THEME.equals(oi.category)) {
127             return false;
128         }
129         try {
130             PackageInfo pi = mPackageManager.getPackageInfo(oi.packageName, 0);
131             return pi != null && !pi.isStaticOverlayPackage();
132         } catch (PackageManager.NameNotFoundException e) {
133             return false;
134         }
135     }
136 
137     @Override
isAvailable()138     public boolean isAvailable() {
139         if (mOverlayService == null) return false;
140         String[] themes = getAvailableThemes(false /* currentThemeOnly */);
141         return themes != null && themes.length > 1;
142     }
143 
144 
145     @VisibleForTesting
getCurrentTheme()146     String getCurrentTheme() {
147         String[] themePackages = getAvailableThemes(true /* currentThemeOnly */);
148         return themePackages.length < 1 ? null : themePackages[0];
149     }
150 
151     @VisibleForTesting
getAvailableThemes(boolean currentThemeOnly)152     String[] getAvailableThemes(boolean currentThemeOnly) {
153         List<OverlayInfo> infos;
154         List<String> pkgs;
155         try {
156             infos = mOverlayService.getOverlayInfosForTarget("android", UserHandle.myUserId());
157             pkgs = new ArrayList<>(infos.size());
158             for (int i = 0, size = infos.size(); i < size; i++) {
159                 if (isTheme(infos.get(i))) {
160                     if (infos.get(i).isEnabled() && currentThemeOnly) {
161                         return new String[] {infos.get(i).packageName};
162                     } else {
163                         pkgs.add(infos.get(i).packageName);
164                     }
165                 }
166             }
167         } catch (RemoteException re) {
168             throw re.rethrowFromSystemServer();
169         }
170 
171         // Current enabled theme is not found.
172         if (currentThemeOnly) {
173             return new String[0];
174         }
175         return pkgs.toArray(new String[pkgs.size()]);
176     }
177 }
178