Setup service for tunable things to use.

Change-Id: I13daa68d3d1ec5584fd84f356f4f5a0d1c0b853a
This commit is contained in:
Jason Monk
2015-06-02 19:14:44 -04:00
parent 683e3cfef1
commit 5e745172d9
9 changed files with 307 additions and 134 deletions

View File

@@ -40,13 +40,14 @@ public class SystemUIApplication extends Application {
* The classes of the stuff to start.
*/
private final Class<?>[] SERVICES = new Class[] {
com.android.systemui.tuner.TunerService.class,
com.android.systemui.keyguard.KeyguardViewMediator.class,
com.android.systemui.recents.Recents.class,
com.android.systemui.volume.VolumeUI.class,
com.android.systemui.statusbar.SystemBars.class,
com.android.systemui.usb.StorageNotification.class,
com.android.systemui.power.PowerUI.class,
com.android.systemui.media.RingtonePlayer.class
com.android.systemui.media.RingtonePlayer.class,
};
/**

View File

@@ -18,14 +18,12 @@ package com.android.systemui.statusbar;
import android.content.Context;
import android.content.res.ColorStateList;
import android.database.ContentObserver;
import android.graphics.Color;
import android.graphics.PorterDuff;
import android.graphics.drawable.Animatable;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.provider.Settings;
import android.telephony.SubscriptionInfo;
import android.util.ArraySet;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
@@ -40,6 +38,8 @@ import com.android.systemui.statusbar.phone.StatusBarIconController;
import com.android.systemui.statusbar.policy.NetworkController.IconState;
import com.android.systemui.statusbar.policy.NetworkControllerImpl;
import com.android.systemui.statusbar.policy.SecurityController;
import com.android.systemui.tuner.TunerService;
import com.android.systemui.tuner.TunerService.Tunable;
import java.util.ArrayList;
import java.util.List;
@@ -48,7 +48,7 @@ import java.util.List;
public class SignalClusterView
extends LinearLayout
implements NetworkControllerImpl.SignalCallback,
SecurityController.SecurityControllerCallback {
SecurityController.SecurityControllerCallback, Tunable {
static final String TAG = "SignalClusterView";
static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
@@ -105,14 +105,22 @@ public class SignalClusterView
public SignalClusterView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
readBlacklist();
}
private void readBlacklist() {
mBlockAirplane = StatusBarIconController.isBlocked(getContext(), SLOT_AIRPLANE);
mBlockMobile = StatusBarIconController.isBlocked(getContext(), SLOT_MOBILE);
mBlockWifi = StatusBarIconController.isBlocked(getContext(), SLOT_WIFI);
mBlockEthernet = StatusBarIconController.isBlocked(getContext(), SLOT_ETHERNET);
@Override
public void onTuningChanged(String key, String newValue) {
if (!StatusBarIconController.ICON_BLACKLIST.equals(key)) {
return;
}
ArraySet<String> blockList = StatusBarIconController.getIconBlacklist(newValue);
mBlockAirplane = blockList.contains(SLOT_AIRPLANE);
mBlockMobile = blockList.contains(SLOT_MOBILE);
mBlockWifi = blockList.contains(SLOT_WIFI);
mBlockEthernet = blockList.contains(SLOT_ETHERNET);
// Re-register to get new callbacks.
mNC.removeSignalCallback(SignalClusterView.this);
mNC.addSignalCallback(SignalClusterView.this);
}
public void setNetworkController(NetworkControllerImpl nc) {
@@ -160,12 +168,10 @@ public class SignalClusterView
for (PhoneState state : mPhoneStates) {
mMobileSignalGroup.addView(state.mMobileGroup);
}
TunerService.get(mContext).addTunable(this, StatusBarIconController.ICON_BLACKLIST);
apply();
applyIconTint();
getContext().getContentResolver().registerContentObserver(
Settings.Secure.getUriFor(StatusBarIconController.ICON_BLACKLIST), false,
mBlacklistObserver);
}
@Override
@@ -178,7 +184,7 @@ public class SignalClusterView
mAirplane = null;
mMobileSignalGroup.removeAllViews();
mMobileSignalGroup = null;
getContext().getContentResolver().unregisterContentObserver(mBlacklistObserver);
TunerService.get(mContext).removeTunable(this);
super.onDetachedFromWindow();
}
@@ -528,14 +534,5 @@ public class SignalClusterView
setTint(mMobileType, tint);
}
}
private final ContentObserver mBlacklistObserver = new ContentObserver(new Handler()) {
public void onChange(boolean selfChange) {
readBlacklist();
// Re-register to get new callbacks.
mNC.removeSignalCallback(SignalClusterView.this);
mNC.addSignalCallback(SignalClusterView.this);
};
};
}

View File

@@ -3166,9 +3166,12 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
(SignalClusterView) mKeyguardStatusBar.findViewById(R.id.signal_cluster);
final SignalClusterView signalClusterQs =
(SignalClusterView) mHeader.findViewById(R.id.signal_cluster);
mNetworkController.addSignalCallback(signalCluster);
mNetworkController.addSignalCallback(signalClusterKeyguard);
mNetworkController.addSignalCallback(signalClusterQs);
mNetworkController.removeSignalCallback(signalCluster);
mNetworkController.removeSignalCallback(signalClusterKeyguard);
mNetworkController.removeSignalCallback(signalClusterQs);
if (mQSPanel != null && mQSPanel.getHost() != null) {
mQSPanel.getHost().destroy();
}
}
private boolean mDemoModeAllowed;

View File

@@ -19,13 +19,9 @@ package com.android.systemui.statusbar.phone;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
import android.database.ContentObserver;
import android.net.Uri;
import android.os.Process;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.provider.Settings.Secure;
import android.os.Process;
import android.util.Log;
import com.android.systemui.R;
@@ -35,25 +31,26 @@ import com.android.systemui.qs.tiles.BluetoothTile;
import com.android.systemui.qs.tiles.CastTile;
import com.android.systemui.qs.tiles.CellularTile;
import com.android.systemui.qs.tiles.ColorInversionTile;
import com.android.systemui.qs.tiles.DndTile;
import com.android.systemui.qs.tiles.FlashlightTile;
import com.android.systemui.qs.tiles.HotspotTile;
import com.android.systemui.qs.tiles.IntentTile;
import com.android.systemui.qs.tiles.LocationTile;
import com.android.systemui.qs.tiles.RotationLockTile;
import com.android.systemui.qs.tiles.WifiTile;
import com.android.systemui.qs.tiles.DndTile;
import com.android.systemui.settings.CurrentUserTracker;
import com.android.systemui.statusbar.policy.BluetoothController;
import com.android.systemui.statusbar.policy.CastController;
import com.android.systemui.statusbar.policy.FlashlightController;
import com.android.systemui.statusbar.policy.HotspotController;
import com.android.systemui.statusbar.policy.KeyguardMonitor;
import com.android.systemui.statusbar.policy.LocationController;
import com.android.systemui.statusbar.policy.NetworkController;
import com.android.systemui.statusbar.policy.RotationLockController;
import com.android.systemui.statusbar.policy.HotspotController;
import com.android.systemui.statusbar.policy.SecurityController;
import com.android.systemui.statusbar.policy.UserSwitcherController;
import com.android.systemui.statusbar.policy.ZenModeController;
import com.android.systemui.tuner.TunerService;
import com.android.systemui.tuner.TunerService.Tunable;
import java.util.ArrayList;
import java.util.Arrays;
@@ -63,7 +60,7 @@ import java.util.List;
import java.util.Map;
/** Platform implementation of the quick settings tile host **/
public class QSTileHost implements QSTile.Host {
public class QSTileHost implements QSTile.Host, Tunable {
private static final String TAG = "QSTileHost";
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
@@ -72,8 +69,7 @@ public class QSTileHost implements QSTile.Host {
private final Context mContext;
private final PhoneStatusBar mStatusBar;
private final LinkedHashMap<String, QSTile<?>> mTiles = new LinkedHashMap<>();
private final ArrayList<String> mTileSpecs = new ArrayList<>();
private final Observer mObserver = new Observer();
protected final ArrayList<String> mTileSpecs = new ArrayList<>();
private final BluetoothController mBluetooth;
private final LocationController mLocation;
private final RotationLockController mRotation;
@@ -82,7 +78,6 @@ public class QSTileHost implements QSTile.Host {
private final HotspotController mHotspot;
private final CastController mCast;
private final Looper mLooper;
protected final CurrentUserTracker mUserTracker;
private final FlashlightController mFlashlight;
private final UserSwitcherController mUserSwitcherController;
private final KeyguardMonitor mKeyguard;
@@ -116,22 +111,11 @@ public class QSTileHost implements QSTile.Host {
ht.start();
mLooper = ht.getLooper();
mUserTracker = new CurrentUserTracker(mContext) {
@Override
public void onUserSwitched(int newUserId) {
recreateTiles();
for (QSTile<?> tile : mTiles.values()) {
tile.userSwitch(newUserId);
}
mSecurity.onUserSwitched(newUserId);
mNetwork.onUserSwitched(newUserId);
mObserver.register();
}
};
recreateTiles();
TunerService.get(mContext).addTunable(this, TILES_SETTING);
}
mUserTracker.startTracking();
mObserver.register();
public void destroy() {
TunerService.get(mContext).removeTunable(this);
}
@Override
@@ -221,10 +205,14 @@ public class QSTileHost implements QSTile.Host {
public SecurityController getSecurityController() {
return mSecurity;
}
private void recreateTiles() {
@Override
public void onTuningChanged(String key, String newValue) {
if (!TILES_SETTING.equals(key)) {
return;
}
if (DEBUG) Log.d(TAG, "Recreating tiles");
final List<String> tileSpecs = loadTileSpecs();
final List<String> tileSpecs = loadTileSpecs(newValue);
if (tileSpecs.equals(mTileSpecs)) return;
for (Map.Entry<String, QSTile<?>> tile : mTiles.entrySet()) {
if (!tileSpecs.contains(tile.getKey())) {
@@ -270,11 +258,9 @@ public class QSTileHost implements QSTile.Host {
else throw new IllegalArgumentException("Bad tile spec: " + tileSpec);
}
protected List<String> loadTileSpecs() {
protected List<String> loadTileSpecs(String tileList) {
final Resources res = mContext.getResources();
final String defaultTileList = res.getString(R.string.quick_settings_tiles_default);
String tileList = Secure.getStringForUser(mContext.getContentResolver(), TILES_SETTING,
mUserTracker.getCurrentUserId());
if (tileList == null) {
tileList = res.getString(R.string.quick_settings_tiles);
if (DEBUG) Log.d(TAG, "Loaded tile specs from config: " + tileList);
@@ -297,26 +283,4 @@ public class QSTileHost implements QSTile.Host {
}
return tiles;
}
private class Observer extends ContentObserver {
private boolean mRegistered;
public Observer() {
super(new Handler(Looper.getMainLooper()));
}
public void register() {
if (mRegistered) {
mContext.getContentResolver().unregisterContentObserver(this);
}
mContext.getContentResolver().registerContentObserver(Secure.getUriFor(TILES_SETTING),
false, this, mUserTracker.getCurrentUserId());
mRegistered = true;
}
@Override
public void onChange(boolean selfChange, Uri uri) {
recreateTiles();
}
}
}

View File

@@ -20,12 +20,10 @@ import android.animation.ArgbEvaluator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.ColorStateList;
import android.database.ContentObserver;
import android.graphics.Color;
import android.os.Bundle;
import android.os.Handler;
import android.os.SystemClock;
import android.provider.Settings;
import android.text.TextUtils;
import android.util.ArraySet;
import android.view.View;
@@ -44,6 +42,8 @@ import com.android.systemui.R;
import com.android.systemui.statusbar.NotificationData;
import com.android.systemui.statusbar.SignalClusterView;
import com.android.systemui.statusbar.StatusBarIconView;
import com.android.systemui.tuner.TunerService;
import com.android.systemui.tuner.TunerService.Tunable;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -53,7 +53,7 @@ import java.util.ArrayList;
* limited to: notification icons, signal cluster, additional status icons, and clock in the status
* bar.
*/
public class StatusBarIconController {
public class StatusBarIconController implements Tunable {
public static final long DEFAULT_TINT_ANIMATION_DURATION = 120;
@@ -95,7 +95,7 @@ public class StatusBarIconController {
private long mTransitionDeferringStartTime;
private long mTransitionDeferringDuration;
private final ArraySet<String> mIconBlacklist;
private final ArraySet<String> mIconBlacklist = new ArraySet<>();
private final Runnable mTransitionDeferringDoneRunnable = new Runnable() {
@Override
@@ -126,14 +126,33 @@ public class StatusBarIconController {
mDarkModeIconColorSingleTone = context.getColor(R.color.dark_mode_icon_color_single_tone);
mLightModeIconColorSingleTone = context.getColor(R.color.light_mode_icon_color_single_tone);
mHandler = new Handler();
mIconBlacklist = getIconBlacklist(context);
updateResources();
context.getContentResolver().registerContentObserver(
Settings.Secure.getUriFor(StatusBarIconController.ICON_BLACKLIST), false,
mBlacklistObserver);
TunerService.get(mContext).addTunable(this, ICON_BLACKLIST);
}
@Override
public void onTuningChanged(String key, String newValue) {
if (!ICON_BLACKLIST.equals(key)) {
return;
}
mIconBlacklist.clear();
mIconBlacklist.addAll(getIconBlacklist(newValue));
ArrayList<StatusBarIconView> views = new ArrayList<StatusBarIconView>();
// Get all the current views.
for (int i = 0; i < mStatusIcons.getChildCount(); i++) {
views.add((StatusBarIconView) mStatusIcons.getChildAt(i));
}
// Remove all the icons.
for (int i = views.size() - 1; i >= 0; i--) {
removeSystemIcon(views.get(i).getSlot(), i, i);
}
// Add them all back
for (int i = 0; i < views.size(); i++) {
addSystemIcon(views.get(i).getSlot(), i, i, views.get(i).getStatusBarIcon());
}
};
public void updateResources() {
mIconSize = mContext.getResources().getDimensionPixelSize(
com.android.internal.R.dimen.status_bar_icon_size);
@@ -429,29 +448,7 @@ public class StatusBarIconController {
mTransitionPending = false;
}
private final ContentObserver mBlacklistObserver = new ContentObserver(new Handler()) {
public void onChange(boolean selfChange) {
mIconBlacklist.clear();
mIconBlacklist.addAll(getIconBlacklist(mContext));
ArrayList<StatusBarIconView> views = new ArrayList<StatusBarIconView>();
// Get all the current views.
for (int i = 0; i < mStatusIcons.getChildCount(); i++) {
views.add((StatusBarIconView) mStatusIcons.getChildAt(i));
}
// Remove all the icons.
for (int i = views.size() - 1; i >= 0; i--) {
removeSystemIcon(views.get(i).getSlot(), i, i);
}
// Add them all back
for (int i = 0; i < views.size(); i++) {
addSystemIcon(views.get(i).getSlot(), i, i, views.get(i).getStatusBarIcon());
}
}
};
public static ArraySet<String> getIconBlacklist(Context context) {
String blackListStr = Settings.Secure.getString(context.getContentResolver(),
ICON_BLACKLIST);
public static ArraySet<String> getIconBlacklist(String blackListStr) {
ArraySet<String> ret = new ArraySet<String>();
if (blackListStr != null) {
String[] blacklist = blackListStr.split(",");
@@ -463,8 +460,4 @@ public class StatusBarIconController {
}
return ret;
}
public static boolean isBlocked(Context context, String slot) {
return getIconBlacklist(context).contains(slot);
}
}

View File

@@ -15,6 +15,7 @@
*/
package com.android.systemui.tuner;
import android.app.ActivityManager;
import android.app.AlertDialog;
import android.app.Fragment;
import android.content.ClipData;
@@ -49,6 +50,7 @@ import com.android.systemui.qs.tiles.IntentTile;
import com.android.systemui.statusbar.phone.QSTileHost;
import com.android.systemui.statusbar.policy.SecurityController;
import java.util.ArrayList;
import java.util.List;
public class QsTuner extends Fragment implements Callback {
@@ -107,6 +109,12 @@ public class QsTuner extends Fragment implements Callback {
return mScrollRoot;
}
@Override
public void onDestroyView() {
mTileHost.destroy();
super.onDestroyView();
}
private void setupDropTarget() {
QSTileView tileView = new QSTileView(getContext());
QSTile.State state = new QSTile.State();
@@ -187,7 +195,7 @@ public class QsTuner extends Fragment implements Callback {
if (oldTile.equals(newTile)) {
return;
}
List<String> order = loadTileSpecs();
List<String> order = new ArrayList<>(mTileSpecs);
int index = order.indexOf(oldTile);
if (index < 0) {
Log.e(TAG, "Can't find " + oldTile);
@@ -199,32 +207,33 @@ public class QsTuner extends Fragment implements Callback {
}
public void remove(String tile) {
List<String> tiles = loadTileSpecs();
List<String> tiles = new ArrayList<>(mTileSpecs);
tiles.remove(tile);
setTiles(tiles);
}
public void add(String tile) {
List<String> tiles = loadTileSpecs();
List<String> tiles = new ArrayList<>(mTileSpecs);
tiles.add(tile);
setTiles(tiles);
}
public void reset() {
Secure.putStringForUser(getContext().getContentResolver(),
TILES_SETTING, "default", mUserTracker.getCurrentUserId());
TILES_SETTING, "default", ActivityManager.getCurrentUser());
}
private void setTiles(List<String> tiles) {
Secure.putStringForUser(getContext().getContentResolver(), TILES_SETTING,
TextUtils.join(",", tiles), mUserTracker.getCurrentUserId());
TextUtils.join(",", tiles), ActivityManager.getCurrentUser());
}
public void showAddDialog() {
List<String> tiles = loadTileSpecs();
List<String> tiles = mTileSpecs;
String[] defaults =
getContext().getString(R.string.quick_settings_tiles_default).split(",");
final String[] available = new String[defaults.length + 1 - tiles.size()];
final String[] availableTiles = new String[available.length];
int index = 0;
for (int i = 0; i < defaults.length; i++) {
if (tiles.contains(defaults[i])) {
@@ -232,8 +241,10 @@ public class QsTuner extends Fragment implements Callback {
}
int resource = getLabelResource(defaults[i]);
if (resource != 0) {
availableTiles[index] = defaults[i];
available[index++] = getContext().getString(resource);
} else {
availableTiles[index] = defaults[i];
available[index++] = defaults[i];
}
}
@@ -243,7 +254,7 @@ public class QsTuner extends Fragment implements Callback {
.setItems(available, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
if (which < available.length - 1) {
add(available[which]);
add(availableTiles[which]);
} else {
showBroadcastTileDialog();
}

View File

@@ -15,6 +15,7 @@
*/
package com.android.systemui.tuner;
import android.app.ActivityManager;
import android.content.ContentResolver;
import android.content.Context;
import android.preference.SwitchPreference;
@@ -23,28 +24,38 @@ import android.text.TextUtils;
import android.util.AttributeSet;
import com.android.systemui.statusbar.phone.StatusBarIconController;
import com.android.systemui.tuner.TunerService.Tunable;
import java.util.Set;
public class StatusBarSwitch extends SwitchPreference {
public class StatusBarSwitch extends SwitchPreference implements Tunable {
private Set<String> mBlacklist;
public StatusBarSwitch(Context context, AttributeSet attrs) {
super(context, attrs);
setChecked(!StatusBarIconController.isBlocked(getContext(), getKey()));
}
@Override
public void onTuningChanged(String key, String newValue) {
if (!StatusBarIconController.ICON_BLACKLIST.equals(key)) {
return;
}
mBlacklist = StatusBarIconController.getIconBlacklist(newValue);
setChecked(!mBlacklist.contains(getKey()));
}
@Override
protected boolean persistBoolean(boolean value) {
Set<String> blacklist = StatusBarIconController.getIconBlacklist(getContext());
if (!value) {
// If not enabled add to blacklist.
if (!blacklist.contains(getKey())) {
blacklist.add(getKey());
setList(blacklist);
if (!mBlacklist.contains(getKey())) {
mBlacklist.add(getKey());
setList(mBlacklist);
}
} else {
if (blacklist != null && blacklist.remove(getKey())) {
setList(blacklist);
if (mBlacklist.remove(getKey())) {
setList(mBlacklist);
}
}
return true;
@@ -52,7 +63,7 @@ public class StatusBarSwitch extends SwitchPreference {
private void setList(Set<String> blacklist) {
ContentResolver contentResolver = getContext().getContentResolver();
Settings.Secure.putString(contentResolver, StatusBarIconController.ICON_BLACKLIST,
TextUtils.join(",", blacklist));
Settings.Secure.putStringForUser(contentResolver, StatusBarIconController.ICON_BLACKLIST,
TextUtils.join(",", blacklist), ActivityManager.getCurrentUser());
}
}

View File

@@ -26,11 +26,14 @@ import android.preference.Preference;
import android.preference.Preference.OnPreferenceChangeListener;
import android.preference.Preference.OnPreferenceClickListener;
import android.preference.PreferenceFragment;
import android.preference.PreferenceGroup;
import android.preference.SwitchPreference;
import android.provider.Settings.System;
import android.view.MenuItem;
import com.android.systemui.R;
import com.android.systemui.statusbar.phone.StatusBarIconController;
import com.android.systemui.tuner.TunerService.Tunable;
public class TunerFragment extends PreferenceFragment {
@@ -67,12 +70,42 @@ public class TunerFragment extends PreferenceFragment {
updateBatteryPct();
getContext().getContentResolver().registerContentObserver(
System.getUriFor(SHOW_PERCENT_SETTING), false, mSettingObserver);
registerPrefs(getPreferenceScreen());
}
@Override
public void onPause() {
super.onPause();
getContext().getContentResolver().unregisterContentObserver(mSettingObserver);
unregisterPrefs(getPreferenceScreen());
}
private void registerPrefs(PreferenceGroup group) {
TunerService tunerService = TunerService.get(getContext());
final int N = group.getPreferenceCount();
for (int i = 0; i < N; i++) {
Preference pref = group.getPreference(i);
if (pref instanceof StatusBarSwitch) {
tunerService.addTunable((Tunable) pref, StatusBarIconController.ICON_BLACKLIST);
} else if (pref instanceof PreferenceGroup) {
registerPrefs((PreferenceGroup) pref);
}
}
}
private void unregisterPrefs(PreferenceGroup group) {
TunerService tunerService = TunerService.get(getContext());
final int N = group.getPreferenceCount();
for (int i = 0; i < N; i++) {
Preference pref = group.getPreference(i);
if (pref instanceof Tunable) {
tunerService.removeTunable((Tunable) pref);
} else if (pref instanceof PreferenceGroup) {
registerPrefs((PreferenceGroup) pref);
}
}
}
@Override

View File

@@ -0,0 +1,160 @@
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License
*/
package com.android.systemui.tuner;
import android.app.ActivityManager;
import android.content.ContentResolver;
import android.content.Context;
import android.database.ContentObserver;
import android.net.Uri;
import android.os.Handler;
import android.os.Looper;
import android.provider.Settings;
import android.util.ArrayMap;
import com.android.systemui.SystemUI;
import com.android.systemui.SystemUIApplication;
import com.android.systemui.settings.CurrentUserTracker;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
public class TunerService extends SystemUI {
private final Observer mObserver = new Observer();
// Map of Uris we listen on to their settings keys.
private final ArrayMap<Uri, String> mListeningUris = new ArrayMap<>();
// Map of settings keys to the listener.
private final HashMap<String, List<Tunable>> mTunableLookup = new HashMap<>();
private ContentResolver mContentResolver;
private int mCurrentUser;
private CurrentUserTracker mUserTracker;
@Override
public void start() {
mContentResolver = mContext.getContentResolver();
putComponent(TunerService.class, this);
mCurrentUser = ActivityManager.getCurrentUser();
mUserTracker = new CurrentUserTracker(mContext) {
@Override
public void onUserSwitched(int newUserId) {
mCurrentUser = newUserId;
reloadAll();
reregisterAll();
}
};
mUserTracker.startTracking();
}
public void addTunable(Tunable tunable, String... keys) {
for (String key : keys) {
addTunable(tunable, key);
}
}
private void addTunable(Tunable tunable, String key) {
if (!mTunableLookup.containsKey(key)) {
mTunableLookup.put(key, new ArrayList<Tunable>());
}
mTunableLookup.get(key).add(tunable);
Uri uri = Settings.Secure.getUriFor(key);
if (!mListeningUris.containsKey(uri)) {
mListeningUris.put(uri, key);
mContentResolver.registerContentObserver(uri, false, mObserver, mCurrentUser);
}
// Send the first state.
String value = Settings.Secure.getStringForUser(mContentResolver, key, mCurrentUser);
tunable.onTuningChanged(key, value);
}
public void removeTunable(Tunable tunable) {
for (List<Tunable> list : mTunableLookup.values()) {
list.remove(tunable);
}
}
protected void reregisterAll() {
if (mListeningUris.size() == 0) {
return;
}
mContentResolver.unregisterContentObserver(mObserver);
for (Uri uri : mListeningUris.keySet()) {
mContentResolver.registerContentObserver(uri, false, mObserver, mCurrentUser);
}
}
public void reloadSetting(Uri uri) {
String key = mListeningUris.get(uri);
String value = Settings.Secure.getStringForUser(mContentResolver, key, mCurrentUser);
for (Tunable tunable : mTunableLookup.get(key)) {
tunable.onTuningChanged(key, value);
}
}
private void reloadAll() {
for (String key : mTunableLookup.keySet()) {
String value = Settings.Secure.getStringForUser(mContentResolver, key,
mCurrentUser);
for (Tunable tunable : mTunableLookup.get(key)) {
tunable.onTuningChanged(key, value);
}
}
}
// Only used in other processes, such as the tuner.
private static TunerService sInstance;
public static TunerService get(Context context) {
SystemUIApplication sysUi = (SystemUIApplication) context.getApplicationContext();
TunerService service = sysUi.getComponent(TunerService.class);
if (service == null) {
// Can't get it as a component, must in the tuner, lets just create one for now.
return getStaticService(context);
}
return service;
}
private static TunerService getStaticService(Context context) {
if (sInstance == null) {
sInstance = new TunerService();
sInstance.mContext = context.getApplicationContext();
sInstance.mComponents = new HashMap<>();
sInstance.start();
}
return sInstance;
}
private class Observer extends ContentObserver {
public Observer() {
super(new Handler(Looper.getMainLooper()));
}
@Override
public void onChange(boolean selfChange, Uri uri, int userId) {
if (userId == ActivityManager.getCurrentUser()) {
reloadSetting(uri);
}
}
}
public interface Tunable {
void onTuningChanged(String key, String newValue);
}
}