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.ContentResolver; 20 import android.content.Context; 21 import android.content.Intent; 22 import android.content.pm.UserInfo; 23 import android.database.ContentObserver; 24 import android.net.Uri; 25 import android.os.Handler; 26 import android.os.Looper; 27 import android.os.UserManager; 28 import android.provider.Settings; 29 import android.provider.Settings.Secure; 30 import android.text.TextUtils; 31 import android.util.ArrayMap; 32 import android.util.ArraySet; 33 34 import com.android.internal.util.ArrayUtils; 35 import com.android.systemui.DemoMode; 36 import com.android.systemui.Dependency; 37 import com.android.systemui.qs.QSTileHost; 38 import com.android.systemui.settings.CurrentUserTracker; 39 import com.android.systemui.statusbar.phone.StatusBarIconController; 40 import com.android.systemui.util.leak.LeakDetector; 41 42 import java.util.HashMap; 43 import java.util.HashSet; 44 import java.util.Set; 45 46 47 public class TunerServiceImpl extends TunerService { 48 49 private static final String TUNER_VERSION = "sysui_tuner_version"; 50 51 private static final int CURRENT_TUNER_VERSION = 4; 52 53 // Things that use the tunable infrastructure but are now real user settings and 54 // shouldn't be reset with tuner settings. 55 private static final String[] RESET_BLACKLIST = new String[] { 56 QSTileHost.TILES_SETTING, 57 Settings.Secure.DOZE_ALWAYS_ON 58 }; 59 60 private final Observer mObserver = new Observer(); 61 // Map of Uris we listen on to their settings keys. 62 private final ArrayMap<Uri, String> mListeningUris = new ArrayMap<>(); 63 // Map of settings keys to the listener. 64 private final HashMap<String, Set<Tunable>> mTunableLookup = new HashMap<>(); 65 // Set of all tunables, used for leak detection. 66 private final HashSet<Tunable> mTunables = LeakDetector.ENABLED ? new HashSet<>() : null; 67 private final Context mContext; 68 69 private ContentResolver mContentResolver; 70 private int mCurrentUser; 71 private CurrentUserTracker mUserTracker; 72 73 public TunerServiceImpl(Context context) { 74 mContext = context; 75 mContentResolver = mContext.getContentResolver(); 76 77 for (UserInfo user : UserManager.get(mContext).getUsers()) { 78 mCurrentUser = user.getUserHandle().getIdentifier(); 79 if (getValue(TUNER_VERSION, 0) != CURRENT_TUNER_VERSION) { 80 upgradeTuner(getValue(TUNER_VERSION, 0), CURRENT_TUNER_VERSION); 81 } 82 } 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 @Override 97 public void destroy() { 98 mUserTracker.stopTracking(); 99 } 100 101 private void upgradeTuner(int oldVersion, int newVersion) { 102 if (oldVersion < 1) { 103 String blacklistStr = getValue(StatusBarIconController.ICON_BLACKLIST); 104 if (blacklistStr != null) { 105 ArraySet<String> iconBlacklist = 106 StatusBarIconController.getIconBlacklist(blacklistStr); 107 108 iconBlacklist.add("rotate"); 109 iconBlacklist.add("headset"); 110 111 Settings.Secure.putStringForUser(mContentResolver, 112 StatusBarIconController.ICON_BLACKLIST, 113 TextUtils.join(",", iconBlacklist), mCurrentUser); 114 } 115 } 116 if (oldVersion < 2) { 117 setTunerEnabled(mContext, false); 118 } 119 // 3 Removed because of a revert. 120 if (oldVersion < 4) { 121 // Delay this so that we can wait for everything to be registered first. 122 new Handler(Dependency.get(Dependency.BG_LOOPER)).postDelayed(() -> clearAll(), 5000); 123 } 124 setValue(TUNER_VERSION, newVersion); 125 } 126 127 @Override 128 public String getValue(String setting) { 129 return Settings.Secure.getStringForUser(mContentResolver, setting, mCurrentUser); 130 } 131 132 @Override 133 public void setValue(String setting, String value) { 134 Settings.Secure.putStringForUser(mContentResolver, setting, value, mCurrentUser); 135 } 136 137 @Override 138 public int getValue(String setting, int def) { 139 return Settings.Secure.getIntForUser(mContentResolver, setting, def, mCurrentUser); 140 } 141 142 @Override 143 public String getValue(String setting, String def) { 144 String ret = Secure.getStringForUser(mContentResolver, setting, mCurrentUser); 145 if (ret == null) return def; 146 return ret; 147 } 148 149 @Override 150 public void setValue(String setting, int value) { 151 Settings.Secure.putIntForUser(mContentResolver, setting, value, mCurrentUser); 152 } 153 154 @Override 155 public void addTunable(Tunable tunable, String... keys) { 156 for (String key : keys) { 157 addTunable(tunable, key); 158 } 159 } 160 161 private void addTunable(Tunable tunable, String key) { 162 if (!mTunableLookup.containsKey(key)) { 163 mTunableLookup.put(key, new ArraySet<Tunable>()); 164 } 165 mTunableLookup.get(key).add(tunable); 166 if (LeakDetector.ENABLED) { 167 mTunables.add(tunable); 168 Dependency.get(LeakDetector.class).trackCollection(mTunables, "TunerService.mTunables"); 169 } 170 Uri uri = Settings.Secure.getUriFor(key); 171 if (!mListeningUris.containsKey(uri)) { 172 mListeningUris.put(uri, key); 173 mContentResolver.registerContentObserver(uri, false, mObserver, mCurrentUser); 174 } 175 // Send the first state. 176 String value = Settings.Secure.getStringForUser(mContentResolver, key, mCurrentUser); 177 tunable.onTuningChanged(key, value); 178 } 179 180 @Override 181 public void removeTunable(Tunable tunable) { 182 for (Set<Tunable> list : mTunableLookup.values()) { 183 list.remove(tunable); 184 } 185 if (LeakDetector.ENABLED) { 186 mTunables.remove(tunable); 187 } 188 } 189 190 protected void reregisterAll() { 191 if (mListeningUris.size() == 0) { 192 return; 193 } 194 mContentResolver.unregisterContentObserver(mObserver); 195 for (Uri uri : mListeningUris.keySet()) { 196 mContentResolver.registerContentObserver(uri, false, mObserver, mCurrentUser); 197 } 198 } 199 200 private void reloadSetting(Uri uri) { 201 String key = mListeningUris.get(uri); 202 Set<Tunable> tunables = mTunableLookup.get(key); 203 if (tunables == null) { 204 return; 205 } 206 String value = Settings.Secure.getStringForUser(mContentResolver, key, mCurrentUser); 207 for (Tunable tunable : tunables) { 208 tunable.onTuningChanged(key, value); 209 } 210 } 211 212 private void reloadAll() { 213 for (String key : mTunableLookup.keySet()) { 214 String value = Settings.Secure.getStringForUser(mContentResolver, key, 215 mCurrentUser); 216 for (Tunable tunable : mTunableLookup.get(key)) { 217 tunable.onTuningChanged(key, value); 218 } 219 } 220 } 221 222 @Override 223 public void clearAll() { 224 // A couple special cases. 225 Settings.Global.putString(mContentResolver, DemoMode.DEMO_MODE_ALLOWED, null); 226 Intent intent = new Intent(DemoMode.ACTION_DEMO); 227 intent.putExtra(DemoMode.EXTRA_COMMAND, DemoMode.COMMAND_EXIT); 228 mContext.sendBroadcast(intent); 229 230 for (String key : mTunableLookup.keySet()) { 231 if (ArrayUtils.contains(RESET_BLACKLIST, key)) { 232 continue; 233 } 234 Settings.Secure.putString(mContentResolver, key, null); 235 } 236 } 237 238 private class Observer extends ContentObserver { 239 public Observer() { 240 super(new Handler(Looper.getMainLooper())); 241 } 242 243 @Override 244 public void onChange(boolean selfChange, Uri uri, int userId) { 245 if (userId == ActivityManager.getCurrentUser()) { 246 reloadSetting(uri); 247 } 248 } 249 } 250 } 251