Home | History | Annotate | Download | only in display
      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.PreferenceController;
     32 import com.android.settings.core.instrumentation.MetricsFeatureProvider;
     33 import com.android.settings.overlay.FeatureFactory;
     34 
     35 import libcore.util.Objects;
     36 
     37 import java.util.ArrayList;
     38 import java.util.List;
     39 
     40 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.ACTION_THEME;
     41 
     42 public class ThemePreferenceController extends PreferenceController implements
     43         Preference.OnPreferenceChangeListener {
     44 
     45     private static final String KEY_THEME = "theme";
     46 
     47     private final MetricsFeatureProvider mMetricsFeatureProvider;
     48     private final OverlayManager mOverlayService;
     49     private final PackageManager mPackageManager;
     50 
     51     public ThemePreferenceController(Context context) {
     52         this(context, ServiceManager.getService(Context.OVERLAY_SERVICE) != null
     53                 ? new OverlayManager() : null);
     54     }
     55 
     56     @VisibleForTesting
     57     ThemePreferenceController(Context context, OverlayManager overlayManager) {
     58         super(context);
     59         mOverlayService = overlayManager;
     60         mPackageManager = context.getPackageManager();
     61         mMetricsFeatureProvider = FeatureFactory.getFactory(context).getMetricsFeatureProvider();
     62     }
     63 
     64     @Override
     65     public String getPreferenceKey() {
     66         return KEY_THEME;
     67     }
     68 
     69     @Override
     70     public boolean handlePreferenceTreeClick(Preference preference) {
     71         if (KEY_THEME.equals(preference.getKey())) {
     72             mMetricsFeatureProvider.action(mContext, ACTION_THEME);
     73         }
     74         return false;
     75     }
     76 
     77     @Override
     78     public void updateState(Preference preference) {
     79         ListPreference pref = (ListPreference) preference;
     80         String[] pkgs = getAvailableThemes();
     81         CharSequence[] labels = new CharSequence[pkgs.length];
     82         for (int i = 0; i < pkgs.length; i++) {
     83             try {
     84                 labels[i] = mPackageManager.getApplicationInfo(pkgs[i], 0)
     85                         .loadLabel(mPackageManager);
     86             } catch (NameNotFoundException e) {
     87                 labels[i] = pkgs[i];
     88             }
     89         }
     90         pref.setEntries(labels);
     91         pref.setEntryValues(pkgs);
     92         String theme = getCurrentTheme();
     93         if (TextUtils.isEmpty(theme)) {
     94             theme = mContext.getString(R.string.default_theme);
     95             pref.setSummary(theme);
     96         }
     97         pref.setSummary(theme);
     98         pref.setValue(theme);
     99     }
    100 
    101     @Override
    102     public boolean onPreferenceChange(Preference preference, Object newValue) {
    103         String current = getTheme();
    104         if (Objects.equal(newValue, current)) {
    105             return true;
    106         }
    107         try {
    108             mOverlayService.setEnabledExclusive((String) newValue, true, UserHandle.myUserId());
    109         } catch (RemoteException e) {
    110             return false;
    111         }
    112         return true;
    113     }
    114 
    115     private boolean isChangeableOverlay(String packageName) {
    116         try {
    117             PackageInfo pi = mPackageManager.getPackageInfo(packageName, 0);
    118             return pi != null && !pi.isStaticOverlay;
    119         } catch (PackageManager.NameNotFoundException e) {
    120             return false;
    121         }
    122     }
    123 
    124     private String getTheme() {
    125         try {
    126             List<OverlayInfo> infos = mOverlayService.getOverlayInfosForTarget("android",
    127                     UserHandle.myUserId());
    128             for (int i = 0, size = infos.size(); i < size; i++) {
    129                 if (infos.get(i).isEnabled() &&
    130                          isChangeableOverlay(infos.get(i).packageName)) {
    131                     return infos.get(i).packageName;
    132                 }
    133             }
    134         } catch (RemoteException e) {
    135         }
    136         return null;
    137     }
    138 
    139     @Override
    140     public boolean isAvailable() {
    141         if (mOverlayService == null) return false;
    142         String[] themes = getAvailableThemes();
    143         return themes != null && themes.length > 1;
    144     }
    145 
    146 
    147     @VisibleForTesting
    148     String getCurrentTheme() {
    149         return getTheme();
    150     }
    151 
    152     @VisibleForTesting
    153     String[] getAvailableThemes() {
    154         try {
    155             List<OverlayInfo> infos = mOverlayService.getOverlayInfosForTarget("android",
    156                     UserHandle.myUserId());
    157             List<String> pkgs = new ArrayList(infos.size());
    158             for (int i = 0, size = infos.size(); i < size; i++) {
    159                 if (isChangeableOverlay(infos.get(i).packageName)) {
    160                     pkgs.add(infos.get(i).packageName);
    161                 }
    162             }
    163             return pkgs.toArray(new String[pkgs.size()]);
    164         } catch (RemoteException e) {
    165         }
    166         return new String[0];
    167     }
    168 
    169     public static class OverlayManager {
    170         private final IOverlayManager mService;
    171 
    172         public OverlayManager() {
    173             mService = IOverlayManager.Stub.asInterface(
    174                     ServiceManager.getService(Context.OVERLAY_SERVICE));
    175         }
    176 
    177         public void setEnabledExclusive(String pkg, boolean enabled, int userId)
    178                 throws RemoteException {
    179             mService.setEnabledExclusive(pkg, enabled, userId);
    180         }
    181 
    182         public List<OverlayInfo> getOverlayInfosForTarget(String target, int userId)
    183                 throws RemoteException {
    184             return mService.getOverlayInfosForTarget(target, userId);
    185         }
    186     }
    187 }
    188