TunerServiceImpl.java revision 248c44b915c6c11b76d6387311ac63f208d6196b
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.ContentResolver;
20import android.content.Context;
21import android.content.Intent;
22import android.content.pm.UserInfo;
23import android.database.ContentObserver;
24import android.net.Uri;
25import android.os.Handler;
26import android.os.Looper;
27import android.os.UserManager;
28import android.provider.Settings;
29import android.provider.Settings.Secure;
30import android.text.TextUtils;
31import android.util.ArrayMap;
32import android.util.ArraySet;
33
34import com.android.internal.util.ArrayUtils;
35import com.android.systemui.DemoMode;
36import com.android.systemui.Dependency;
37import com.android.systemui.qs.QSTileHost;
38import com.android.systemui.settings.CurrentUserTracker;
39import com.android.systemui.statusbar.phone.StatusBarIconController;
40import com.android.systemui.util.leak.LeakDetector;
41
42import java.util.HashMap;
43import java.util.HashSet;
44import java.util.Set;
45
46
47public class TunerServiceImpl extends TunerService {
48
49    private static final String TUNER_VERSION = "sysui_tuner_version";
50
51    private static final int CURRENT_TUNER_VERSION = 4;
52
53    // Things that use the tunable infrastructure but are now real user settings and
54    // shouldn't be reset with tuner settings.
55    private static final String[] RESET_BLACKLIST = new String[] {
56            QSTileHost.TILES_SETTING,
57    };
58
59    private final Observer mObserver = new Observer();
60    // Map of Uris we listen on to their settings keys.
61    private final ArrayMap<Uri, String> mListeningUris = new ArrayMap<>();
62    // Map of settings keys to the listener.
63    private final HashMap<String, Set<Tunable>> mTunableLookup = new HashMap<>();
64    // Set of all tunables, used for leak detection.
65    private final HashSet<Tunable> mTunables = LeakDetector.ENABLED ? new HashSet<>() : null;
66    private final Context mContext;
67
68    private ContentResolver mContentResolver;
69    private int mCurrentUser;
70    private CurrentUserTracker mUserTracker;
71
72    public TunerServiceImpl(Context context) {
73        mContext = context;
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
83        mCurrentUser = ActivityManager.getCurrentUser();
84        mUserTracker = new CurrentUserTracker(mContext) {
85            @Override
86            public void onUserSwitched(int newUserId) {
87                mCurrentUser = newUserId;
88                reloadAll();
89                reregisterAll();
90            }
91        };
92        mUserTracker.startTracking();
93    }
94
95    @Override
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        if (oldVersion < 2) {
116            setTunerEnabled(mContext, false);
117        }
118        // 3 Removed because of a revert.
119        if (oldVersion < 4) {
120            // Delay this so that we can wait for everything to be registered first.
121            new Handler(Dependency.get(Dependency.BG_LOOPER)).postDelayed(() -> clearAll(), 5000);
122        }
123        setValue(TUNER_VERSION, newVersion);
124    }
125
126    @Override
127    public String getValue(String setting) {
128        return Settings.Secure.getStringForUser(mContentResolver, setting, mCurrentUser);
129    }
130
131    @Override
132    public void setValue(String setting, String value) {
133         Settings.Secure.putStringForUser(mContentResolver, setting, value, mCurrentUser);
134    }
135
136    @Override
137    public int getValue(String setting, int def) {
138        return Settings.Secure.getIntForUser(mContentResolver, setting, def, mCurrentUser);
139    }
140
141    @Override
142    public String getValue(String setting, String def) {
143        String ret = Secure.getStringForUser(mContentResolver, setting, mCurrentUser);
144        if (ret == null) return def;
145        return ret;
146    }
147
148    @Override
149    public void setValue(String setting, int value) {
150         Settings.Secure.putIntForUser(mContentResolver, setting, value, mCurrentUser);
151    }
152
153    @Override
154    public void addTunable(Tunable tunable, String... keys) {
155        for (String key : keys) {
156            addTunable(tunable, key);
157        }
158    }
159
160    private void addTunable(Tunable tunable, String key) {
161        if (!mTunableLookup.containsKey(key)) {
162            mTunableLookup.put(key, new ArraySet<Tunable>());
163        }
164        mTunableLookup.get(key).add(tunable);
165        if (LeakDetector.ENABLED) {
166            mTunables.add(tunable);
167            Dependency.get(LeakDetector.class).trackCollection(mTunables, "TunerService.mTunables");
168        }
169        Uri uri = Settings.Secure.getUriFor(key);
170        if (!mListeningUris.containsKey(uri)) {
171            mListeningUris.put(uri, key);
172            mContentResolver.registerContentObserver(uri, false, mObserver, mCurrentUser);
173        }
174        // Send the first state.
175        String value = Settings.Secure.getStringForUser(mContentResolver, key, mCurrentUser);
176        tunable.onTuningChanged(key, value);
177    }
178
179    @Override
180    public void removeTunable(Tunable tunable) {
181        for (Set<Tunable> list : mTunableLookup.values()) {
182            list.remove(tunable);
183        }
184        if (LeakDetector.ENABLED) {
185            mTunables.remove(tunable);
186        }
187    }
188
189    protected void reregisterAll() {
190        if (mListeningUris.size() == 0) {
191            return;
192        }
193        mContentResolver.unregisterContentObserver(mObserver);
194        for (Uri uri : mListeningUris.keySet()) {
195            mContentResolver.registerContentObserver(uri, false, mObserver, mCurrentUser);
196        }
197    }
198
199    private void reloadSetting(Uri uri) {
200        String key = mListeningUris.get(uri);
201        Set<Tunable> tunables = mTunableLookup.get(key);
202        if (tunables == null) {
203            return;
204        }
205        String value = Settings.Secure.getStringForUser(mContentResolver, key, mCurrentUser);
206        for (Tunable tunable : tunables) {
207            tunable.onTuningChanged(key, value);
208        }
209    }
210
211    private void reloadAll() {
212        for (String key : mTunableLookup.keySet()) {
213            String value = Settings.Secure.getStringForUser(mContentResolver, key,
214                    mCurrentUser);
215            for (Tunable tunable : mTunableLookup.get(key)) {
216                tunable.onTuningChanged(key, value);
217            }
218        }
219    }
220
221    @Override
222    public void clearAll() {
223        // A couple special cases.
224        Settings.Global.putString(mContentResolver, DemoMode.DEMO_MODE_ALLOWED, null);
225        Intent intent = new Intent(DemoMode.ACTION_DEMO);
226        intent.putExtra(DemoMode.EXTRA_COMMAND, DemoMode.COMMAND_EXIT);
227        mContext.sendBroadcast(intent);
228
229        for (String key : mTunableLookup.keySet()) {
230            if (ArrayUtils.contains(RESET_BLACKLIST, key)) {
231                continue;
232            }
233            Settings.Secure.putString(mContentResolver, key, null);
234        }
235    }
236
237    private class Observer extends ContentObserver {
238        public Observer() {
239            super(new Handler(Looper.getMainLooper()));
240        }
241
242        @Override
243        public void onChange(boolean selfChange, Uri uri, int userId) {
244            if (userId == ActivityManager.getCurrentUser()) {
245                reloadSetting(uri);
246            }
247        }
248    }
249}
250