blob: 9081af156f0006907761fc33ce7a4f98f5a93970 [file] [log] [blame]
Jason Monk5e745172015-06-02 19:14:44 -04001/*
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;
Jason Monk431ad732015-07-16 08:58:15 -040019import android.content.BroadcastReceiver;
20import android.content.ComponentName;
Jason Monk5e745172015-06-02 19:14:44 -040021import android.content.ContentResolver;
22import android.content.Context;
Jason Monk431ad732015-07-16 08:58:15 -040023import android.content.DialogInterface;
24import android.content.DialogInterface.OnClickListener;
25import android.content.Intent;
26import android.content.pm.PackageManager;
Jason Monk540542b2015-08-11 14:18:14 -040027import android.content.pm.PackageManager.NameNotFoundException;
Jason Monk5e745172015-06-02 19:14:44 -040028import android.database.ContentObserver;
29import android.net.Uri;
30import android.os.Handler;
31import android.os.Looper;
Jason Monk540542b2015-08-11 14:18:14 -040032import android.os.UserHandle;
Jason Monk5e745172015-06-02 19:14:44 -040033import android.provider.Settings;
34import android.util.ArrayMap;
35
Jason Monkabe19742015-09-29 09:47:06 -040036import com.android.systemui.BatteryMeterDrawable;
Jason Monk431ad732015-07-16 08:58:15 -040037import com.android.systemui.DemoMode;
38import com.android.systemui.R;
Jason Monk5e745172015-06-02 19:14:44 -040039import com.android.systemui.SystemUI;
40import com.android.systemui.SystemUIApplication;
41import com.android.systemui.settings.CurrentUserTracker;
Jason Monk431ad732015-07-16 08:58:15 -040042import com.android.systemui.statusbar.phone.SystemUIDialog;
Jason Monk5e745172015-06-02 19:14:44 -040043
44import java.util.ArrayList;
45import java.util.HashMap;
46import java.util.List;
47
48
49public class TunerService extends SystemUI {
50
Jason Monk431ad732015-07-16 08:58:15 -040051 public static final String ACTION_CLEAR = "com.android.systemui.action.CLEAR_TUNER";
52
Jason Monk5e745172015-06-02 19:14:44 -040053 private final Observer mObserver = new Observer();
54 // Map of Uris we listen on to their settings keys.
55 private final ArrayMap<Uri, String> mListeningUris = new ArrayMap<>();
56 // Map of settings keys to the listener.
57 private final HashMap<String, List<Tunable>> mTunableLookup = new HashMap<>();
58
59 private ContentResolver mContentResolver;
60 private int mCurrentUser;
61 private CurrentUserTracker mUserTracker;
62
63 @Override
64 public void start() {
65 mContentResolver = mContext.getContentResolver();
66 putComponent(TunerService.class, this);
67
68 mCurrentUser = ActivityManager.getCurrentUser();
69 mUserTracker = new CurrentUserTracker(mContext) {
70 @Override
71 public void onUserSwitched(int newUserId) {
72 mCurrentUser = newUserId;
73 reloadAll();
74 reregisterAll();
75 }
76 };
77 mUserTracker.startTracking();
78 }
79
80 public void addTunable(Tunable tunable, String... keys) {
81 for (String key : keys) {
82 addTunable(tunable, key);
83 }
84 }
85
86 private void addTunable(Tunable tunable, String key) {
87 if (!mTunableLookup.containsKey(key)) {
88 mTunableLookup.put(key, new ArrayList<Tunable>());
89 }
90 mTunableLookup.get(key).add(tunable);
91 Uri uri = Settings.Secure.getUriFor(key);
92 if (!mListeningUris.containsKey(uri)) {
93 mListeningUris.put(uri, key);
94 mContentResolver.registerContentObserver(uri, false, mObserver, mCurrentUser);
95 }
96 // Send the first state.
97 String value = Settings.Secure.getStringForUser(mContentResolver, key, mCurrentUser);
98 tunable.onTuningChanged(key, value);
99 }
100
101 public void removeTunable(Tunable tunable) {
102 for (List<Tunable> list : mTunableLookup.values()) {
103 list.remove(tunable);
104 }
105 }
106
107 protected void reregisterAll() {
108 if (mListeningUris.size() == 0) {
109 return;
110 }
111 mContentResolver.unregisterContentObserver(mObserver);
112 for (Uri uri : mListeningUris.keySet()) {
113 mContentResolver.registerContentObserver(uri, false, mObserver, mCurrentUser);
114 }
115 }
116
117 public void reloadSetting(Uri uri) {
118 String key = mListeningUris.get(uri);
Jason Monk72def0d2015-11-10 16:03:06 -0500119 List<Tunable> tunables = mTunableLookup.get(key);
120 if (tunables == null) {
121 return;
122 }
Jason Monk5e745172015-06-02 19:14:44 -0400123 String value = Settings.Secure.getStringForUser(mContentResolver, key, mCurrentUser);
Jason Monk72def0d2015-11-10 16:03:06 -0500124 for (Tunable tunable : tunables) {
Jason Monk5e745172015-06-02 19:14:44 -0400125 tunable.onTuningChanged(key, value);
126 }
127 }
128
129 private void reloadAll() {
130 for (String key : mTunableLookup.keySet()) {
131 String value = Settings.Secure.getStringForUser(mContentResolver, key,
132 mCurrentUser);
133 for (Tunable tunable : mTunableLookup.get(key)) {
134 tunable.onTuningChanged(key, value);
135 }
136 }
137 }
138
Jason Monk431ad732015-07-16 08:58:15 -0400139 public void clearAll() {
140 // A couple special cases.
141 Settings.Global.putString(mContentResolver, DemoMode.DEMO_MODE_ALLOWED, null);
Jason Monkabe19742015-09-29 09:47:06 -0400142 Settings.System.putString(mContentResolver, BatteryMeterDrawable.SHOW_PERCENT_SETTING, null);
Jason Monk431ad732015-07-16 08:58:15 -0400143 Intent intent = new Intent(DemoMode.ACTION_DEMO);
144 intent.putExtra(DemoMode.EXTRA_COMMAND, DemoMode.COMMAND_EXIT);
145 mContext.sendBroadcast(intent);
146
147 for (String key : mTunableLookup.keySet()) {
148 Settings.Secure.putString(mContentResolver, key, null);
149 }
150 }
151
Jason Monk5e745172015-06-02 19:14:44 -0400152 // Only used in other processes, such as the tuner.
153 private static TunerService sInstance;
154
155 public static TunerService get(Context context) {
Jason Monkd5a204f2015-12-21 08:50:01 -0500156 TunerService service = null;
157 if (context.getApplicationContext() instanceof SystemUIApplication) {
158 SystemUIApplication sysUi = (SystemUIApplication) context.getApplicationContext();
159 service = sysUi.getComponent(TunerService.class);
160 }
Jason Monk5e745172015-06-02 19:14:44 -0400161 if (service == null) {
162 // Can't get it as a component, must in the tuner, lets just create one for now.
163 return getStaticService(context);
164 }
165 return service;
166 }
167
168 private static TunerService getStaticService(Context context) {
169 if (sInstance == null) {
170 sInstance = new TunerService();
171 sInstance.mContext = context.getApplicationContext();
172 sInstance.mComponents = new HashMap<>();
173 sInstance.start();
174 }
175 return sInstance;
176 }
177
Jason Monk431ad732015-07-16 08:58:15 -0400178 public static final void showResetRequest(final Context context, final Runnable onDisabled) {
179 SystemUIDialog dialog = new SystemUIDialog(context);
Jason Monk540542b2015-08-11 14:18:14 -0400180 dialog.setShowForAllUsers(true);
Jason Monk431ad732015-07-16 08:58:15 -0400181 dialog.setMessage(R.string.remove_from_settings_prompt);
182 dialog.setButton(DialogInterface.BUTTON_NEGATIVE, context.getString(R.string.cancel),
183 (OnClickListener) null);
184 dialog.setButton(DialogInterface.BUTTON_POSITIVE,
185 context.getString(R.string.guest_exit_guest_dialog_remove), new OnClickListener() {
186 @Override
187 public void onClick(DialogInterface dialog, int which) {
188 // Tell the tuner (in main SysUI process) to clear all its settings.
189 context.sendBroadcast(new Intent(TunerService.ACTION_CLEAR));
190 // Disable access to tuner.
191 TunerService.setTunerEnabled(context, false);
192 // Make them sit through the warning dialog again.
193 Settings.Secure.putInt(context.getContentResolver(),
194 TunerFragment.SETTING_SEEN_TUNER_WARNING, 0);
195 if (onDisabled != null) {
196 onDisabled.run();
197 }
198 }
199 });
200 dialog.show();
201 }
202
203 public static final void setTunerEnabled(Context context, boolean enabled) {
Jason Monk540542b2015-08-11 14:18:14 -0400204 userContext(context).getPackageManager().setComponentEnabledSetting(
Jason Monk431ad732015-07-16 08:58:15 -0400205 new ComponentName(context, TunerActivity.class),
206 enabled ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED
207 : PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
208 PackageManager.DONT_KILL_APP);
209 }
210
211 public static final boolean isTunerEnabled(Context context) {
Jason Monk540542b2015-08-11 14:18:14 -0400212 return userContext(context).getPackageManager().getComponentEnabledSetting(
Jason Monk431ad732015-07-16 08:58:15 -0400213 new ComponentName(context, TunerActivity.class))
214 == PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
215 }
216
Jason Monk540542b2015-08-11 14:18:14 -0400217 private static Context userContext(Context context) {
218 try {
219 return context.createPackageContextAsUser(context.getPackageName(), 0,
220 new UserHandle(ActivityManager.getCurrentUser()));
221 } catch (NameNotFoundException e) {
222 return context;
223 }
224 }
225
Jason Monk5e745172015-06-02 19:14:44 -0400226 private class Observer extends ContentObserver {
227 public Observer() {
228 super(new Handler(Looper.getMainLooper()));
229 }
230
231 @Override
232 public void onChange(boolean selfChange, Uri uri, int userId) {
233 if (userId == ActivityManager.getCurrentUser()) {
234 reloadSetting(uri);
235 }
236 }
237 }
238
239 public interface Tunable {
240 void onTuningChanged(String key, String newValue);
241 }
Jason Monk431ad732015-07-16 08:58:15 -0400242
243 public static class ClearReceiver extends BroadcastReceiver {
244 @Override
245 public void onReceive(Context context, Intent intent) {
246 if (ACTION_CLEAR.equals(intent.getAction())) {
247 get(context).clearAll();
248 }
249 }
250 }
Jason Monk5e745172015-06-02 19:14:44 -0400251}