2 * Copyright (C) 2017 The Android Open Source Project
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
7 * http://www.apache.org/licenses/LICENSE-2.0
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.
14 package com.android.settings.display;
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;
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;
36 import libcore.util.Objects;
38 import java.util.ArrayList;
39 import java.util.List;
41 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.ACTION_THEME;
43 public class ThemePreferenceController extends AbstractPreferenceController implements
44 PreferenceControllerMixin, Preference.OnPreferenceChangeListener {
46 private static final String KEY_THEME = "theme";
48 private final MetricsFeatureProvider mMetricsFeatureProvider;
49 private final OverlayManager mOverlayService;
50 private final PackageManager mPackageManager;
52 public ThemePreferenceController(Context context) {
53 this(context, ServiceManager.getService(Context.OVERLAY_SERVICE) != null
54 ? new OverlayManager() : null);
58 ThemePreferenceController(Context context, OverlayManager overlayManager) {
60 mOverlayService = overlayManager;
61 mPackageManager = context.getPackageManager();
62 mMetricsFeatureProvider = FeatureFactory.getFactory(context).getMetricsFeatureProvider();
66 public String getPreferenceKey() {
71 public boolean handlePreferenceTreeClick(Preference preference) {
72 if (KEY_THEME.equals(preference.getKey())) {
73 mMetricsFeatureProvider.action(mContext, ACTION_THEME);
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++) {
85 labels[i] = mPackageManager.getApplicationInfo(pkgs[i], 0)
86 .loadLabel(mPackageManager);
87 } catch (NameNotFoundException e) {
91 pref.setEntries(labels);
92 pref.setEntryValues(pkgs);
93 String theme = getCurrentTheme();
94 CharSequence themeLabel = null;
96 for (int i = 0; i < pkgs.length; i++) {
97 if (TextUtils.equals(pkgs[i], theme)) {
98 themeLabel = labels[i];
103 if (TextUtils.isEmpty(themeLabel)) {
104 themeLabel = mContext.getString(R.string.default_theme);
107 pref.setSummary(themeLabel);
108 pref.setValue(theme);
112 public boolean onPreferenceChange(Preference preference, Object newValue) {
113 String current = getTheme();
114 if (Objects.equal(newValue, current)) {
118 mOverlayService.setEnabledExclusive((String) newValue, true, UserHandle.myUserId());
119 } catch (RemoteException e) {
125 private boolean isChangeableOverlay(String packageName) {
127 PackageInfo pi = mPackageManager.getPackageInfo(packageName, 0);
128 return pi != null && !pi.isStaticOverlay;
129 } catch (PackageManager.NameNotFoundException e) {
134 private String getTheme() {
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;
144 } catch (RemoteException e) {
150 public boolean isAvailable() {
151 if (mOverlayService == null) return false;
152 String[] themes = getAvailableThemes();
153 return themes != null && themes.length > 1;
158 String getCurrentTheme() {
163 String[] getAvailableThemes() {
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);
173 return pkgs.toArray(new String[pkgs.size()]);
174 } catch (RemoteException e) {
176 return new String[0];
179 public static class OverlayManager {
180 private final IOverlayManager mService;
182 public OverlayManager() {
183 mService = IOverlayManager.Stub.asInterface(
184 ServiceManager.getService(Context.OVERLAY_SERVICE));
187 public void setEnabledExclusive(String pkg, boolean enabled, int userId)
188 throws RemoteException {
189 mService.setEnabledExclusive(pkg, enabled, userId);
192 public List<OverlayInfo> getOverlayInfosForTarget(String target, int userId)
193 throws RemoteException {
194 return mService.getOverlayInfosForTarget(target, userId);