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.content.ComponentName; 19 import android.content.ContentResolver; 20 import android.content.Context; 21 import android.content.DialogInterface; 22 import android.content.Intent; 23 import android.content.pm.PackageManager; 24 import android.content.pm.UserInfo; 25 import android.database.ContentObserver; 26 import android.net.Uri; 27 import android.os.Handler; 28 import android.os.HandlerExecutor; 29 import android.os.Looper; 30 import android.os.UserManager; 31 import android.provider.Settings; 32 import android.provider.Settings.Secure; 33 import android.text.TextUtils; 34 import android.util.ArrayMap; 35 import android.util.ArraySet; 36 37 import androidx.annotation.WorkerThread; 38 39 import com.android.internal.util.ArrayUtils; 40 import com.android.systemui.DejankUtils; 41 import com.android.systemui.dagger.SysUISingleton; 42 import com.android.systemui.dagger.qualifiers.Main; 43 import com.android.systemui.demomode.DemoModeController; 44 import com.android.systemui.qs.QSHost; 45 import com.android.systemui.res.R; 46 import com.android.systemui.settings.UserTracker; 47 import com.android.systemui.statusbar.phone.SystemUIDialog; 48 import com.android.systemui.statusbar.phone.ui.StatusBarIconController; 49 import com.android.systemui.util.leak.LeakDetector; 50 51 import dagger.Lazy; 52 53 import java.util.HashSet; 54 import java.util.Set; 55 import java.util.concurrent.ConcurrentHashMap; 56 57 import javax.inject.Inject; 58 59 /** 60 * @deprecated Don't use this class to listen to Secure Settings. Use {@code SecureSettings} instead 61 * or {@code SettingsObserver} to be able to specify the handler. 62 * This class will interact with SecureSettings using the main looper. 63 */ 64 @Deprecated 65 @SysUISingleton 66 public class TunerServiceImpl extends TunerService { 67 68 private static final String TAG = "TunerService"; 69 private static final String TUNER_VERSION = "sysui_tuner_version"; 70 71 private static final int CURRENT_TUNER_VERSION = 4; 72 73 // Things that use the tunable infrastructure but are now real user settings and 74 // shouldn't be reset with tuner settings. 75 private static final String[] RESET_EXCEPTION_LIST = new String[] { 76 QSHost.TILES_SETTING, 77 Settings.Secure.DOZE_ALWAYS_ON, 78 Settings.Secure.MEDIA_CONTROLS_RESUME, 79 Settings.Secure.MEDIA_CONTROLS_RECOMMENDATION 80 }; 81 82 private final Observer mObserver = new Observer(); 83 // Map of Uris we listen on to their settings keys. 84 private final ArrayMap<Uri, String> mListeningUris = new ArrayMap<>(); 85 // Map of settings keys to the listener. 86 private final ConcurrentHashMap<String, Set<Tunable>> mTunableLookup = 87 new ConcurrentHashMap<>(); 88 // Set of all tunables, used for leak detection. 89 private final HashSet<Tunable> mTunables = LeakDetector.ENABLED ? new HashSet<>() : null; 90 private final Context mContext; 91 private final Lazy<SystemUIDialog.Factory> mSystemUIDialogFactoryLazy; 92 private final LeakDetector mLeakDetector; 93 private final DemoModeController mDemoModeController; 94 95 private ContentResolver mContentResolver; 96 private int mCurrentUser; 97 private UserTracker.Callback mCurrentUserTracker; 98 private UserTracker mUserTracker; 99 private final ComponentName mTunerComponent; 100 101 /** 102 */ 103 @Inject TunerServiceImpl( Context context, @Main Handler mainHandler, LeakDetector leakDetector, DemoModeController demoModeController, UserTracker userTracker, Lazy<SystemUIDialog.Factory> systemUIDialogFactoryLazy)104 public TunerServiceImpl( 105 Context context, 106 @Main Handler mainHandler, 107 LeakDetector leakDetector, 108 DemoModeController demoModeController, 109 UserTracker userTracker, 110 Lazy<SystemUIDialog.Factory> systemUIDialogFactoryLazy) { 111 super(context); 112 mContext = context; 113 mSystemUIDialogFactoryLazy = systemUIDialogFactoryLazy; 114 mContentResolver = mContext.getContentResolver(); 115 mLeakDetector = leakDetector; 116 mDemoModeController = demoModeController; 117 mUserTracker = userTracker; 118 mTunerComponent = new ComponentName(mContext, TunerActivity.class); 119 120 for (UserInfo user : UserManager.get(mContext).getUsers()) { 121 mCurrentUser = user.getUserHandle().getIdentifier(); 122 if (getValue(TUNER_VERSION, 0) != CURRENT_TUNER_VERSION) { 123 upgradeTuner(getValue(TUNER_VERSION, 0), CURRENT_TUNER_VERSION, mainHandler); 124 } 125 } 126 127 mCurrentUser = mUserTracker.getUserId(); 128 mCurrentUserTracker = new UserTracker.Callback() { 129 @Override 130 public void onUserChanged(int newUser, Context userContext) { 131 mCurrentUser = newUser; 132 reloadAll(); 133 reregisterAll(); 134 } 135 }; 136 mUserTracker.addCallback(mCurrentUserTracker, 137 new HandlerExecutor(mainHandler)); 138 } 139 140 @Override destroy()141 public void destroy() { 142 mUserTracker.removeCallback(mCurrentUserTracker); 143 } 144 upgradeTuner(int oldVersion, int newVersion, Handler mainHandler)145 private void upgradeTuner(int oldVersion, int newVersion, Handler mainHandler) { 146 if (oldVersion < 1) { 147 String hideListStr = getValue(StatusBarIconController.ICON_HIDE_LIST); 148 if (hideListStr != null) { 149 ArraySet<String> iconHideList = 150 StatusBarIconController.getIconHideList(mContext, hideListStr); 151 152 iconHideList.add("rotate"); 153 iconHideList.add("headset"); 154 155 Settings.Secure.putStringForUser(mContentResolver, 156 StatusBarIconController.ICON_HIDE_LIST, 157 TextUtils.join(",", iconHideList), mCurrentUser); 158 } 159 } 160 if (oldVersion < 2) { 161 setTunerEnabled(false); 162 } 163 // 3 Removed because of a revert. 164 if (oldVersion < 4) { 165 // Delay this so that we can wait for everything to be registered first. 166 final int user = mCurrentUser; 167 mainHandler.postDelayed( 168 () -> clearAllFromUser(user), 5000); 169 } 170 setValue(TUNER_VERSION, newVersion); 171 } 172 173 @Override getValue(String setting)174 public String getValue(String setting) { 175 return Settings.Secure.getStringForUser(mContentResolver, setting, mCurrentUser); 176 } 177 178 @Override setValue(String setting, String value)179 public void setValue(String setting, String value) { 180 Settings.Secure.putStringForUser(mContentResolver, setting, value, mCurrentUser); 181 } 182 183 @Override getValue(String setting, int def)184 public int getValue(String setting, int def) { 185 return Settings.Secure.getIntForUser(mContentResolver, setting, def, mCurrentUser); 186 } 187 188 @Override getValue(String setting, String def)189 public String getValue(String setting, String def) { 190 String ret = Secure.getStringForUser(mContentResolver, setting, mCurrentUser); 191 if (ret == null) return def; 192 return ret; 193 } 194 195 @Override setValue(String setting, int value)196 public void setValue(String setting, int value) { 197 Settings.Secure.putIntForUser(mContentResolver, setting, value, mCurrentUser); 198 } 199 200 @Override addTunable(Tunable tunable, String... keys)201 public void addTunable(Tunable tunable, String... keys) { 202 for (String key : keys) { 203 addTunable(tunable, key); 204 } 205 } 206 addTunable(Tunable tunable, String key)207 private void addTunable(Tunable tunable, String key) { 208 if (!mTunableLookup.containsKey(key)) { 209 mTunableLookup.put(key, new ArraySet<Tunable>()); 210 } 211 mTunableLookup.get(key).add(tunable); 212 if (LeakDetector.ENABLED) { 213 mTunables.add(tunable); 214 mLeakDetector.trackCollection(mTunables, "TunerService.mTunables"); 215 } 216 Uri uri = Settings.Secure.getUriFor(key); 217 if (!mListeningUris.containsKey(uri)) { 218 mListeningUris.put(uri, key); 219 mContentResolver.registerContentObserver(uri, false, mObserver, mCurrentUser); 220 } 221 // Send the first state. 222 String value = DejankUtils.whitelistIpcs(() -> Settings.Secure 223 .getStringForUser(mContentResolver, key, mCurrentUser)); 224 tunable.onTuningChanged(key, value); 225 } 226 227 @Override removeTunable(Tunable tunable)228 public void removeTunable(Tunable tunable) { 229 for (Set<Tunable> list : mTunableLookup.values()) { 230 list.remove(tunable); 231 } 232 if (LeakDetector.ENABLED) { 233 mTunables.remove(tunable); 234 } 235 } 236 reregisterAll()237 protected void reregisterAll() { 238 if (mListeningUris.size() == 0) { 239 return; 240 } 241 mContentResolver.unregisterContentObserver(mObserver); 242 for (Uri uri : mListeningUris.keySet()) { 243 mContentResolver.registerContentObserver(uri, false, mObserver, mCurrentUser); 244 } 245 } 246 reloadSetting(Uri uri)247 private void reloadSetting(Uri uri) { 248 String key = mListeningUris.get(uri); 249 Set<Tunable> tunables = mTunableLookup.get(key); 250 if (tunables == null) { 251 return; 252 } 253 String value = Settings.Secure.getStringForUser(mContentResolver, key, mCurrentUser); 254 for (Tunable tunable : tunables) { 255 tunable.onTuningChanged(key, value); 256 } 257 } 258 reloadAll()259 private void reloadAll() { 260 for (String key : mTunableLookup.keySet()) { 261 String value = Settings.Secure.getStringForUser(mContentResolver, key, 262 mCurrentUser); 263 for (Tunable tunable : mTunableLookup.get(key)) { 264 tunable.onTuningChanged(key, value); 265 } 266 } 267 } 268 269 @Override clearAll()270 public void clearAll() { 271 clearAllFromUser(mCurrentUser); 272 } 273 clearAllFromUser(int user)274 public void clearAllFromUser(int user) { 275 // Turn off demo mode 276 mDemoModeController.requestFinishDemoMode(); 277 mDemoModeController.requestSetDemoModeAllowed(false); 278 279 // A couple special cases. 280 for (String key : mTunableLookup.keySet()) { 281 if (ArrayUtils.contains(RESET_EXCEPTION_LIST, key)) { 282 continue; 283 } 284 Settings.Secure.putStringForUser(mContentResolver, key, null, user); 285 } 286 } 287 288 289 @Override setTunerEnabled(boolean enabled)290 public void setTunerEnabled(boolean enabled) { 291 mUserTracker.getUserContext().getPackageManager().setComponentEnabledSetting( 292 mTunerComponent, 293 enabled ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED 294 : PackageManager.COMPONENT_ENABLED_STATE_DISABLED, 295 PackageManager.DONT_KILL_APP 296 ); 297 } 298 299 @Override 300 @WorkerThread isTunerEnabled()301 public boolean isTunerEnabled() { 302 return mUserTracker.getUserContext().getPackageManager().getComponentEnabledSetting( 303 mTunerComponent) == PackageManager.COMPONENT_ENABLED_STATE_ENABLED; 304 } 305 306 @Override showResetRequest(Runnable onDisabled)307 public void showResetRequest(Runnable onDisabled) { 308 SystemUIDialog dialog = mSystemUIDialogFactoryLazy.get().create(); 309 dialog.setShowForAllUsers(true); 310 dialog.setMessage(R.string.remove_from_settings_prompt); 311 dialog.setButton(DialogInterface.BUTTON_NEGATIVE, mContext.getString(R.string.cancel), 312 (DialogInterface.OnClickListener) null); 313 dialog.setButton(DialogInterface.BUTTON_POSITIVE, 314 mContext.getString(R.string.qs_customize_remove), (d, which) -> { 315 // Tell the tuner (in main SysUI process) to clear all its settings. 316 mContext.sendBroadcast(new Intent(TunerService.ACTION_CLEAR)); 317 // Disable access to tuner. 318 setTunerEnabled(false); 319 // Make them sit through the warning dialog again. 320 Secure.putInt(mContext.getContentResolver(), 321 TunerFragment.SETTING_SEEN_TUNER_WARNING, 0); 322 if (onDisabled != null) { 323 onDisabled.run(); 324 } 325 }); 326 dialog.show(); 327 } 328 329 private class Observer extends ContentObserver { Observer()330 public Observer() { 331 super(new Handler(Looper.getMainLooper())); 332 } 333 334 @Override onChange(boolean selfChange, java.util.Collection<Uri> uris, int flags, int userId)335 public void onChange(boolean selfChange, java.util.Collection<Uri> uris, 336 int flags, int userId) { 337 if (userId == mUserTracker.getUserId()) { 338 for (Uri u : uris) { 339 reloadSetting(u); 340 } 341 } 342 } 343 344 } 345 } 346