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