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