OSDN Git Service

3bb58b15d0c929e0159afddc7e16f7e51780977b
[android-x86/packages-apps-Settings.git] / src / com / android / settings / display / ThemePreferenceController.java
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 import android.content.Context;
17 import android.content.om.IOverlayManager;
18 import android.content.om.OverlayInfo;
19 import android.content.pm.PackageInfo;
20 import android.content.pm.PackageManager;
21 import android.content.pm.PackageManager.NameNotFoundException;
22 import android.os.RemoteException;
23 import android.os.ServiceManager;
24 import android.os.UserHandle;
25 import android.support.annotation.VisibleForTesting;
26 import android.support.v7.preference.ListPreference;
27 import android.support.v7.preference.Preference;
28 import android.text.TextUtils;
29
30 import com.android.settings.R;
31 import com.android.settings.core.PreferenceControllerMixin;
32 import com.android.settings.core.instrumentation.MetricsFeatureProvider;
33 import com.android.settings.overlay.FeatureFactory;
34 import com.android.settingslib.core.AbstractPreferenceController;
35
36 import libcore.util.Objects;
37
38 import java.util.ArrayList;
39 import java.util.List;
40
41 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.ACTION_THEME;
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 OverlayManager mOverlayService;
50     private final PackageManager mPackageManager;
51
52     public ThemePreferenceController(Context context) {
53         this(context, ServiceManager.getService(Context.OVERLAY_SERVICE) != null
54                 ? new OverlayManager() : null);
55     }
56
57     @VisibleForTesting
58     ThemePreferenceController(Context context, OverlayManager overlayManager) {
59         super(context);
60         mOverlayService = overlayManager;
61         mPackageManager = context.getPackageManager();
62         mMetricsFeatureProvider = FeatureFactory.getFactory(context).getMetricsFeatureProvider();
63     }
64
65     @Override
66     public String getPreferenceKey() {
67         return KEY_THEME;
68     }
69
70     @Override
71     public boolean handlePreferenceTreeClick(Preference preference) {
72         if (KEY_THEME.equals(preference.getKey())) {
73             mMetricsFeatureProvider.action(mContext, ACTION_THEME);
74         }
75         return false;
76     }
77
78     @Override
79     public void updateState(Preference preference) {
80         ListPreference pref = (ListPreference) preference;
81         String[] pkgs = getAvailableThemes();
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
112     public boolean onPreferenceChange(Preference preference, Object newValue) {
113         String current = getTheme();
114         if (Objects.equal(newValue, current)) {
115             return true;
116         }
117         try {
118             mOverlayService.setEnabledExclusive((String) newValue, true, UserHandle.myUserId());
119         } catch (RemoteException e) {
120             return false;
121         }
122         return true;
123     }
124
125     private boolean isChangeableOverlay(String packageName) {
126         try {
127             PackageInfo pi = mPackageManager.getPackageInfo(packageName, 0);
128             return pi != null && !pi.isStaticOverlay;
129         } catch (PackageManager.NameNotFoundException e) {
130             return false;
131         }
132     }
133
134     private String getTheme() {
135         try {
136             List<OverlayInfo> infos = mOverlayService.getOverlayInfosForTarget("android",
137                     UserHandle.myUserId());
138             for (int i = 0, size = infos.size(); i < size; i++) {
139                 if (infos.get(i).isEnabled() &&
140                         isChangeableOverlay(infos.get(i).packageName)) {
141                     return infos.get(i).packageName;
142                 }
143             }
144         } catch (RemoteException e) {
145         }
146         return null;
147     }
148
149     @Override
150     public boolean isAvailable() {
151         if (mOverlayService == null) return false;
152         String[] themes = getAvailableThemes();
153         return themes != null && themes.length > 1;
154     }
155
156
157     @VisibleForTesting
158     String getCurrentTheme() {
159         return getTheme();
160     }
161
162     @VisibleForTesting
163     String[] getAvailableThemes() {
164         try {
165             List<OverlayInfo> infos = mOverlayService.getOverlayInfosForTarget("android",
166                     UserHandle.myUserId());
167             List<String> pkgs = new ArrayList(infos.size());
168             for (int i = 0, size = infos.size(); i < size; i++) {
169                 if (isChangeableOverlay(infos.get(i).packageName)) {
170                     pkgs.add(infos.get(i).packageName);
171                 }
172             }
173             return pkgs.toArray(new String[pkgs.size()]);
174         } catch (RemoteException e) {
175         }
176         return new String[0];
177     }
178
179     public static class OverlayManager {
180         private final IOverlayManager mService;
181
182         public OverlayManager() {
183             mService = IOverlayManager.Stub.asInterface(
184                     ServiceManager.getService(Context.OVERLAY_SERVICE));
185         }
186
187         public void setEnabledExclusive(String pkg, boolean enabled, int userId)
188                 throws RemoteException {
189             mService.setEnabledExclusive(pkg, enabled, userId);
190         }
191
192         public List<OverlayInfo> getOverlayInfosForTarget(String target, int userId)
193                 throws RemoteException {
194             return mService.getOverlayInfosForTarget(target, userId);
195         }
196     }
197 }