Home | History | Annotate | Download | only in tuner
      1 /*
      2  * Copyright (C) 2015 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  */
     16 package com.android.systemui.tuner;
     17 
     18 import android.app.ActivityManager;
     19 import android.content.BroadcastReceiver;
     20 import android.content.ComponentName;
     21 import android.content.ContentResolver;
     22 import android.content.Context;
     23 import android.content.DialogInterface;
     24 import android.content.DialogInterface.OnClickListener;
     25 import android.content.Intent;
     26 import android.content.pm.PackageManager;
     27 import android.content.pm.PackageManager.NameNotFoundException;
     28 import android.content.pm.UserInfo;
     29 import android.database.ContentObserver;
     30 import android.net.Uri;
     31 import android.os.Handler;
     32 import android.os.Looper;
     33 import android.os.UserHandle;
     34 import android.os.UserManager;
     35 import android.provider.Settings;
     36 import android.text.TextUtils;
     37 import android.util.ArrayMap;
     38 import android.util.ArraySet;
     39 
     40 import com.android.systemui.BatteryMeterDrawable;
     41 import com.android.systemui.DemoMode;
     42 import com.android.systemui.R;
     43 import com.android.systemui.SystemUI;
     44 import com.android.systemui.SystemUIApplication;
     45 import com.android.systemui.settings.CurrentUserTracker;
     46 import com.android.systemui.statusbar.phone.StatusBarIconController;
     47 import com.android.systemui.statusbar.phone.SystemUIDialog;
     48 
     49 import java.util.HashMap;
     50 import java.util.Set;
     51 
     52 
     53 public class TunerService extends SystemUI {
     54 
     55     public static final String ACTION_CLEAR = "com.android.systemui.action.CLEAR_TUNER";
     56 
     57     private static final String TUNER_VERSION = "sysui_tuner_version";
     58 
     59     private static final int CURRENT_TUNER_VERSION = 1;
     60 
     61     private final Observer mObserver = new Observer();
     62     // Map of Uris we listen on to their settings keys.
     63     private final ArrayMap<Uri, String> mListeningUris = new ArrayMap<>();
     64     // Map of settings keys to the listener.
     65     private final HashMap<String, Set<Tunable>> mTunableLookup = new HashMap<>();
     66 
     67     private ContentResolver mContentResolver;
     68     private int mCurrentUser;
     69     private CurrentUserTracker mUserTracker;
     70 
     71     @Override
     72     public void start() {
     73         mContentResolver = mContext.getContentResolver();
     74 
     75         for (UserInfo user : UserManager.get(mContext).getUsers()) {
     76             mCurrentUser = user.getUserHandle().getIdentifier();
     77             if (getValue(TUNER_VERSION, 0) != CURRENT_TUNER_VERSION) {
     78                 upgradeTuner(getValue(TUNER_VERSION, 0), CURRENT_TUNER_VERSION);
     79             }
     80         }
     81         putComponent(TunerService.class, this);
     82 
     83         mCurrentUser = ActivityManager.getCurrentUser();
     84         mUserTracker = new CurrentUserTracker(mContext) {
     85             @Override
     86             public void onUserSwitched(int newUserId) {
     87                 mCurrentUser = newUserId;
     88                 reloadAll();
     89                 reregisterAll();
     90             }
     91         };
     92         mUserTracker.startTracking();
     93     }
     94 
     95     private void upgradeTuner(int oldVersion, int newVersion) {
     96         if (oldVersion < 1) {
     97             String blacklistStr = getValue(StatusBarIconController.ICON_BLACKLIST);
     98             if (blacklistStr != null) {
     99                 ArraySet<String> iconBlacklist =
    100                         StatusBarIconController.getIconBlacklist(blacklistStr);
    101 
    102                 iconBlacklist.add("rotate");
    103                 iconBlacklist.add("headset");
    104 
    105                 Settings.Secure.putStringForUser(mContentResolver,
    106                         StatusBarIconController.ICON_BLACKLIST,
    107                         TextUtils.join(",", iconBlacklist), mCurrentUser);
    108             }
    109         }
    110         setValue(TUNER_VERSION, newVersion);
    111     }
    112 
    113     public String getValue(String setting) {
    114         return Settings.Secure.getStringForUser(mContentResolver, setting, mCurrentUser);
    115     }
    116 
    117     public void setValue(String setting, String value) {
    118          Settings.Secure.putStringForUser(mContentResolver, setting, value, mCurrentUser);
    119     }
    120 
    121     public int getValue(String setting, int def) {
    122         return Settings.Secure.getIntForUser(mContentResolver, setting, def, mCurrentUser);
    123     }
    124 
    125     public void setValue(String setting, int value) {
    126          Settings.Secure.putIntForUser(mContentResolver, setting, value, mCurrentUser);
    127     }
    128 
    129     public void addTunable(Tunable tunable, String... keys) {
    130         for (String key : keys) {
    131             addTunable(tunable, key);
    132         }
    133     }
    134 
    135     private void addTunable(Tunable tunable, String key) {
    136         if (!mTunableLookup.containsKey(key)) {
    137             mTunableLookup.put(key, new ArraySet<Tunable>());
    138         }
    139         mTunableLookup.get(key).add(tunable);
    140         Uri uri = Settings.Secure.getUriFor(key);
    141         if (!mListeningUris.containsKey(uri)) {
    142             mListeningUris.put(uri, key);
    143             mContentResolver.registerContentObserver(uri, false, mObserver, mCurrentUser);
    144         }
    145         // Send the first state.
    146         String value = Settings.Secure.getStringForUser(mContentResolver, key, mCurrentUser);
    147         tunable.onTuningChanged(key, value);
    148     }
    149 
    150     public void removeTunable(Tunable tunable) {
    151         for (Set<Tunable> list : mTunableLookup.values()) {
    152             list.remove(tunable);
    153         }
    154     }
    155 
    156     protected void reregisterAll() {
    157         if (mListeningUris.size() == 0) {
    158             return;
    159         }
    160         mContentResolver.unregisterContentObserver(mObserver);
    161         for (Uri uri : mListeningUris.keySet()) {
    162             mContentResolver.registerContentObserver(uri, false, mObserver, mCurrentUser);
    163         }
    164     }
    165 
    166     public void reloadSetting(Uri uri) {
    167         String key = mListeningUris.get(uri);
    168         Set<Tunable> tunables = mTunableLookup.get(key);
    169         if (tunables == null) {
    170             return;
    171         }
    172         String value = Settings.Secure.getStringForUser(mContentResolver, key, mCurrentUser);
    173         for (Tunable tunable : tunables) {
    174             tunable.onTuningChanged(key, value);
    175         }
    176     }
    177 
    178     private void reloadAll() {
    179         for (String key : mTunableLookup.keySet()) {
    180             String value = Settings.Secure.getStringForUser(mContentResolver, key,
    181                     mCurrentUser);
    182             for (Tunable tunable : mTunableLookup.get(key)) {
    183                 tunable.onTuningChanged(key, value);
    184             }
    185         }
    186     }
    187 
    188     public void clearAll() {
    189         // A couple special cases.
    190         Settings.Global.putString(mContentResolver, DemoMode.DEMO_MODE_ALLOWED, null);
    191         Settings.System.putString(mContentResolver, BatteryMeterDrawable.SHOW_PERCENT_SETTING, null);
    192         Intent intent = new Intent(DemoMode.ACTION_DEMO);
    193         intent.putExtra(DemoMode.EXTRA_COMMAND, DemoMode.COMMAND_EXIT);
    194         mContext.sendBroadcast(intent);
    195 
    196         for (String key : mTunableLookup.keySet()) {
    197             Settings.Secure.putString(mContentResolver, key, null);
    198         }
    199     }
    200 
    201     // Only used in other processes, such as the tuner.
    202     private static TunerService sInstance;
    203 
    204     public static TunerService get(Context context) {
    205         TunerService service = null;
    206         if (context.getApplicationContext() instanceof SystemUIApplication) {
    207             SystemUIApplication sysUi = (SystemUIApplication) context.getApplicationContext();
    208             service = sysUi.getComponent(TunerService.class);
    209         }
    210         if (service == null) {
    211             // Can't get it as a component, must in the tuner, lets just create one for now.
    212             return getStaticService(context);
    213         }
    214         return service;
    215     }
    216 
    217     private static TunerService getStaticService(Context context) {
    218         if (sInstance == null) {
    219             sInstance = new TunerService();
    220             sInstance.mContext = context.getApplicationContext();
    221             sInstance.mComponents = new HashMap<>();
    222             sInstance.start();
    223         }
    224         return sInstance;
    225     }
    226 
    227     public static final void showResetRequest(final Context context, final Runnable onDisabled) {
    228         SystemUIDialog dialog = new SystemUIDialog(context);
    229         dialog.setShowForAllUsers(true);
    230         dialog.setMessage(R.string.remove_from_settings_prompt);
    231         dialog.setButton(DialogInterface.BUTTON_NEGATIVE, context.getString(R.string.cancel),
    232                 (OnClickListener) null);
    233         dialog.setButton(DialogInterface.BUTTON_POSITIVE,
    234                 context.getString(R.string.guest_exit_guest_dialog_remove), new OnClickListener() {
    235             @Override
    236             public void onClick(DialogInterface dialog, int which) {
    237                 // Tell the tuner (in main SysUI process) to clear all its settings.
    238                 context.sendBroadcast(new Intent(TunerService.ACTION_CLEAR));
    239                 // Disable access to tuner.
    240                 TunerService.setTunerEnabled(context, false);
    241                 // Make them sit through the warning dialog again.
    242                 Settings.Secure.putInt(context.getContentResolver(),
    243                         TunerFragment.SETTING_SEEN_TUNER_WARNING, 0);
    244                 if (onDisabled != null) {
    245                     onDisabled.run();
    246                 }
    247             }
    248         });
    249         dialog.show();
    250     }
    251 
    252     public static final void setTunerEnabled(Context context, boolean enabled) {
    253         userContext(context).getPackageManager().setComponentEnabledSetting(
    254                 new ComponentName(context, TunerActivity.class),
    255                 enabled ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED
    256                         : PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
    257                         PackageManager.DONT_KILL_APP);
    258     }
    259 
    260     public static final boolean isTunerEnabled(Context context) {
    261         return userContext(context).getPackageManager().getComponentEnabledSetting(
    262                 new ComponentName(context, TunerActivity.class))
    263                 == PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
    264     }
    265 
    266     private static Context userContext(Context context) {
    267         try {
    268             return context.createPackageContextAsUser(context.getPackageName(), 0,
    269                     new UserHandle(ActivityManager.getCurrentUser()));
    270         } catch (NameNotFoundException e) {
    271             return context;
    272         }
    273     }
    274 
    275     private class Observer extends ContentObserver {
    276         public Observer() {
    277             super(new Handler(Looper.getMainLooper()));
    278         }
    279 
    280         @Override
    281         public void onChange(boolean selfChange, Uri uri, int userId) {
    282             if (userId == ActivityManager.getCurrentUser()) {
    283                 reloadSetting(uri);
    284             }
    285         }
    286     }
    287 
    288     public interface Tunable {
    289         void onTuningChanged(String key, String newValue);
    290     }
    291 
    292     public static class ClearReceiver extends BroadcastReceiver {
    293         @Override
    294         public void onReceive(Context context, Intent intent) {
    295             if (ACTION_CLEAR.equals(intent.getAction())) {
    296                 get(context).clearAll();
    297             }
    298         }
    299     }
    300 }
    301