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