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