am e895d43e: am 632fc874: Merge "QS: Fix some QS layout issues." into lmp-dev
* commit 'e895d43e9640b1e38c86af4e1556c5f88fd07241': QS: Fix some QS layout issues.
This commit is contained in:
@@ -90,6 +90,14 @@
|
||||
<!-- The number of columns that the top level tiles span in the QuickSettings -->
|
||||
<integer name="quick_settings_user_time_settings_tile_span">1</integer>
|
||||
|
||||
<!-- The default tiles to display in QuickSettings -->
|
||||
<string name="quick_settings_tiles_default" translatable="false">
|
||||
wifi,bt,inversion,cell,airplane,rotation,flashlight,location,cast
|
||||
</string>
|
||||
|
||||
<!-- The tiles to display in QuickSettings -->
|
||||
<string name="quick_settings_tiles" translatable="false">default</string>
|
||||
|
||||
<!-- Whether or not the RSSI tile is capitalized or not. -->
|
||||
<bool name="quick_settings_rssi_tile_capitalization">true</bool>
|
||||
|
||||
|
||||
@@ -37,6 +37,7 @@ import com.android.systemui.settings.ToggleSlider;
|
||||
import com.android.systemui.statusbar.phone.QSTileHost;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
||||
/** View that represents the quick settings tile panel. **/
|
||||
public class QSPanel extends ViewGroup {
|
||||
@@ -186,12 +187,25 @@ public class QSPanel extends ViewGroup {
|
||||
v.setVisibility(visible ? VISIBLE : GONE);
|
||||
}
|
||||
|
||||
public void addTile(final QSTile<?> tile) {
|
||||
public void setTiles(Collection<QSTile<?>> tiles) {
|
||||
for (TileRecord record : mRecords) {
|
||||
removeView(record.tileView);
|
||||
}
|
||||
mRecords.clear();
|
||||
for (QSTile<?> tile : tiles) {
|
||||
addTile(tile);
|
||||
}
|
||||
if (isShowingDetail()) {
|
||||
mDetail.bringToFront();
|
||||
}
|
||||
}
|
||||
|
||||
private void addTile(final QSTile<?> tile) {
|
||||
final TileRecord r = new TileRecord();
|
||||
r.tile = tile;
|
||||
r.tileView = tile.createTileView(mContext);
|
||||
r.tileView.setVisibility(View.GONE);
|
||||
r.tile.setCallback(new QSTile.Callback() {
|
||||
final QSTile.Callback callback = new QSTile.Callback() {
|
||||
@Override
|
||||
public void onStateChanged(QSTile.State state) {
|
||||
setTileVisibility(r.tileView, state.visible);
|
||||
@@ -213,7 +227,8 @@ public class QSPanel extends ViewGroup {
|
||||
fireScanStateChanged(state);
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
r.tile.setCallback(callback);
|
||||
final View.OnClickListener click = new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
@@ -227,6 +242,8 @@ public class QSPanel extends ViewGroup {
|
||||
}
|
||||
};
|
||||
r.tileView.init(click, clickSecondary);
|
||||
r.tile.setListening(mListening);
|
||||
callback.onStateChanged(r.tile.getState());
|
||||
r.tile.refreshState();
|
||||
mRecords.add(r);
|
||||
|
||||
|
||||
@@ -37,9 +37,8 @@ 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.ZenModeController;
|
||||
import com.android.systemui.volume.VolumeComponent;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Collection;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
@@ -134,6 +133,14 @@ public abstract class QSTile<TState extends State> implements Listenable {
|
||||
mHandler.obtainMessage(H.SCAN_STATE_CHANGED, state ? 1 : 0, 0).sendToTarget();
|
||||
}
|
||||
|
||||
public void destroy() {
|
||||
mHandler.sendEmptyMessage(H.DESTROY);
|
||||
}
|
||||
|
||||
public TState getState() {
|
||||
return mState;
|
||||
}
|
||||
|
||||
// call only on tile worker looper
|
||||
|
||||
private void handleSetCallback(Callback callback) {
|
||||
@@ -181,6 +188,11 @@ public abstract class QSTile<TState extends State> implements Listenable {
|
||||
handleRefreshState(null);
|
||||
}
|
||||
|
||||
protected void handleDestroy() {
|
||||
setListening(false);
|
||||
mCallback = null;
|
||||
}
|
||||
|
||||
protected final class H extends Handler {
|
||||
private static final int SET_CALLBACK = 1;
|
||||
private static final int CLICK = 2;
|
||||
@@ -190,6 +202,7 @@ public abstract class QSTile<TState extends State> implements Listenable {
|
||||
private static final int USER_SWITCH = 6;
|
||||
private static final int TOGGLE_STATE_CHANGED = 7;
|
||||
private static final int SCAN_STATE_CHANGED = 8;
|
||||
private static final int DESTROY = 9;
|
||||
|
||||
private H(Looper looper) {
|
||||
super(looper);
|
||||
@@ -223,6 +236,11 @@ public abstract class QSTile<TState extends State> implements Listenable {
|
||||
} else if (msg.what == SCAN_STATE_CHANGED) {
|
||||
name = "handleScanStateChanged";
|
||||
handleScanStateChanged(msg.arg1 != 0);
|
||||
} else if (msg.what == DESTROY) {
|
||||
name = "handleDestroy";
|
||||
handleDestroy();
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unknown msg: " + msg.what);
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
final String error = "Error in " + name;
|
||||
@@ -245,7 +263,8 @@ public abstract class QSTile<TState extends State> implements Listenable {
|
||||
void collapsePanels();
|
||||
Looper getLooper();
|
||||
Context getContext();
|
||||
List<QSTile<?>> getTiles();
|
||||
Collection<QSTile<?>> getTiles();
|
||||
void setCallback(Callback callback);
|
||||
BluetoothController getBluetoothController();
|
||||
LocationController getLocationController();
|
||||
RotationLockController getRotationLockController();
|
||||
@@ -255,6 +274,10 @@ public abstract class QSTile<TState extends State> implements Listenable {
|
||||
CastController getCastController();
|
||||
FlashlightController getFlashlightController();
|
||||
KeyguardMonitor getKeyguardMonitor();
|
||||
|
||||
public interface Callback {
|
||||
void onTilesChanged();
|
||||
}
|
||||
}
|
||||
|
||||
public static class State {
|
||||
|
||||
@@ -23,8 +23,9 @@ import android.content.IntentFilter;
|
||||
import android.content.SharedPreferences;
|
||||
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.statusbar.policy.Listenable;
|
||||
|
||||
public class UsageTracker {
|
||||
public class UsageTracker implements Listenable {
|
||||
private static final long MILLIS_PER_DAY = 1000 * 60 * 60 * 24;
|
||||
|
||||
private final Context mContext;
|
||||
@@ -32,7 +33,7 @@ public class UsageTracker {
|
||||
private final String mPrefKey;
|
||||
private final String mResetAction;
|
||||
|
||||
private BroadcastReceiver mReceiver;
|
||||
private boolean mRegistered;
|
||||
|
||||
public UsageTracker(Context context, Class<?> tile) {
|
||||
mContext = context;
|
||||
@@ -42,17 +43,14 @@ public class UsageTracker {
|
||||
mResetAction = "com.android.systemui.qs." + tile.getSimpleName() + ".usage_reset";
|
||||
}
|
||||
|
||||
public void listenForReset() {
|
||||
if (mReceiver != null) {
|
||||
mReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
if (mResetAction.equals(intent.getAction())) {
|
||||
reset();
|
||||
}
|
||||
}
|
||||
};
|
||||
mContext.registerReceiver(mReceiver, new IntentFilter(mResetAction));
|
||||
@Override
|
||||
public void setListening(boolean listen) {
|
||||
if (listen && !mRegistered) {
|
||||
mContext.registerReceiver(mReceiver, new IntentFilter(mResetAction));
|
||||
mRegistered = true;
|
||||
} else if (!listen && mRegistered) {
|
||||
mContext.unregisterReceiver(mReceiver);
|
||||
mRegistered = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,4 +70,13 @@ public class UsageTracker {
|
||||
private SharedPreferences getSharedPrefs() {
|
||||
return mContext.getSharedPreferences(mContext.getPackageName(), 0);
|
||||
}
|
||||
|
||||
private BroadcastReceiver mReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
if (mResetAction.equals(intent.getAction())) {
|
||||
reset();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -31,6 +31,8 @@ import com.android.systemui.qs.QSTile;
|
||||
public class AirplaneModeTile extends QSTile<QSTile.BooleanState> {
|
||||
private final GlobalSetting mSetting;
|
||||
|
||||
private boolean mListening;
|
||||
|
||||
public AirplaneModeTile(Host host) {
|
||||
super(host);
|
||||
|
||||
@@ -79,6 +81,8 @@ public class AirplaneModeTile extends QSTile<QSTile.BooleanState> {
|
||||
}
|
||||
|
||||
public void setListening(boolean listening) {
|
||||
if (mListening == listening) return;
|
||||
mListening = listening;
|
||||
if (listening) {
|
||||
final IntentFilter filter = new IntentFilter();
|
||||
filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
|
||||
|
||||
@@ -41,7 +41,13 @@ public class ColorInversionTile extends QSTile<QSTile.BooleanState> {
|
||||
}
|
||||
};
|
||||
mUsageTracker = new UsageTracker(host.getContext(), ColorInversionTile.class);
|
||||
mUsageTracker.listenForReset();
|
||||
mUsageTracker.setListening(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void handleDestroy() {
|
||||
super.handleDestroy();
|
||||
mUsageTracker.setListening(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -16,18 +16,13 @@
|
||||
|
||||
package com.android.systemui.qs.tiles;
|
||||
|
||||
import android.app.ActivityManager;
|
||||
import android.os.SystemClock;
|
||||
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.qs.QSTile;
|
||||
import com.android.systemui.qs.SecureSetting;
|
||||
import com.android.systemui.statusbar.policy.FlashlightController;
|
||||
|
||||
import android.app.ActivityManager;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.os.SystemClock;
|
||||
import android.provider.Settings.Secure;
|
||||
import android.util.Log;
|
||||
|
||||
/** Quick settings tile: Control flashlight **/
|
||||
public class FlashlightTile extends QSTile<QSTile.BooleanState> implements
|
||||
FlashlightController.FlashlightListener {
|
||||
@@ -45,6 +40,12 @@ public class FlashlightTile extends QSTile<QSTile.BooleanState> implements
|
||||
mFlashlightController.addListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void handleDestroy() {
|
||||
super.handleDestroy();
|
||||
mFlashlightController.removeListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected BooleanState newTileState() {
|
||||
return new BooleanState();
|
||||
|
||||
@@ -35,7 +35,13 @@ public class HotspotTile extends QSTile<QSTile.BooleanState> {
|
||||
super(host);
|
||||
mController = host.getHotspotController();
|
||||
mUsageTracker = new UsageTracker(host.getContext(), HotspotTile.class);
|
||||
mUsageTracker.listenForReset();
|
||||
mUsageTracker.setListening(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void handleDestroy() {
|
||||
super.handleDestroy();
|
||||
mUsageTracker.setListening(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
* Copyright (C) 2014 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.qs.tiles;
|
||||
|
||||
import android.app.PendingIntent;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.UserHandle;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.systemui.qs.QSTile;
|
||||
|
||||
public class IntentTile extends QSTile<QSTile.State> {
|
||||
public static final String PREFIX = "intent(";
|
||||
|
||||
private PendingIntent mOnClick;
|
||||
private String mOnClickUri;
|
||||
private int mCurrentUserId;
|
||||
|
||||
private IntentTile(Host host, String action) {
|
||||
super(host);
|
||||
mContext.registerReceiver(mReceiver, new IntentFilter(action));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void handleDestroy() {
|
||||
super.handleDestroy();
|
||||
mContext.unregisterReceiver(mReceiver);
|
||||
}
|
||||
|
||||
public static QSTile<?> create(Host host, String spec) {
|
||||
if (spec == null || !spec.startsWith(PREFIX) || !spec.endsWith(")")) {
|
||||
throw new IllegalArgumentException("Bad intent tile spec: " + spec);
|
||||
}
|
||||
final String action = spec.substring(PREFIX.length(), spec.length() - 1);
|
||||
if (action.isEmpty()) {
|
||||
throw new IllegalArgumentException("Empty intent tile spec action");
|
||||
}
|
||||
return new IntentTile(host, action);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setListening(boolean listening) {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected State newTileState() {
|
||||
return new State();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void handleUserSwitch(int newUserId) {
|
||||
super.handleUserSwitch(newUserId);
|
||||
mCurrentUserId = newUserId;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void handleClick() {
|
||||
try {
|
||||
if (mOnClick != null) {
|
||||
mOnClick.send();
|
||||
} else if (mOnClickUri != null) {
|
||||
final Intent intent = Intent.parseUri(mOnClickUri, Intent.URI_INTENT_SCHEME);
|
||||
mContext.sendBroadcastAsUser(intent, new UserHandle(mCurrentUserId));
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
Log.w(TAG, "Error sending click intent", t);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void handleUpdateState(State state, Object arg) {
|
||||
if (!(arg instanceof Intent)) return;
|
||||
final Intent intent = (Intent) arg;
|
||||
state.visible = intent.getBooleanExtra("visible", true);
|
||||
state.contentDescription = intent.getStringExtra("contentDescription");
|
||||
state.label = intent.getStringExtra("label");
|
||||
state.iconId = 0;
|
||||
state.icon = null;
|
||||
final byte[] iconBitmap = intent.getByteArrayExtra("iconBitmap");
|
||||
if (iconBitmap != null) {
|
||||
try {
|
||||
final Bitmap b = BitmapFactory.decodeByteArray(iconBitmap, 0, iconBitmap.length);
|
||||
state.icon = new BitmapDrawable(mContext.getResources(), b);
|
||||
} catch (Throwable t) {
|
||||
Log.w(TAG, "Error loading icon bitmap, length " + iconBitmap.length, t);
|
||||
}
|
||||
} else {
|
||||
final int iconId = intent.getIntExtra("iconId", 0);
|
||||
if (iconId != 0) {
|
||||
final String iconPackage = intent.getStringExtra("iconPackage");
|
||||
if (!TextUtils.isEmpty(iconPackage)) {
|
||||
state.icon = getPackageDrawable(iconPackage, iconId);
|
||||
} else {
|
||||
state.iconId = iconId;
|
||||
}
|
||||
}
|
||||
}
|
||||
mOnClick = intent.getParcelableExtra("onClick");
|
||||
mOnClickUri = intent.getStringExtra("onClickUri");
|
||||
}
|
||||
|
||||
private Drawable getPackageDrawable(String pkg, int id) {
|
||||
try {
|
||||
return mContext.createPackageContext(pkg, 0).getDrawable(id);
|
||||
} catch (Throwable t) {
|
||||
Log.w(TAG, "Error loading package drawable pkg=" + pkg + " id=" + id, t);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
refreshState(intent);
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -197,6 +197,20 @@ public class NotificationPanelView extends PanelView implements
|
||||
mAfforanceHelper = new KeyguardAffordanceHelper(this, getContext());
|
||||
mSecureCameraLaunchManager =
|
||||
new SecureCameraLaunchManager(getContext(), mKeyguardBottomArea);
|
||||
|
||||
// recompute internal state when qspanel height changes
|
||||
mQsContainer.addOnLayoutChangeListener(new OnLayoutChangeListener() {
|
||||
@Override
|
||||
public void onLayoutChange(View v, int left, int top, int right,
|
||||
int bottom, int oldLeft, int oldTop, int oldRight,
|
||||
int oldBottom) {
|
||||
final int height = bottom - top;
|
||||
final int oldHeight = oldBottom - oldTop;
|
||||
if (height != oldHeight) {
|
||||
onScrollChanged();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -818,10 +818,14 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
|
||||
mUserSwitcherController, mKeyguardMonitor,
|
||||
mSecurityController);
|
||||
mQSPanel.setHost(qsh);
|
||||
for (QSTile<?> tile : qsh.getTiles()) {
|
||||
mQSPanel.addTile(tile);
|
||||
}
|
||||
mQSPanel.setTiles(qsh.getTiles());
|
||||
mHeader.setQSPanel(mQSPanel);
|
||||
qsh.setCallback(new QSTileHost.Callback() {
|
||||
@Override
|
||||
public void onTilesChanged() {
|
||||
mQSPanel.setTiles(qsh.getTiles());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
mBackdrop = (FrameLayout) mStatusBarWindow.findViewById(R.id.backdrop);
|
||||
|
||||
@@ -18,9 +18,16 @@ 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.Handler;
|
||||
import android.os.HandlerThread;
|
||||
import android.os.Looper;
|
||||
import android.provider.Settings.Secure;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.qs.QSTile;
|
||||
import com.android.systemui.qs.tiles.AirplaneModeTile;
|
||||
import com.android.systemui.qs.tiles.BluetoothTile;
|
||||
@@ -29,6 +36,7 @@ import com.android.systemui.qs.tiles.CellularTile;
|
||||
import com.android.systemui.qs.tiles.ColorInversionTile;
|
||||
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;
|
||||
@@ -46,13 +54,23 @@ import com.android.systemui.statusbar.policy.UserSwitcherController;
|
||||
import com.android.systemui.statusbar.policy.ZenModeController;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/** Platform implementation of the quick settings tile host **/
|
||||
public class QSTileHost implements QSTile.Host {
|
||||
private static final String TAG = "QSTileHost";
|
||||
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
|
||||
|
||||
private static final String TILES_SETTING = "sysui_qs_tiles";
|
||||
|
||||
private final Context mContext;
|
||||
private final PhoneStatusBar mStatusBar;
|
||||
private final LinkedHashMap<String, QSTile<?>> mTiles = new LinkedHashMap<>();
|
||||
private final Observer mObserver = new Observer();
|
||||
private final BluetoothController mBluetooth;
|
||||
private final LocationController mLocation;
|
||||
private final RotationLockController mRotation;
|
||||
@@ -62,12 +80,13 @@ public class QSTileHost implements QSTile.Host {
|
||||
private final CastController mCast;
|
||||
private final Looper mLooper;
|
||||
private final CurrentUserTracker mUserTracker;
|
||||
private final ArrayList<QSTile<?>> mTiles = new ArrayList<QSTile<?>>();
|
||||
private final FlashlightController mFlashlight;
|
||||
private final UserSwitcherController mUserSwitcherController;
|
||||
private final KeyguardMonitor mKeyguard;
|
||||
private final SecurityController mSecurity;
|
||||
|
||||
private Callback mCallback;
|
||||
|
||||
public QSTileHost(Context context, PhoneStatusBar statusBar,
|
||||
BluetoothController bluetooth, LocationController location,
|
||||
RotationLockController rotation, NetworkController network,
|
||||
@@ -93,31 +112,30 @@ public class QSTileHost implements QSTile.Host {
|
||||
ht.start();
|
||||
mLooper = ht.getLooper();
|
||||
|
||||
mTiles.add(new WifiTile(this));
|
||||
mTiles.add(new BluetoothTile(this));
|
||||
mTiles.add(new ColorInversionTile(this));
|
||||
mTiles.add(new CellularTile(this));
|
||||
mTiles.add(new AirplaneModeTile(this));
|
||||
mTiles.add(new RotationLockTile(this));
|
||||
mTiles.add(new FlashlightTile(this));
|
||||
mTiles.add(new LocationTile(this));
|
||||
mTiles.add(new CastTile(this));
|
||||
mTiles.add(new HotspotTile(this));
|
||||
|
||||
mUserTracker = new CurrentUserTracker(mContext) {
|
||||
@Override
|
||||
public void onUserSwitched(int newUserId) {
|
||||
for (QSTile<?> tile : mTiles) {
|
||||
recreateTiles();
|
||||
for (QSTile<?> tile : mTiles.values()) {
|
||||
tile.userSwitch(newUserId);
|
||||
}
|
||||
mObserver.register();
|
||||
}
|
||||
};
|
||||
recreateTiles();
|
||||
|
||||
mUserTracker.startTracking();
|
||||
mObserver.register();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<QSTile<?>> getTiles() {
|
||||
return mTiles;
|
||||
public void setCallback(Callback callback) {
|
||||
mCallback = callback;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<QSTile<?>> getTiles() {
|
||||
return mTiles.values();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -197,4 +215,99 @@ public class QSTileHost implements QSTile.Host {
|
||||
public SecurityController getSecurityController() {
|
||||
return mSecurity;
|
||||
}
|
||||
|
||||
private void recreateTiles() {
|
||||
if (DEBUG) Log.d(TAG, "Recreating tiles");
|
||||
final List<String> tileSpecs = loadTileSpecs();
|
||||
for (Map.Entry<String, QSTile<?>> tile : mTiles.entrySet()) {
|
||||
if (!tileSpecs.contains(tile.getKey())) {
|
||||
if (DEBUG) Log.d(TAG, "Destroying tile: " + tile.getKey());
|
||||
tile.getValue().destroy();
|
||||
}
|
||||
}
|
||||
final LinkedHashMap<String, QSTile<?>> newTiles = new LinkedHashMap<>();
|
||||
for (String tileSpec : tileSpecs) {
|
||||
if (mTiles.containsKey(tileSpec)) {
|
||||
newTiles.put(tileSpec, mTiles.get(tileSpec));
|
||||
} else {
|
||||
if (DEBUG) Log.d(TAG, "Creating tile: " + tileSpec);
|
||||
try {
|
||||
newTiles.put(tileSpec, createTile(tileSpec));
|
||||
} catch (Throwable t) {
|
||||
Log.w(TAG, "Error creating tile for spec: " + tileSpec, t);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (mTiles.equals(newTiles)) return;
|
||||
mTiles.clear();
|
||||
mTiles.putAll(newTiles);
|
||||
if (mCallback != null) {
|
||||
mCallback.onTilesChanged();
|
||||
}
|
||||
}
|
||||
|
||||
private QSTile<?> createTile(String tileSpec) {
|
||||
if (tileSpec.equals("wifi")) return new WifiTile(this);
|
||||
else if (tileSpec.equals("bt")) return new BluetoothTile(this);
|
||||
else if (tileSpec.equals("inversion")) return new ColorInversionTile(this);
|
||||
else if (tileSpec.equals("cell")) return new CellularTile(this);
|
||||
else if (tileSpec.equals("airplane")) return new AirplaneModeTile(this);
|
||||
else if (tileSpec.equals("rotation")) return new RotationLockTile(this);
|
||||
else if (tileSpec.equals("flashlight")) return new FlashlightTile(this);
|
||||
else if (tileSpec.equals("location")) return new LocationTile(this);
|
||||
else if (tileSpec.equals("cast")) return new CastTile(this);
|
||||
else if (tileSpec.equals("hotspot")) return new HotspotTile(this);
|
||||
else if (tileSpec.startsWith(IntentTile.PREFIX)) return IntentTile.create(this,tileSpec);
|
||||
else throw new IllegalArgumentException("Bad tile spec: " + tileSpec);
|
||||
}
|
||||
|
||||
private List<String> loadTileSpecs() {
|
||||
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);
|
||||
} else {
|
||||
if (DEBUG) Log.d(TAG, "Loaded tile specs from setting: " + tileList);
|
||||
}
|
||||
final ArrayList<String> tiles = new ArrayList<String>();
|
||||
boolean addedDefault = false;
|
||||
for (String tile : tileList.split(",")) {
|
||||
tile = tile.trim();
|
||||
if (tile.isEmpty()) continue;
|
||||
if (tile.equals("default")) {
|
||||
if (!addedDefault) {
|
||||
tiles.addAll(Arrays.asList(defaultTileList.split(",")));
|
||||
addedDefault = true;
|
||||
}
|
||||
} else {
|
||||
tiles.add(tile);
|
||||
}
|
||||
}
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user