Merge "Store state of active TileService" into sc-dev am: 22a01eca60
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/14937370 Change-Id: Id8897654ed8092472bc5ff0ea1317beb69cc57e0
This commit is contained in:
@@ -45,7 +45,9 @@ import com.android.systemui.plugins.qs.QSFactory;
|
|||||||
import com.android.systemui.plugins.qs.QSTile;
|
import com.android.systemui.plugins.qs.QSTile;
|
||||||
import com.android.systemui.plugins.qs.QSTileView;
|
import com.android.systemui.plugins.qs.QSTileView;
|
||||||
import com.android.systemui.qs.external.CustomTile;
|
import com.android.systemui.qs.external.CustomTile;
|
||||||
|
import com.android.systemui.qs.external.CustomTileStatePersister;
|
||||||
import com.android.systemui.qs.external.TileLifecycleManager;
|
import com.android.systemui.qs.external.TileLifecycleManager;
|
||||||
|
import com.android.systemui.qs.external.TileServiceKey;
|
||||||
import com.android.systemui.qs.external.TileServices;
|
import com.android.systemui.qs.external.TileServices;
|
||||||
import com.android.systemui.qs.logging.QSLogger;
|
import com.android.systemui.qs.logging.QSLogger;
|
||||||
import com.android.systemui.settings.UserTracker;
|
import com.android.systemui.settings.UserTracker;
|
||||||
@@ -93,6 +95,7 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D
|
|||||||
private final QSLogger mQSLogger;
|
private final QSLogger mQSLogger;
|
||||||
private final UiEventLogger mUiEventLogger;
|
private final UiEventLogger mUiEventLogger;
|
||||||
private final InstanceIdSequence mInstanceIdSequence;
|
private final InstanceIdSequence mInstanceIdSequence;
|
||||||
|
private final CustomTileStatePersister mCustomTileStatePersister;
|
||||||
|
|
||||||
private final List<Callback> mCallbacks = new ArrayList<>();
|
private final List<Callback> mCallbacks = new ArrayList<>();
|
||||||
private AutoTileManager mAutoTiles;
|
private AutoTileManager mAutoTiles;
|
||||||
@@ -119,7 +122,8 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D
|
|||||||
QSLogger qsLogger,
|
QSLogger qsLogger,
|
||||||
UiEventLogger uiEventLogger,
|
UiEventLogger uiEventLogger,
|
||||||
UserTracker userTracker,
|
UserTracker userTracker,
|
||||||
SecureSettings secureSettings) {
|
SecureSettings secureSettings,
|
||||||
|
CustomTileStatePersister customTileStatePersister) {
|
||||||
mIconController = iconController;
|
mIconController = iconController;
|
||||||
mContext = context;
|
mContext = context;
|
||||||
mUserContext = context;
|
mUserContext = context;
|
||||||
@@ -139,6 +143,7 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D
|
|||||||
mDumpManager.registerDumpable(TAG, this);
|
mDumpManager.registerDumpable(TAG, this);
|
||||||
mUserTracker = userTracker;
|
mUserTracker = userTracker;
|
||||||
mSecureSettings = secureSettings;
|
mSecureSettings = secureSettings;
|
||||||
|
mCustomTileStatePersister = customTileStatePersister;
|
||||||
|
|
||||||
mainHandler.post(() -> {
|
mainHandler.post(() -> {
|
||||||
// This is technically a hack to avoid circular dependency of
|
// This is technically a hack to avoid circular dependency of
|
||||||
@@ -418,6 +423,11 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D
|
|||||||
changeTiles(mTileSpecs, newSpecs);
|
changeTiles(mTileSpecs, newSpecs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Change the tiles triggered by the user editing.
|
||||||
|
* <p>
|
||||||
|
* This is not called on device start, or on user change.
|
||||||
|
*/
|
||||||
public void changeTiles(List<String> previousTiles, List<String> newTiles) {
|
public void changeTiles(List<String> previousTiles, List<String> newTiles) {
|
||||||
final List<String> copy = new ArrayList<>(previousTiles);
|
final List<String> copy = new ArrayList<>(previousTiles);
|
||||||
final int NP = copy.size();
|
final int NP = copy.size();
|
||||||
@@ -433,6 +443,7 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D
|
|||||||
mBroadcastDispatcher);
|
mBroadcastDispatcher);
|
||||||
lifecycleManager.onStopListening();
|
lifecycleManager.onStopListening();
|
||||||
lifecycleManager.onTileRemoved();
|
lifecycleManager.onTileRemoved();
|
||||||
|
mCustomTileStatePersister.removeState(new TileServiceKey(component, mCurrentUser));
|
||||||
TileLifecycleManager.setTileAdded(mContext, component, false);
|
TileLifecycleManager.setTileAdded(mContext, component, false);
|
||||||
lifecycleManager.flushMessagesAndUnbind();
|
lifecycleManager.flushMessagesAndUnbind();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ import android.widget.Switch;
|
|||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.annotation.WorkerThread;
|
||||||
|
|
||||||
import com.android.internal.logging.MetricsLogger;
|
import com.android.internal.logging.MetricsLogger;
|
||||||
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
|
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
|
||||||
@@ -85,6 +86,7 @@ public class CustomTile extends QSTileImpl<State> implements TileChangeListener
|
|||||||
private final IQSTileService mService;
|
private final IQSTileService mService;
|
||||||
private final TileServiceManager mServiceManager;
|
private final TileServiceManager mServiceManager;
|
||||||
private final int mUser;
|
private final int mUser;
|
||||||
|
private final CustomTileStatePersister mCustomTileStatePersister;
|
||||||
private android.graphics.drawable.Icon mDefaultIcon;
|
private android.graphics.drawable.Icon mDefaultIcon;
|
||||||
private CharSequence mDefaultLabel;
|
private CharSequence mDefaultLabel;
|
||||||
|
|
||||||
@@ -94,6 +96,8 @@ public class CustomTile extends QSTileImpl<State> implements TileChangeListener
|
|||||||
private boolean mIsTokenGranted;
|
private boolean mIsTokenGranted;
|
||||||
private boolean mIsShowingDialog;
|
private boolean mIsShowingDialog;
|
||||||
|
|
||||||
|
private final TileServiceKey mKey;
|
||||||
|
|
||||||
private CustomTile(
|
private CustomTile(
|
||||||
QSHost host,
|
QSHost host,
|
||||||
Looper backgroundLooper,
|
Looper backgroundLooper,
|
||||||
@@ -104,7 +108,8 @@ public class CustomTile extends QSTileImpl<State> implements TileChangeListener
|
|||||||
ActivityStarter activityStarter,
|
ActivityStarter activityStarter,
|
||||||
QSLogger qsLogger,
|
QSLogger qsLogger,
|
||||||
String action,
|
String action,
|
||||||
Context userContext
|
Context userContext,
|
||||||
|
CustomTileStatePersister customTileStatePersister
|
||||||
) {
|
) {
|
||||||
super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger,
|
super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger,
|
||||||
statusBarStateController, activityStarter, qsLogger);
|
statusBarStateController, activityStarter, qsLogger);
|
||||||
@@ -113,15 +118,29 @@ public class CustomTile extends QSTileImpl<State> implements TileChangeListener
|
|||||||
mTile = new Tile();
|
mTile = new Tile();
|
||||||
mUserContext = userContext;
|
mUserContext = userContext;
|
||||||
mUser = mUserContext.getUserId();
|
mUser = mUserContext.getUserId();
|
||||||
updateDefaultTileAndIcon();
|
mKey = new TileServiceKey(mComponent, mUser);
|
||||||
|
|
||||||
mServiceManager = host.getTileServices().getTileWrapper(this);
|
mServiceManager = host.getTileServices().getTileWrapper(this);
|
||||||
|
mService = mServiceManager.getTileService();
|
||||||
|
mCustomTileStatePersister = customTileStatePersister;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void handleInitialize() {
|
||||||
|
updateDefaultTileAndIcon();
|
||||||
if (mServiceManager.isToggleableTile()) {
|
if (mServiceManager.isToggleableTile()) {
|
||||||
// Replace states with BooleanState
|
// Replace states with BooleanState
|
||||||
resetStates();
|
resetStates();
|
||||||
}
|
}
|
||||||
|
|
||||||
mService = mServiceManager.getTileService();
|
|
||||||
mServiceManager.setTileChangeListener(this);
|
mServiceManager.setTileChangeListener(this);
|
||||||
|
if (mServiceManager.isActiveTile()) {
|
||||||
|
Tile t = mCustomTileStatePersister.readState(mKey);
|
||||||
|
if (t != null) {
|
||||||
|
applyTileState(t, /* overwriteNulls */ false);
|
||||||
|
mServiceManager.clearPendingBind();
|
||||||
|
refreshState();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -191,7 +210,7 @@ public class CustomTile extends QSTileImpl<State> implements TileChangeListener
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onTileChanged(ComponentName tile) {
|
public void onTileChanged(ComponentName tile) {
|
||||||
updateDefaultTileAndIcon();
|
mHandler.post(this::updateDefaultTileAndIcon);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -213,16 +232,44 @@ public class CustomTile extends QSTileImpl<State> implements TileChangeListener
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Tile getQsTile() {
|
public Tile getQsTile() {
|
||||||
|
// TODO(b/191145007) Move to background thread safely
|
||||||
updateDefaultTileAndIcon();
|
updateDefaultTileAndIcon();
|
||||||
return mTile;
|
return mTile;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateState(Tile tile) {
|
/**
|
||||||
|
* Update state of {@link this#mTile} from a remote {@link TileService}.
|
||||||
|
* @param tile tile populated with state to apply
|
||||||
|
*/
|
||||||
|
public void updateTileState(Tile tile) {
|
||||||
|
// This comes from a binder call IQSService.updateQsTile
|
||||||
|
mHandler.post(() -> handleUpdateTileState(tile));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleUpdateTileState(Tile tile) {
|
||||||
|
applyTileState(tile, /* overwriteNulls */ true);
|
||||||
|
if (mServiceManager.isActiveTile()) {
|
||||||
|
mCustomTileStatePersister.persistState(mKey, tile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@WorkerThread
|
||||||
|
private void applyTileState(Tile tile, boolean overwriteNulls) {
|
||||||
|
if (tile.getIcon() != null || overwriteNulls) {
|
||||||
mTile.setIcon(tile.getIcon());
|
mTile.setIcon(tile.getIcon());
|
||||||
|
}
|
||||||
|
if (tile.getLabel() != null || overwriteNulls) {
|
||||||
mTile.setLabel(tile.getLabel());
|
mTile.setLabel(tile.getLabel());
|
||||||
|
}
|
||||||
|
if (tile.getSubtitle() != null || overwriteNulls) {
|
||||||
mTile.setSubtitle(tile.getSubtitle());
|
mTile.setSubtitle(tile.getSubtitle());
|
||||||
|
}
|
||||||
|
if (tile.getContentDescription() != null || overwriteNulls) {
|
||||||
mTile.setContentDescription(tile.getContentDescription());
|
mTile.setContentDescription(tile.getContentDescription());
|
||||||
|
}
|
||||||
|
if (tile.getStateDescription() != null || overwriteNulls) {
|
||||||
mTile.setStateDescription(tile.getStateDescription());
|
mTile.setStateDescription(tile.getStateDescription());
|
||||||
|
}
|
||||||
mTile.setState(tile.getState());
|
mTile.setState(tile.getState());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -459,6 +506,7 @@ public class CustomTile extends QSTileImpl<State> implements TileChangeListener
|
|||||||
final StatusBarStateController mStatusBarStateController;
|
final StatusBarStateController mStatusBarStateController;
|
||||||
final ActivityStarter mActivityStarter;
|
final ActivityStarter mActivityStarter;
|
||||||
final QSLogger mQSLogger;
|
final QSLogger mQSLogger;
|
||||||
|
final CustomTileStatePersister mCustomTileStatePersister;
|
||||||
|
|
||||||
Context mUserContext;
|
Context mUserContext;
|
||||||
String mSpec = "";
|
String mSpec = "";
|
||||||
@@ -472,7 +520,8 @@ public class CustomTile extends QSTileImpl<State> implements TileChangeListener
|
|||||||
MetricsLogger metricsLogger,
|
MetricsLogger metricsLogger,
|
||||||
StatusBarStateController statusBarStateController,
|
StatusBarStateController statusBarStateController,
|
||||||
ActivityStarter activityStarter,
|
ActivityStarter activityStarter,
|
||||||
QSLogger qsLogger
|
QSLogger qsLogger,
|
||||||
|
CustomTileStatePersister customTileStatePersister
|
||||||
) {
|
) {
|
||||||
mQSHostLazy = hostLazy;
|
mQSHostLazy = hostLazy;
|
||||||
mBackgroundLooper = backgroundLooper;
|
mBackgroundLooper = backgroundLooper;
|
||||||
@@ -482,6 +531,7 @@ public class CustomTile extends QSTileImpl<State> implements TileChangeListener
|
|||||||
mStatusBarStateController = statusBarStateController;
|
mStatusBarStateController = statusBarStateController;
|
||||||
mActivityStarter = activityStarter;
|
mActivityStarter = activityStarter;
|
||||||
mQSLogger = qsLogger;
|
mQSLogger = qsLogger;
|
||||||
|
mCustomTileStatePersister = customTileStatePersister;
|
||||||
}
|
}
|
||||||
|
|
||||||
Builder setSpec(@NonNull String spec) {
|
Builder setSpec(@NonNull String spec) {
|
||||||
@@ -509,7 +559,8 @@ public class CustomTile extends QSTileImpl<State> implements TileChangeListener
|
|||||||
mActivityStarter,
|
mActivityStarter,
|
||||||
mQSLogger,
|
mQSLogger,
|
||||||
action,
|
action,
|
||||||
mUserContext
|
mUserContext,
|
||||||
|
mCustomTileStatePersister
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
122
packages/SystemUI/src/com/android/systemui/qs/external/CustomTileStatePersister.kt
vendored
Normal file
122
packages/SystemUI/src/com/android/systemui/qs/external/CustomTileStatePersister.kt
vendored
Normal file
@@ -0,0 +1,122 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2021 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.external
|
||||||
|
|
||||||
|
import android.content.ComponentName
|
||||||
|
import android.content.Context
|
||||||
|
import android.service.quicksettings.Tile
|
||||||
|
import android.util.Log
|
||||||
|
import com.android.internal.annotations.VisibleForTesting
|
||||||
|
import org.json.JSONException
|
||||||
|
import org.json.JSONObject
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
data class TileServiceKey(val componentName: ComponentName, val user: Int) {
|
||||||
|
private val string = "${componentName.flattenToString()}:$user"
|
||||||
|
override fun toString() = string
|
||||||
|
}
|
||||||
|
private const val STATE = "state"
|
||||||
|
private const val LABEL = "label"
|
||||||
|
private const val SUBTITLE = "subtitle"
|
||||||
|
private const val CONTENT_DESCRIPTION = "content_description"
|
||||||
|
private const val STATE_DESCRIPTION = "state_description"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Persists and retrieves state for [CustomTile].
|
||||||
|
*
|
||||||
|
* This class will persists to a fixed [SharedPreference] file a state for a pair of [ComponentName]
|
||||||
|
* and user id ([TileServiceKey]).
|
||||||
|
*
|
||||||
|
* It persists the state from a [Tile] necessary to present the view in the same state when
|
||||||
|
* retrieved, with the exception of the icon.
|
||||||
|
*/
|
||||||
|
class CustomTileStatePersister @Inject constructor(context: Context) {
|
||||||
|
companion object {
|
||||||
|
private const val FILE_NAME = "custom_tiles_state"
|
||||||
|
}
|
||||||
|
|
||||||
|
private val sharedPreferences = context.getSharedPreferences(FILE_NAME, 0)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read the state from [SharedPreferences].
|
||||||
|
*
|
||||||
|
* Returns `null` if the tile has no saved state.
|
||||||
|
*
|
||||||
|
* Any fields that have not been saved will be set to `null`
|
||||||
|
*/
|
||||||
|
fun readState(key: TileServiceKey): Tile? {
|
||||||
|
val state = sharedPreferences.getString(key.toString(), null) ?: return null
|
||||||
|
return try {
|
||||||
|
readTileFromString(state)
|
||||||
|
} catch (e: JSONException) {
|
||||||
|
Log.e("TileServicePersistence", "Bad saved state: $state", e)
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Persists the state into [SharedPreferences].
|
||||||
|
*
|
||||||
|
* The implementation does not store fields that are `null` or icons.
|
||||||
|
*/
|
||||||
|
fun persistState(key: TileServiceKey, tile: Tile) {
|
||||||
|
val state = writeToString(tile)
|
||||||
|
|
||||||
|
sharedPreferences.edit().putString(key.toString(), state).apply()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the state for a given tile, user pair.
|
||||||
|
*
|
||||||
|
* Used when the tile is removed by the user.
|
||||||
|
*/
|
||||||
|
fun removeState(key: TileServiceKey) {
|
||||||
|
sharedPreferences.edit().remove(key.toString()).apply()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
internal fun readTileFromString(stateString: String): Tile {
|
||||||
|
val json = JSONObject(stateString)
|
||||||
|
return Tile().apply {
|
||||||
|
state = json.getInt(STATE)
|
||||||
|
label = json.getStringOrNull(LABEL)
|
||||||
|
subtitle = json.getStringOrNull(SUBTITLE)
|
||||||
|
contentDescription = json.getStringOrNull(CONTENT_DESCRIPTION)
|
||||||
|
stateDescription = json.getStringOrNull(STATE_DESCRIPTION)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Properties with null values will not be saved to the Json string in any way. This makes sure
|
||||||
|
// to properly retrieve a null in that case.
|
||||||
|
private fun JSONObject.getStringOrNull(name: String): String? {
|
||||||
|
return if (has(name)) getString(name) else null
|
||||||
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
internal fun writeToString(tile: Tile): String {
|
||||||
|
// Not storing the icon
|
||||||
|
return with(tile) {
|
||||||
|
JSONObject()
|
||||||
|
.put(STATE, state)
|
||||||
|
.put(LABEL, label)
|
||||||
|
.put(SUBTITLE, subtitle)
|
||||||
|
.put(CONTENT_DESCRIPTION, contentDescription)
|
||||||
|
.put(STATE_DESCRIPTION, stateDescription)
|
||||||
|
.toString()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -204,7 +204,7 @@ public class TileServices extends IQSService.Stub {
|
|||||||
tileServiceManager.clearPendingBind();
|
tileServiceManager.clearPendingBind();
|
||||||
tileServiceManager.setLastUpdate(System.currentTimeMillis());
|
tileServiceManager.setLastUpdate(System.currentTimeMillis());
|
||||||
}
|
}
|
||||||
customTile.updateState(tile);
|
customTile.updateTileState(tile);
|
||||||
customTile.refreshState();
|
customTile.refreshState();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -160,7 +160,8 @@ public class QSFactoryImpl implements QSFactory {
|
|||||||
public QSTile createTile(String tileSpec) {
|
public QSTile createTile(String tileSpec) {
|
||||||
QSTileImpl tile = createTileInternal(tileSpec);
|
QSTileImpl tile = createTileInternal(tileSpec);
|
||||||
if (tile != null) {
|
if (tile != null) {
|
||||||
tile.handleStale(); // Tile was just created, must be stale.
|
tile.initialize();
|
||||||
|
tile.postStale(); // Tile was just created, must be stale.
|
||||||
}
|
}
|
||||||
return tile;
|
return tile;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -159,6 +159,15 @@ public abstract class QSTileImpl<TState extends State> implements QSTile, Lifecy
|
|||||||
*/
|
*/
|
||||||
abstract public int getMetricsCategory();
|
abstract public int getMetricsCategory();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs initialization of the tile
|
||||||
|
*
|
||||||
|
* Use this to perform initialization of the tile. Empty by default.
|
||||||
|
*/
|
||||||
|
protected void handleInitialize() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
protected QSTileImpl(
|
protected QSTileImpl(
|
||||||
QSHost host,
|
QSHost host,
|
||||||
Looper backgroundLooper,
|
Looper backgroundLooper,
|
||||||
@@ -347,6 +356,15 @@ public abstract class QSTileImpl<TState extends State> implements QSTile, Lifecy
|
|||||||
mHandler.sendEmptyMessage(H.DESTROY);
|
mHandler.sendEmptyMessage(H.DESTROY);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Schedules initialization of the tile.
|
||||||
|
*
|
||||||
|
* Should be called upon creation of the tile, before performing other operations
|
||||||
|
*/
|
||||||
|
public void initialize() {
|
||||||
|
mHandler.sendEmptyMessage(H.INITIALIZE);
|
||||||
|
}
|
||||||
|
|
||||||
public TState getState() {
|
public TState getState() {
|
||||||
return mState;
|
return mState;
|
||||||
}
|
}
|
||||||
@@ -370,6 +388,13 @@ public abstract class QSTileImpl<TState extends State> implements QSTile, Lifecy
|
|||||||
mCallbacks.clear();
|
mCallbacks.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Posts a stale message to the background thread.
|
||||||
|
*/
|
||||||
|
public void postStale() {
|
||||||
|
mHandler.sendEmptyMessage(H.STALE);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles secondary click on the tile.
|
* Handles secondary click on the tile.
|
||||||
*
|
*
|
||||||
@@ -582,6 +607,7 @@ public abstract class QSTileImpl<TState extends State> implements QSTile, Lifecy
|
|||||||
private static final int SET_LISTENING = 13;
|
private static final int SET_LISTENING = 13;
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
protected static final int STALE = 14;
|
protected static final int STALE = 14;
|
||||||
|
private static final int INITIALIZE = 15;
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
protected H(Looper looper) {
|
protected H(Looper looper) {
|
||||||
@@ -640,6 +666,9 @@ public abstract class QSTileImpl<TState extends State> implements QSTile, Lifecy
|
|||||||
} else if (msg.what == STALE) {
|
} else if (msg.what == STALE) {
|
||||||
name = "handleStale";
|
name = "handleStale";
|
||||||
handleStale();
|
handleStale();
|
||||||
|
} else if (msg.what == INITIALIZE) {
|
||||||
|
name = "initialize";
|
||||||
|
handleInitialize();
|
||||||
} else {
|
} else {
|
||||||
throw new IllegalArgumentException("Unknown msg: " + msg.what);
|
throw new IllegalArgumentException("Unknown msg: " + msg.what);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ import com.android.systemui.dump.DumpManager;
|
|||||||
import com.android.systemui.media.MediaHost;
|
import com.android.systemui.media.MediaHost;
|
||||||
import com.android.systemui.plugins.statusbar.StatusBarStateController;
|
import com.android.systemui.plugins.statusbar.StatusBarStateController;
|
||||||
import com.android.systemui.qs.dagger.QSFragmentComponent;
|
import com.android.systemui.qs.dagger.QSFragmentComponent;
|
||||||
|
import com.android.systemui.qs.external.CustomTileStatePersister;
|
||||||
import com.android.systemui.qs.logging.QSLogger;
|
import com.android.systemui.qs.logging.QSLogger;
|
||||||
import com.android.systemui.qs.tileimpl.QSFactoryImpl;
|
import com.android.systemui.qs.tileimpl.QSFactoryImpl;
|
||||||
import com.android.systemui.settings.UserTracker;
|
import com.android.systemui.settings.UserTracker;
|
||||||
@@ -132,7 +133,7 @@ public class QSFragmentTest extends SysuiBaseFragmentTest {
|
|||||||
() -> mock(AutoTileManager.class), mock(DumpManager.class),
|
() -> mock(AutoTileManager.class), mock(DumpManager.class),
|
||||||
mock(BroadcastDispatcher.class), Optional.of(mock(StatusBar.class)),
|
mock(BroadcastDispatcher.class), Optional.of(mock(StatusBar.class)),
|
||||||
mock(QSLogger.class), mock(UiEventLogger.class), mock(UserTracker.class),
|
mock(QSLogger.class), mock(UiEventLogger.class), mock(UserTracker.class),
|
||||||
mock(SecureSettings.class));
|
mock(SecureSettings.class), mock(CustomTileStatePersister.class));
|
||||||
qs.setHost(host);
|
qs.setHost(host);
|
||||||
|
|
||||||
qs.setListening(true);
|
qs.setListening(true);
|
||||||
|
|||||||
@@ -59,6 +59,8 @@ import com.android.systemui.plugins.qs.QSFactory;
|
|||||||
import com.android.systemui.plugins.qs.QSTile;
|
import com.android.systemui.plugins.qs.QSTile;
|
||||||
import com.android.systemui.plugins.statusbar.StatusBarStateController;
|
import com.android.systemui.plugins.statusbar.StatusBarStateController;
|
||||||
import com.android.systemui.qs.external.CustomTile;
|
import com.android.systemui.qs.external.CustomTile;
|
||||||
|
import com.android.systemui.qs.external.CustomTileStatePersister;
|
||||||
|
import com.android.systemui.qs.external.TileServiceKey;
|
||||||
import com.android.systemui.qs.logging.QSLogger;
|
import com.android.systemui.qs.logging.QSLogger;
|
||||||
import com.android.systemui.qs.tileimpl.QSTileImpl;
|
import com.android.systemui.qs.tileimpl.QSTileImpl;
|
||||||
import com.android.systemui.settings.UserTracker;
|
import com.android.systemui.settings.UserTracker;
|
||||||
@@ -125,6 +127,8 @@ public class QSTileHostTest extends SysuiTestCase {
|
|||||||
private UserTracker mUserTracker;
|
private UserTracker mUserTracker;
|
||||||
@Mock
|
@Mock
|
||||||
private SecureSettings mSecureSettings;
|
private SecureSettings mSecureSettings;
|
||||||
|
@Mock
|
||||||
|
private CustomTileStatePersister mCustomTileStatePersister;
|
||||||
|
|
||||||
private Handler mHandler;
|
private Handler mHandler;
|
||||||
private TestableLooper mLooper;
|
private TestableLooper mLooper;
|
||||||
@@ -145,7 +149,7 @@ public class QSTileHostTest extends SysuiTestCase {
|
|||||||
mQSTileHost = new TestQSTileHost(mContext, mIconController, mDefaultFactory, mHandler,
|
mQSTileHost = new TestQSTileHost(mContext, mIconController, mDefaultFactory, mHandler,
|
||||||
mLooper.getLooper(), mPluginManager, mTunerService, mAutoTiles, mDumpManager,
|
mLooper.getLooper(), mPluginManager, mTunerService, mAutoTiles, mDumpManager,
|
||||||
mBroadcastDispatcher, mStatusBar, mQSLogger, mUiEventLogger, mUserTracker,
|
mBroadcastDispatcher, mStatusBar, mQSLogger, mUiEventLogger, mUserTracker,
|
||||||
mSecureSettings);
|
mSecureSettings, mCustomTileStatePersister);
|
||||||
setUpTileFactory();
|
setUpTileFactory();
|
||||||
|
|
||||||
when(mSecureSettings.getStringForUser(eq(QSTileHost.TILES_SETTING), anyInt()))
|
when(mSecureSettings.getStringForUser(eq(QSTileHost.TILES_SETTING), anyInt()))
|
||||||
@@ -371,6 +375,14 @@ public class QSTileHostTest extends SysuiTestCase {
|
|||||||
verify(mQSLogger, never()).logTileDestroyed(isNull(), anyString());
|
verify(mQSLogger, never()).logTileDestroyed(isNull(), anyString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCustomTileRemoved_stateDeleted() {
|
||||||
|
mQSTileHost.changeTiles(List.of(CUSTOM_TILE_SPEC), List.of());
|
||||||
|
|
||||||
|
verify(mCustomTileStatePersister)
|
||||||
|
.removeState(new TileServiceKey(CUSTOM_TILE, mQSTileHost.getUserId()));
|
||||||
|
}
|
||||||
|
|
||||||
private class TestQSTileHost extends QSTileHost {
|
private class TestQSTileHost extends QSTileHost {
|
||||||
TestQSTileHost(Context context, StatusBarIconController iconController,
|
TestQSTileHost(Context context, StatusBarIconController iconController,
|
||||||
QSFactory defaultFactory, Handler mainHandler, Looper bgLooper,
|
QSFactory defaultFactory, Handler mainHandler, Looper bgLooper,
|
||||||
@@ -378,10 +390,11 @@ public class QSTileHostTest extends SysuiTestCase {
|
|||||||
Provider<AutoTileManager> autoTiles, DumpManager dumpManager,
|
Provider<AutoTileManager> autoTiles, DumpManager dumpManager,
|
||||||
BroadcastDispatcher broadcastDispatcher, StatusBar statusBar, QSLogger qsLogger,
|
BroadcastDispatcher broadcastDispatcher, StatusBar statusBar, QSLogger qsLogger,
|
||||||
UiEventLogger uiEventLogger, UserTracker userTracker,
|
UiEventLogger uiEventLogger, UserTracker userTracker,
|
||||||
SecureSettings secureSettings) {
|
SecureSettings secureSettings, CustomTileStatePersister customTileStatePersister) {
|
||||||
super(context, iconController, defaultFactory, mainHandler, bgLooper, pluginManager,
|
super(context, iconController, defaultFactory, mainHandler, bgLooper, pluginManager,
|
||||||
tunerService, autoTiles, dumpManager, broadcastDispatcher,
|
tunerService, autoTiles, dumpManager, broadcastDispatcher,
|
||||||
Optional.of(statusBar), qsLogger, uiEventLogger, userTracker, secureSettings);
|
Optional.of(statusBar), qsLogger, uiEventLogger, userTracker, secureSettings,
|
||||||
|
customTileStatePersister);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
159
packages/SystemUI/tests/src/com/android/systemui/qs/external/CustomTileStatePersisterTest.kt
vendored
Normal file
159
packages/SystemUI/tests/src/com/android/systemui/qs/external/CustomTileStatePersisterTest.kt
vendored
Normal file
@@ -0,0 +1,159 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2021 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.external
|
||||||
|
|
||||||
|
import android.content.ComponentName
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.SharedPreferences
|
||||||
|
import android.service.quicksettings.Tile
|
||||||
|
import android.testing.AndroidTestingRunner
|
||||||
|
import androidx.test.filters.SmallTest
|
||||||
|
import com.android.systemui.SysuiTestCase
|
||||||
|
import com.android.systemui.util.mockito.capture
|
||||||
|
import com.android.systemui.util.mockito.eq
|
||||||
|
import com.google.common.truth.Truth.assertThat
|
||||||
|
import org.junit.Before
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
import org.mockito.Answers
|
||||||
|
import org.mockito.ArgumentCaptor
|
||||||
|
import org.mockito.ArgumentMatchers.any
|
||||||
|
import org.mockito.ArgumentMatchers.anyInt
|
||||||
|
import org.mockito.ArgumentMatchers.anyString
|
||||||
|
import org.mockito.Captor
|
||||||
|
import org.mockito.Mock
|
||||||
|
import org.mockito.Mockito.`when`
|
||||||
|
import org.mockito.Mockito.verify
|
||||||
|
import org.mockito.MockitoAnnotations
|
||||||
|
|
||||||
|
@SmallTest
|
||||||
|
@RunWith(AndroidTestingRunner::class)
|
||||||
|
class CustomTileStatePersisterTest : SysuiTestCase() {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val TEST_COMPONENT = ComponentName("pkg", "cls")
|
||||||
|
private const val TEST_USER = 0
|
||||||
|
private val KEY = TileServiceKey(TEST_COMPONENT, TEST_USER)
|
||||||
|
|
||||||
|
private const val TEST_STATE = Tile.STATE_INACTIVE
|
||||||
|
private const val TEST_LABEL = "test_label"
|
||||||
|
private const val TEST_SUBTITLE = "test_subtitle"
|
||||||
|
private const val TEST_CONTENT_DESCRIPTION = "test_content_description"
|
||||||
|
private const val TEST_STATE_DESCRIPTION = "test_state_description"
|
||||||
|
|
||||||
|
private fun Tile.isEqualTo(other: Tile): Boolean {
|
||||||
|
return state == other.state &&
|
||||||
|
label == other.label &&
|
||||||
|
subtitle == other.subtitle &&
|
||||||
|
contentDescription == other.contentDescription &&
|
||||||
|
stateDescription == other.stateDescription
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private lateinit var mockContext: Context
|
||||||
|
@Mock
|
||||||
|
private lateinit var sharedPreferences: SharedPreferences
|
||||||
|
@Mock(answer = Answers.RETURNS_SELF)
|
||||||
|
private lateinit var editor: SharedPreferences.Editor
|
||||||
|
private lateinit var tile: Tile
|
||||||
|
private lateinit var customTileStatePersister: CustomTileStatePersister
|
||||||
|
|
||||||
|
@Captor
|
||||||
|
private lateinit var stringCaptor: ArgumentCaptor<String>
|
||||||
|
|
||||||
|
@Before
|
||||||
|
fun setUp() {
|
||||||
|
MockitoAnnotations.initMocks(this)
|
||||||
|
`when`(mockContext.getSharedPreferences(anyString(), anyInt()))
|
||||||
|
.thenReturn(sharedPreferences)
|
||||||
|
`when`(sharedPreferences.edit()).thenReturn(editor)
|
||||||
|
|
||||||
|
tile = Tile()
|
||||||
|
customTileStatePersister = CustomTileStatePersister(mockContext)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testWriteState() {
|
||||||
|
tile.apply {
|
||||||
|
state = TEST_STATE
|
||||||
|
label = TEST_LABEL
|
||||||
|
subtitle = TEST_SUBTITLE
|
||||||
|
contentDescription = TEST_CONTENT_DESCRIPTION
|
||||||
|
stateDescription = TEST_STATE_DESCRIPTION
|
||||||
|
}
|
||||||
|
|
||||||
|
customTileStatePersister.persistState(KEY, tile)
|
||||||
|
|
||||||
|
verify(editor).putString(eq(KEY.toString()), capture(stringCaptor))
|
||||||
|
|
||||||
|
assertThat(tile.isEqualTo(readTileFromString(stringCaptor.value))).isTrue()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testReadState() {
|
||||||
|
tile.apply {
|
||||||
|
state = TEST_STATE
|
||||||
|
label = TEST_LABEL
|
||||||
|
subtitle = TEST_SUBTITLE
|
||||||
|
contentDescription = TEST_CONTENT_DESCRIPTION
|
||||||
|
stateDescription = TEST_STATE_DESCRIPTION
|
||||||
|
}
|
||||||
|
|
||||||
|
`when`(sharedPreferences.getString(eq(KEY.toString()), any()))
|
||||||
|
.thenReturn(writeToString(tile))
|
||||||
|
|
||||||
|
assertThat(tile.isEqualTo(customTileStatePersister.readState(KEY)!!)).isTrue()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testReadStateDefault() {
|
||||||
|
`when`(sharedPreferences.getString(any(), any())).thenAnswer {
|
||||||
|
it.getArgument(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
assertThat(customTileStatePersister.readState(KEY)).isNull()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testStoreNulls() {
|
||||||
|
assertThat(tile.label).isNull()
|
||||||
|
|
||||||
|
customTileStatePersister.persistState(KEY, tile)
|
||||||
|
|
||||||
|
verify(editor).putString(eq(KEY.toString()), capture(stringCaptor))
|
||||||
|
|
||||||
|
assertThat(readTileFromString(stringCaptor.value).label).isNull()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testReadNulls() {
|
||||||
|
assertThat(tile.label).isNull()
|
||||||
|
|
||||||
|
`when`(sharedPreferences.getString(eq(KEY.toString()), any()))
|
||||||
|
.thenReturn(writeToString(tile))
|
||||||
|
|
||||||
|
assertThat(customTileStatePersister.readState(KEY)!!.label).isNull()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testRemoveState() {
|
||||||
|
customTileStatePersister.removeState(KEY)
|
||||||
|
|
||||||
|
verify(editor).remove(KEY.toString())
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -38,6 +38,7 @@ import com.android.systemui.plugins.qs.QSTile
|
|||||||
import com.android.systemui.plugins.statusbar.StatusBarStateController
|
import com.android.systemui.plugins.statusbar.StatusBarStateController
|
||||||
import com.android.systemui.qs.QSHost
|
import com.android.systemui.qs.QSHost
|
||||||
import com.android.systemui.qs.logging.QSLogger
|
import com.android.systemui.qs.logging.QSLogger
|
||||||
|
import com.android.systemui.util.mockito.any
|
||||||
import org.junit.Assert.assertEquals
|
import org.junit.Assert.assertEquals
|
||||||
import org.junit.Assert.assertFalse
|
import org.junit.Assert.assertFalse
|
||||||
import org.junit.Assert.assertTrue
|
import org.junit.Assert.assertTrue
|
||||||
@@ -48,8 +49,9 @@ import org.mockito.ArgumentMatchers.anyInt
|
|||||||
import org.mockito.ArgumentMatchers.anyString
|
import org.mockito.ArgumentMatchers.anyString
|
||||||
import org.mockito.Mock
|
import org.mockito.Mock
|
||||||
import org.mockito.Mockito.`when`
|
import org.mockito.Mockito.`when`
|
||||||
import org.mockito.Mockito.any
|
|
||||||
import org.mockito.Mockito.mock
|
import org.mockito.Mockito.mock
|
||||||
|
import org.mockito.Mockito.never
|
||||||
|
import org.mockito.Mockito.verify
|
||||||
import org.mockito.MockitoAnnotations
|
import org.mockito.MockitoAnnotations
|
||||||
|
|
||||||
@SmallTest
|
@SmallTest
|
||||||
@@ -76,6 +78,7 @@ class CustomTileTest : SysuiTestCase() {
|
|||||||
@Mock private lateinit var packageManager: PackageManager
|
@Mock private lateinit var packageManager: PackageManager
|
||||||
@Mock private lateinit var applicationInfo: ApplicationInfo
|
@Mock private lateinit var applicationInfo: ApplicationInfo
|
||||||
@Mock private lateinit var serviceInfo: ServiceInfo
|
@Mock private lateinit var serviceInfo: ServiceInfo
|
||||||
|
@Mock private lateinit var customTileStatePersister: CustomTileStatePersister
|
||||||
|
|
||||||
private lateinit var customTile: CustomTile
|
private lateinit var customTile: CustomTile
|
||||||
private lateinit var testableLooper: TestableLooper
|
private lateinit var testableLooper: TestableLooper
|
||||||
@@ -108,10 +111,13 @@ class CustomTileTest : SysuiTestCase() {
|
|||||||
metricsLogger,
|
metricsLogger,
|
||||||
statusBarStateController,
|
statusBarStateController,
|
||||||
activityStarter,
|
activityStarter,
|
||||||
qsLogger
|
qsLogger,
|
||||||
|
customTileStatePersister
|
||||||
)
|
)
|
||||||
|
|
||||||
customTile = CustomTile.create(customTileBuilder, TILE_SPEC, mContext)
|
customTile = CustomTile.create(customTileBuilder, TILE_SPEC, mContext)
|
||||||
|
customTile.initialize()
|
||||||
|
testableLooper.processAllMessages()
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -123,6 +129,8 @@ class CustomTileTest : SysuiTestCase() {
|
|||||||
`when`(userContext.userId).thenReturn(10)
|
`when`(userContext.userId).thenReturn(10)
|
||||||
|
|
||||||
val tile = CustomTile.create(customTileBuilder, TILE_SPEC, userContext)
|
val tile = CustomTile.create(customTileBuilder, TILE_SPEC, userContext)
|
||||||
|
tile.initialize()
|
||||||
|
testableLooper.processAllMessages()
|
||||||
|
|
||||||
assertEquals(10, tile.user)
|
assertEquals(10, tile.user)
|
||||||
}
|
}
|
||||||
@@ -131,6 +139,8 @@ class CustomTileTest : SysuiTestCase() {
|
|||||||
fun testToggleableTileHasBooleanState() {
|
fun testToggleableTileHasBooleanState() {
|
||||||
`when`(tileServiceManager.isToggleableTile).thenReturn(true)
|
`when`(tileServiceManager.isToggleableTile).thenReturn(true)
|
||||||
customTile = CustomTile.create(customTileBuilder, TILE_SPEC, mContext)
|
customTile = CustomTile.create(customTileBuilder, TILE_SPEC, mContext)
|
||||||
|
customTile.initialize()
|
||||||
|
testableLooper.processAllMessages()
|
||||||
|
|
||||||
assertTrue(customTile.state is QSTile.BooleanState)
|
assertTrue(customTile.state is QSTile.BooleanState)
|
||||||
assertTrue(customTile.newTileState() is QSTile.BooleanState)
|
assertTrue(customTile.newTileState() is QSTile.BooleanState)
|
||||||
@@ -146,6 +156,9 @@ class CustomTileTest : SysuiTestCase() {
|
|||||||
fun testValueUpdatedInBooleanTile() {
|
fun testValueUpdatedInBooleanTile() {
|
||||||
`when`(tileServiceManager.isToggleableTile).thenReturn(true)
|
`when`(tileServiceManager.isToggleableTile).thenReturn(true)
|
||||||
customTile = CustomTile.create(customTileBuilder, TILE_SPEC, mContext)
|
customTile = CustomTile.create(customTileBuilder, TILE_SPEC, mContext)
|
||||||
|
customTile.initialize()
|
||||||
|
testableLooper.processAllMessages()
|
||||||
|
|
||||||
customTile.qsTile.icon = mock(Icon::class.java)
|
customTile.qsTile.icon = mock(Icon::class.java)
|
||||||
`when`(customTile.qsTile.icon.loadDrawable(any(Context::class.java)))
|
`when`(customTile.qsTile.icon.loadDrawable(any(Context::class.java)))
|
||||||
.thenReturn(mock(Drawable::class.java))
|
.thenReturn(mock(Drawable::class.java))
|
||||||
@@ -173,4 +186,88 @@ class CustomTileTest : SysuiTestCase() {
|
|||||||
.thenReturn(null)
|
.thenReturn(null)
|
||||||
customTile.handleUpdateState(customTile.newTileState(), null)
|
customTile.handleUpdateState(customTile.newTileState(), null)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testNoLoadStateTileNotActive() {
|
||||||
|
// Not active by default
|
||||||
|
testableLooper.processAllMessages()
|
||||||
|
|
||||||
|
verify(customTileStatePersister, never()).readState(any())
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testNoPersistedStateTileNotActive() {
|
||||||
|
// Not active by default
|
||||||
|
val t = Tile().apply {
|
||||||
|
state = Tile.STATE_INACTIVE
|
||||||
|
}
|
||||||
|
customTile.updateTileState(t)
|
||||||
|
testableLooper.processAllMessages()
|
||||||
|
|
||||||
|
verify(customTileStatePersister, never()).persistState(any(), any())
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testPersistedStateRetrieved() {
|
||||||
|
val state = Tile.STATE_INACTIVE
|
||||||
|
val label = "test_label"
|
||||||
|
val subtitle = "test_subtitle"
|
||||||
|
val contentDescription = "test_content_description"
|
||||||
|
val stateDescription = "test_state_description"
|
||||||
|
|
||||||
|
val t = Tile().apply {
|
||||||
|
this.state = state
|
||||||
|
this.label = label
|
||||||
|
this.subtitle = subtitle
|
||||||
|
this.contentDescription = contentDescription
|
||||||
|
this.stateDescription = stateDescription
|
||||||
|
}
|
||||||
|
`when`(tileServiceManager.isActiveTile).thenReturn(true)
|
||||||
|
`when`(customTileStatePersister
|
||||||
|
.readState(TileServiceKey(componentName, customTile.user))).thenReturn(t)
|
||||||
|
val tile = CustomTile.create(customTileBuilder, TILE_SPEC, mContext)
|
||||||
|
tile.initialize()
|
||||||
|
testableLooper.processAllMessages()
|
||||||
|
|
||||||
|
// Make sure we have an icon in the tile because we don't have a default icon
|
||||||
|
// This should not be overridden by the retrieved tile that has null icon.
|
||||||
|
tile.qsTile.icon = mock(Icon::class.java)
|
||||||
|
`when`(tile.qsTile.icon.loadDrawable(any(Context::class.java)))
|
||||||
|
.thenReturn(mock(Drawable::class.java))
|
||||||
|
|
||||||
|
tile.refreshState()
|
||||||
|
|
||||||
|
testableLooper.processAllMessages()
|
||||||
|
|
||||||
|
val tileState = tile.state
|
||||||
|
|
||||||
|
assertEquals(state, tileState.state)
|
||||||
|
assertEquals(label, tileState.label)
|
||||||
|
assertEquals(subtitle, tileState.secondaryLabel)
|
||||||
|
assertEquals(contentDescription, tileState.contentDescription)
|
||||||
|
assertEquals(stateDescription, tileState.stateDescription)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testStoreStateOnChange() {
|
||||||
|
val t = Tile().apply {
|
||||||
|
state = Tile.STATE_INACTIVE
|
||||||
|
label = "test_label"
|
||||||
|
subtitle = "test_subtitle"
|
||||||
|
contentDescription = "test_content_description"
|
||||||
|
stateDescription = "test_state_description"
|
||||||
|
}
|
||||||
|
`when`(tileServiceManager.isActiveTile).thenReturn(true)
|
||||||
|
|
||||||
|
val tile = CustomTile.create(customTileBuilder, TILE_SPEC, mContext)
|
||||||
|
tile.initialize()
|
||||||
|
testableLooper.processAllMessages()
|
||||||
|
|
||||||
|
tile.updateTileState(t)
|
||||||
|
|
||||||
|
testableLooper.processAllMessages()
|
||||||
|
|
||||||
|
verify(customTileStatePersister)
|
||||||
|
.persistState(TileServiceKey(componentName, customTile.user), t)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -118,7 +118,8 @@ public class TileServicesTest extends SysuiTestCase {
|
|||||||
mQSLogger,
|
mQSLogger,
|
||||||
mUiEventLogger,
|
mUiEventLogger,
|
||||||
mUserTracker,
|
mUserTracker,
|
||||||
mSecureSettings);
|
mSecureSettings,
|
||||||
|
mock(CustomTileStatePersister.class));
|
||||||
mTileService = new TestTileServices(host, Looper.getMainLooper(), mBroadcastDispatcher,
|
mTileService = new TestTileServices(host, Looper.getMainLooper(), mBroadcastDispatcher,
|
||||||
mUserTracker);
|
mUserTracker);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -121,6 +121,9 @@ public class QSTileImplTest extends SysuiTestCase {
|
|||||||
|
|
||||||
mTile = new TileImpl(mHost, mTestableLooper.getLooper(), mainHandler, mFalsingManager,
|
mTile = new TileImpl(mHost, mTestableLooper.getLooper(), mainHandler, mFalsingManager,
|
||||||
mMetricsLogger, mStatusBarStateController, mActivityStarter, mQsLogger);
|
mMetricsLogger, mStatusBarStateController, mActivityStarter, mQsLogger);
|
||||||
|
mTile.initialize();
|
||||||
|
mTestableLooper.processAllMessages();
|
||||||
|
|
||||||
mTile.setTileSpec(SPEC);
|
mTile.setTileSpec(SPEC);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -80,6 +80,8 @@ class AlarmTileTest : SysuiTestCase() {
|
|||||||
nextAlarmController
|
nextAlarmController
|
||||||
)
|
)
|
||||||
|
|
||||||
|
tile.initialize()
|
||||||
|
|
||||||
verify(nextAlarmController).observe(eq(tile), capture(callbackCaptor))
|
verify(nextAlarmController).observe(eq(tile), capture(callbackCaptor))
|
||||||
tile.refreshState()
|
tile.refreshState()
|
||||||
testableLooper.processAllMessages()
|
testableLooper.processAllMessages()
|
||||||
|
|||||||
@@ -87,6 +87,9 @@ class BatterySaverTileTest : SysuiTestCase() {
|
|||||||
qsLogger,
|
qsLogger,
|
||||||
batteryController,
|
batteryController,
|
||||||
secureSettings)
|
secureSettings)
|
||||||
|
|
||||||
|
tile.initialize()
|
||||||
|
testableLooper.processAllMessages()
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
@@ -112,11 +112,14 @@ public class CastTileTest extends SysuiTestCase {
|
|||||||
mNetworkController,
|
mNetworkController,
|
||||||
mHotspotController
|
mHotspotController
|
||||||
);
|
);
|
||||||
|
mCastTile.initialize();
|
||||||
|
|
||||||
// We are not setting the mocks to listening, so we trigger a first refresh state to
|
// We are not setting the mocks to listening, so we trigger a first refresh state to
|
||||||
// set the initial state
|
// set the initial state
|
||||||
mCastTile.refreshState();
|
mCastTile.refreshState();
|
||||||
|
|
||||||
|
mTestableLooper.processAllMessages();
|
||||||
|
|
||||||
mCastTile.handleSetListening(true);
|
mCastTile.handleSetListening(true);
|
||||||
ArgumentCaptor<NetworkController.SignalCallback> signalCallbackArgumentCaptor =
|
ArgumentCaptor<NetworkController.SignalCallback> signalCallbackArgumentCaptor =
|
||||||
ArgumentCaptor.forClass(NetworkController.SignalCallback.class);
|
ArgumentCaptor.forClass(NetworkController.SignalCallback.class);
|
||||||
|
|||||||
@@ -378,7 +378,10 @@ class DeviceControlsTileTest : SysuiTestCase() {
|
|||||||
qsLogger,
|
qsLogger,
|
||||||
controlsComponent,
|
controlsComponent,
|
||||||
keyguardStateController
|
keyguardStateController
|
||||||
)
|
).also {
|
||||||
|
it.initialize()
|
||||||
|
testableLooper.processAllMessages()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -92,6 +92,9 @@ public class NfcTileTest extends SysuiTestCase {
|
|||||||
mQSLogger,
|
mQSLogger,
|
||||||
mBroadcastDispatcher
|
mBroadcastDispatcher
|
||||||
);
|
);
|
||||||
|
|
||||||
|
mNfcTile.initialize();
|
||||||
|
mTestableLooper.processAllMessages();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
@@ -155,6 +155,9 @@ public class QuickAccessWalletTileTest extends SysuiTestCase {
|
|||||||
mPackageManager,
|
mPackageManager,
|
||||||
mSecureSettings,
|
mSecureSettings,
|
||||||
mController);
|
mController);
|
||||||
|
|
||||||
|
mTile.initialize();
|
||||||
|
mTestableLooper.processAllMessages();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
@@ -89,6 +89,9 @@ public class ReduceBrightColorsTileTest extends SysuiTestCase {
|
|||||||
mActivityStarter,
|
mActivityStarter,
|
||||||
mQSLogger
|
mQSLogger
|
||||||
);
|
);
|
||||||
|
|
||||||
|
mTile.initialize();
|
||||||
|
mTestableLooper.processAllMessages();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
@@ -91,6 +91,9 @@ public class ScreenRecordTileTest extends SysuiTestCase {
|
|||||||
mController,
|
mController,
|
||||||
mKeyguardDismissUtil
|
mKeyguardDismissUtil
|
||||||
);
|
);
|
||||||
|
|
||||||
|
mTile.initialize();
|
||||||
|
mTestableLooper.processAllMessages();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test that the tile is inactive and labeled correctly when the controller is neither starting
|
// Test that the tile is inactive and labeled correctly when the controller is neither starting
|
||||||
|
|||||||
Reference in New Issue
Block a user