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