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