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