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