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.provider.Settings.Secure; 37 import android.text.TextUtils; 38 import android.util.ArrayMap; 39 import android.util.ArraySet; 40 41 import com.android.systemui.DemoMode; 42 import com.android.systemui.Dependency; 43 import com.android.systemui.R; 44 import com.android.systemui.SysUiServiceProvider; 45 import com.android.systemui.SystemUI; 46 import com.android.systemui.SystemUIApplication; 47 import com.android.systemui.settings.CurrentUserTracker; 48 import com.android.systemui.statusbar.phone.StatusBarIconController; 49 import com.android.systemui.statusbar.phone.SystemUIDialog; 50 import com.android.systemui.util.leak.LeakDetector; 51 52 import java.util.HashMap; 53 import java.util.HashSet; 54 import java.util.Set; 55 56 57 public class TunerServiceImpl extends TunerService { 58 59 private static final String TUNER_VERSION = "sysui_tuner_version"; 60 61 private static final int CURRENT_TUNER_VERSION = 1; 62 63 private final Observer mObserver = new Observer(); 64 // Map of Uris we listen on to their settings keys. 65 private final ArrayMap<Uri, String> mListeningUris = new ArrayMap<>(); 66 // Map of settings keys to the listener. 67 private final HashMap<String, Set<Tunable>> mTunableLookup = new HashMap<>(); 68 // Set of all tunables, used for leak detection. 69 private final HashSet<Tunable> mTunables = LeakDetector.ENABLED ? new HashSet<>() : null; 70 private final Context mContext; 71 72 private ContentResolver mContentResolver; 73 private int mCurrentUser; 74 private CurrentUserTracker mUserTracker; 75 76 public TunerServiceImpl(Context context) { 77 mContext = context; 78 mContentResolver = mContext.getContentResolver(); 79 80 for (UserInfo user : UserManager.get(mContext).getUsers()) { 81 mCurrentUser = user.getUserHandle().getIdentifier(); 82 if (getValue(TUNER_VERSION, 0) != CURRENT_TUNER_VERSION) { 83 upgradeTuner(getValue(TUNER_VERSION, 0), CURRENT_TUNER_VERSION); 84 } 85 } 86 87 mCurrentUser = ActivityManager.getCurrentUser(); 88 mUserTracker = new CurrentUserTracker(mContext) { 89 @Override 90 public void onUserSwitched(int newUserId) { 91 mCurrentUser = newUserId; 92 reloadAll(); 93 reregisterAll(); 94 } 95 }; 96 mUserTracker.startTracking(); 97 } 98 99 @Override 100 public void destroy() { 101 mUserTracker.stopTracking(); 102 } 103 104 private void upgradeTuner(int oldVersion, int newVersion) { 105 if (oldVersion < 1) { 106 String blacklistStr = getValue(StatusBarIconController.ICON_BLACKLIST); 107 if (blacklistStr != null) { 108 ArraySet<String> iconBlacklist = 109 StatusBarIconController.getIconBlacklist(blacklistStr); 110 111 iconBlacklist.add("rotate"); 112 iconBlacklist.add("headset"); 113 114 Settings.Secure.putStringForUser(mContentResolver, 115 StatusBarIconController.ICON_BLACKLIST, 116 TextUtils.join(",", iconBlacklist), mCurrentUser); 117 } 118 } 119 setValue(TUNER_VERSION, newVersion); 120 } 121 122 @Override 123 public String getValue(String setting) { 124 return Settings.Secure.getStringForUser(mContentResolver, setting, mCurrentUser); 125 } 126 127 @Override 128 public void setValue(String setting, String value) { 129 Settings.Secure.putStringForUser(mContentResolver, setting, value, mCurrentUser); 130 } 131 132 @Override 133 public int getValue(String setting, int def) { 134 return Settings.Secure.getIntForUser(mContentResolver, setting, def, mCurrentUser); 135 } 136 137 @Override 138 public String getValue(String setting, String def) { 139 String ret = Secure.getStringForUser(mContentResolver, setting, mCurrentUser); 140 if (ret == null) return def; 141 return ret; 142 } 143 144 @Override 145 public void setValue(String setting, int value) { 146 Settings.Secure.putIntForUser(mContentResolver, setting, value, mCurrentUser); 147 } 148 149 @Override 150 public void addTunable(Tunable tunable, String... keys) { 151 for (String key : keys) { 152 addTunable(tunable, key); 153 } 154 } 155 156 private void addTunable(Tunable tunable, String key) { 157 if (!mTunableLookup.containsKey(key)) { 158 mTunableLookup.put(key, new ArraySet<Tunable>()); 159 } 160 mTunableLookup.get(key).add(tunable); 161 if (LeakDetector.ENABLED) { 162 mTunables.add(tunable); 163 Dependency.get(LeakDetector.class).trackCollection(mTunables, "TunerService.mTunables"); 164 } 165 Uri uri = Settings.Secure.getUriFor(key); 166 if (!mListeningUris.containsKey(uri)) { 167 mListeningUris.put(uri, key); 168 mContentResolver.registerContentObserver(uri, false, mObserver, mCurrentUser); 169 } 170 // Send the first state. 171 String value = Settings.Secure.getStringForUser(mContentResolver, key, mCurrentUser); 172 tunable.onTuningChanged(key, value); 173 } 174 175 @Override 176 public void removeTunable(Tunable tunable) { 177 for (Set<Tunable> list : mTunableLookup.values()) { 178 list.remove(tunable); 179 } 180 if (LeakDetector.ENABLED) { 181 mTunables.remove(tunable); 182 } 183 } 184 185 protected void reregisterAll() { 186 if (mListeningUris.size() == 0) { 187 return; 188 } 189 mContentResolver.unregisterContentObserver(mObserver); 190 for (Uri uri : mListeningUris.keySet()) { 191 mContentResolver.registerContentObserver(uri, false, mObserver, mCurrentUser); 192 } 193 } 194 195 private void reloadSetting(Uri uri) { 196 String key = mListeningUris.get(uri); 197 Set<Tunable> tunables = mTunableLookup.get(key); 198 if (tunables == null) { 199 return; 200 } 201 String value = Settings.Secure.getStringForUser(mContentResolver, key, mCurrentUser); 202 for (Tunable tunable : tunables) { 203 tunable.onTuningChanged(key, value); 204 } 205 } 206 207 private void reloadAll() { 208 for (String key : mTunableLookup.keySet()) { 209 String value = Settings.Secure.getStringForUser(mContentResolver, key, 210 mCurrentUser); 211 for (Tunable tunable : mTunableLookup.get(key)) { 212 tunable.onTuningChanged(key, value); 213 } 214 } 215 } 216 217 @Override 218 public void clearAll() { 219 // A couple special cases. 220 Settings.Global.putString(mContentResolver, DemoMode.DEMO_MODE_ALLOWED, null); 221 Intent intent = new Intent(DemoMode.ACTION_DEMO); 222 intent.putExtra(DemoMode.EXTRA_COMMAND, DemoMode.COMMAND_EXIT); 223 mContext.sendBroadcast(intent); 224 225 for (String key : mTunableLookup.keySet()) { 226 Settings.Secure.putString(mContentResolver, key, null); 227 } 228 } 229 230 private class Observer extends ContentObserver { 231 public Observer() { 232 super(new Handler(Looper.getMainLooper())); 233 } 234 235 @Override 236 public void onChange(boolean selfChange, Uri uri, int userId) { 237 if (userId == ActivityManager.getCurrentUser()) { 238 reloadSetting(uri); 239 } 240 } 241 } 242 } 243