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