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