TunerService.java revision 38b4725108d25928b2df7966a08d9369828d1e14
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 */
16package com.android.systemui.tuner;
17
18import android.app.ActivityManager;
19import android.content.BroadcastReceiver;
20import android.content.ComponentName;
21import android.content.ContentResolver;
22import android.content.Context;
23import android.content.DialogInterface;
24import android.content.DialogInterface.OnClickListener;
25import android.content.Intent;
26import android.content.pm.PackageManager;
27import android.content.pm.PackageManager.NameNotFoundException;
28import android.content.pm.UserInfo;
29import android.database.ContentObserver;
30import android.net.Uri;
31import android.os.Handler;
32import android.os.Looper;
33import android.os.UserHandle;
34import android.os.UserManager;
35import android.provider.Settings;
36import android.text.TextUtils;
37import android.util.ArrayMap;
38import android.util.ArraySet;
39
40import com.android.systemui.BatteryMeterDrawable;
41import com.android.systemui.DemoMode;
42import com.android.systemui.R;
43import com.android.systemui.SystemUI;
44import com.android.systemui.SystemUIApplication;
45import com.android.systemui.settings.CurrentUserTracker;
46import com.android.systemui.statusbar.phone.StatusBarIconController;
47import com.android.systemui.statusbar.phone.SystemUIDialog;
48
49import java.util.HashMap;
50import java.util.Set;
51
52
53public class TunerService extends SystemUI {
54
55    public static final String ACTION_CLEAR = "com.android.systemui.action.CLEAR_TUNER";
56
57    private static final String TUNER_VERSION = "sysui_tuner_version";
58
59    private static final int CURRENT_TUNER_VERSION = 1;
60
61    private final Observer mObserver = new Observer();
62    // Map of Uris we listen on to their settings keys.
63    private final ArrayMap<Uri, String> mListeningUris = new ArrayMap<>();
64    // Map of settings keys to the listener.
65    private final HashMap<String, Set<Tunable>> mTunableLookup = new HashMap<>();
66
67    private ContentResolver mContentResolver;
68    private int mCurrentUser;
69    private CurrentUserTracker mUserTracker;
70
71    @Override
72    public void start() {
73        mContentResolver = mContext.getContentResolver();
74
75        for (UserInfo user : UserManager.get(mContext).getUsers()) {
76            mCurrentUser = user.getUserHandle().getIdentifier();
77            if (getValue(TUNER_VERSION, 0) != CURRENT_TUNER_VERSION) {
78                upgradeTuner(getValue(TUNER_VERSION, 0), CURRENT_TUNER_VERSION);
79            }
80        }
81        putComponent(TunerService.class, this);
82
83        mCurrentUser = ActivityManager.getCurrentUser();
84        mUserTracker = new CurrentUserTracker(mContext) {
85            @Override
86            public void onUserSwitched(int newUserId) {
87                mCurrentUser = newUserId;
88                reloadAll();
89                reregisterAll();
90            }
91        };
92        mUserTracker.startTracking();
93    }
94
95    private void upgradeTuner(int oldVersion, int newVersion) {
96        if (oldVersion < 1) {
97            String blacklistStr = getValue(StatusBarIconController.ICON_BLACKLIST);
98            if (blacklistStr != null) {
99                ArraySet<String> iconBlacklist =
100                        StatusBarIconController.getIconBlacklist(blacklistStr);
101
102                iconBlacklist.add("rotate");
103                iconBlacklist.add("headset");
104
105                Settings.Secure.putStringForUser(mContentResolver,
106                        StatusBarIconController.ICON_BLACKLIST,
107                        TextUtils.join(",", iconBlacklist), mCurrentUser);
108            }
109        }
110        setValue(TUNER_VERSION, newVersion);
111    }
112
113    public String getValue(String setting) {
114        return Settings.Secure.getStringForUser(mContentResolver, setting, mCurrentUser);
115    }
116
117    public void setValue(String setting, String value) {
118         Settings.Secure.putStringForUser(mContentResolver, setting, value, mCurrentUser);
119    }
120
121    public int getValue(String setting, int def) {
122        return Settings.Secure.getIntForUser(mContentResolver, setting, def, mCurrentUser);
123    }
124
125    public void setValue(String setting, int value) {
126         Settings.Secure.putIntForUser(mContentResolver, setting, value, mCurrentUser);
127    }
128
129    public void addTunable(Tunable tunable, String... keys) {
130        for (String key : keys) {
131            addTunable(tunable, key);
132        }
133    }
134
135    private void addTunable(Tunable tunable, String key) {
136        if (!mTunableLookup.containsKey(key)) {
137            mTunableLookup.put(key, new ArraySet<Tunable>());
138        }
139        mTunableLookup.get(key).add(tunable);
140        Uri uri = Settings.Secure.getUriFor(key);
141        if (!mListeningUris.containsKey(uri)) {
142            mListeningUris.put(uri, key);
143            mContentResolver.registerContentObserver(uri, false, mObserver, mCurrentUser);
144        }
145        // Send the first state.
146        String value = Settings.Secure.getStringForUser(mContentResolver, key, mCurrentUser);
147        tunable.onTuningChanged(key, value);
148    }
149
150    public void removeTunable(Tunable tunable) {
151        for (Set<Tunable> list : mTunableLookup.values()) {
152            list.remove(tunable);
153        }
154    }
155
156    protected void reregisterAll() {
157        if (mListeningUris.size() == 0) {
158            return;
159        }
160        mContentResolver.unregisterContentObserver(mObserver);
161        for (Uri uri : mListeningUris.keySet()) {
162            mContentResolver.registerContentObserver(uri, false, mObserver, mCurrentUser);
163        }
164    }
165
166    public void reloadSetting(Uri uri) {
167        String key = mListeningUris.get(uri);
168        Set<Tunable> tunables = mTunableLookup.get(key);
169        if (tunables == null) {
170            return;
171        }
172        String value = Settings.Secure.getStringForUser(mContentResolver, key, mCurrentUser);
173        for (Tunable tunable : tunables) {
174            tunable.onTuningChanged(key, value);
175        }
176    }
177
178    private void reloadAll() {
179        for (String key : mTunableLookup.keySet()) {
180            String value = Settings.Secure.getStringForUser(mContentResolver, key,
181                    mCurrentUser);
182            for (Tunable tunable : mTunableLookup.get(key)) {
183                tunable.onTuningChanged(key, value);
184            }
185        }
186    }
187
188    public void clearAll() {
189        // A couple special cases.
190        Settings.Global.putString(mContentResolver, DemoMode.DEMO_MODE_ALLOWED, null);
191        Settings.System.putString(mContentResolver, BatteryMeterDrawable.SHOW_PERCENT_SETTING, null);
192        Intent intent = new Intent(DemoMode.ACTION_DEMO);
193        intent.putExtra(DemoMode.EXTRA_COMMAND, DemoMode.COMMAND_EXIT);
194        mContext.sendBroadcast(intent);
195
196        for (String key : mTunableLookup.keySet()) {
197            Settings.Secure.putString(mContentResolver, key, null);
198        }
199    }
200
201    // Only used in other processes, such as the tuner.
202    private static TunerService sInstance;
203
204    public static TunerService get(Context context) {
205        TunerService service = null;
206        if (context.getApplicationContext() instanceof SystemUIApplication) {
207            SystemUIApplication sysUi = (SystemUIApplication) context.getApplicationContext();
208            service = sysUi.getComponent(TunerService.class);
209        }
210        if (service == null) {
211            // Can't get it as a component, must in the tuner, lets just create one for now.
212            return getStaticService(context);
213        }
214        return service;
215    }
216
217    private static TunerService getStaticService(Context context) {
218        if (sInstance == null) {
219            sInstance = new TunerService();
220            sInstance.mContext = context.getApplicationContext();
221            sInstance.mComponents = new HashMap<>();
222            sInstance.start();
223        }
224        return sInstance;
225    }
226
227    public static final void showResetRequest(final Context context, final Runnable onDisabled) {
228        SystemUIDialog dialog = new SystemUIDialog(context);
229        dialog.setShowForAllUsers(true);
230        dialog.setMessage(R.string.remove_from_settings_prompt);
231        dialog.setButton(DialogInterface.BUTTON_NEGATIVE, context.getString(R.string.cancel),
232                (OnClickListener) null);
233        dialog.setButton(DialogInterface.BUTTON_POSITIVE,
234                context.getString(R.string.guest_exit_guest_dialog_remove), new OnClickListener() {
235            @Override
236            public void onClick(DialogInterface dialog, int which) {
237                // Tell the tuner (in main SysUI process) to clear all its settings.
238                context.sendBroadcast(new Intent(TunerService.ACTION_CLEAR));
239                // Disable access to tuner.
240                TunerService.setTunerEnabled(context, false);
241                // Make them sit through the warning dialog again.
242                Settings.Secure.putInt(context.getContentResolver(),
243                        TunerFragment.SETTING_SEEN_TUNER_WARNING, 0);
244                if (onDisabled != null) {
245                    onDisabled.run();
246                }
247            }
248        });
249        dialog.show();
250    }
251
252    public static final void setTunerEnabled(Context context, boolean enabled) {
253        userContext(context).getPackageManager().setComponentEnabledSetting(
254                new ComponentName(context, TunerActivity.class),
255                enabled ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED
256                        : PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
257                        PackageManager.DONT_KILL_APP);
258
259        userContext(context).getPackageManager().setComponentEnabledSetting(
260                new ComponentName(context, TunerActivity.ACTIVITY_ALIAS_NAME),
261                enabled ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED
262                        : PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
263                PackageManager.DONT_KILL_APP);
264    }
265
266    public static final boolean isTunerEnabled(Context context) {
267        return userContext(context).getPackageManager().getComponentEnabledSetting(
268                new ComponentName(context, TunerActivity.class))
269                == PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
270    }
271
272    private static Context userContext(Context context) {
273        try {
274            return context.createPackageContextAsUser(context.getPackageName(), 0,
275                    new UserHandle(ActivityManager.getCurrentUser()));
276        } catch (NameNotFoundException e) {
277            return context;
278        }
279    }
280
281    private class Observer extends ContentObserver {
282        public Observer() {
283            super(new Handler(Looper.getMainLooper()));
284        }
285
286        @Override
287        public void onChange(boolean selfChange, Uri uri, int userId) {
288            if (userId == ActivityManager.getCurrentUser()) {
289                reloadSetting(uri);
290            }
291        }
292    }
293
294    public interface Tunable {
295        void onTuningChanged(String key, String newValue);
296    }
297
298    public static class ClearReceiver extends BroadcastReceiver {
299        @Override
300        public void onReceive(Context context, Intent intent) {
301            if (ACTION_CLEAR.equals(intent.getAction())) {
302                get(context).clearAll();
303            }
304        }
305    }
306}
307