Merge changes from topic "race_condition_tm-d1-dev" into tm-d1-dev
* changes: Reduce blocking calls to Settings in main thread Fix race condition in QSTileHost
This commit is contained in:
committed by
Android (Google) Code Review
commit
f247c1b1d5
@@ -19,8 +19,6 @@ import android.content.Context;
|
|||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.res.Resources;
|
import android.content.res.Resources;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Handler;
|
|
||||||
import android.os.Looper;
|
|
||||||
import android.os.UserHandle;
|
import android.os.UserHandle;
|
||||||
import android.os.UserManager;
|
import android.os.UserManager;
|
||||||
import android.provider.Settings.Secure;
|
import android.provider.Settings.Secure;
|
||||||
@@ -28,6 +26,7 @@ import android.text.TextUtils;
|
|||||||
import android.util.ArraySet;
|
import android.util.ArraySet;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
|
import androidx.annotation.MainThread;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
import com.android.internal.logging.InstanceId;
|
import com.android.internal.logging.InstanceId;
|
||||||
@@ -35,9 +34,7 @@ import com.android.internal.logging.InstanceIdSequence;
|
|||||||
import com.android.internal.logging.UiEventLogger;
|
import com.android.internal.logging.UiEventLogger;
|
||||||
import com.android.systemui.Dumpable;
|
import com.android.systemui.Dumpable;
|
||||||
import com.android.systemui.R;
|
import com.android.systemui.R;
|
||||||
import com.android.systemui.broadcast.BroadcastDispatcher;
|
|
||||||
import com.android.systemui.dagger.SysUISingleton;
|
import com.android.systemui.dagger.SysUISingleton;
|
||||||
import com.android.systemui.dagger.qualifiers.Background;
|
|
||||||
import com.android.systemui.dagger.qualifiers.Main;
|
import com.android.systemui.dagger.qualifiers.Main;
|
||||||
import com.android.systemui.dump.DumpManager;
|
import com.android.systemui.dump.DumpManager;
|
||||||
import com.android.systemui.plugins.PluginListener;
|
import com.android.systemui.plugins.PluginListener;
|
||||||
@@ -68,12 +65,20 @@ import java.util.LinkedHashMap;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.Executor;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javax.inject.Provider;
|
import javax.inject.Provider;
|
||||||
|
|
||||||
/** Platform implementation of the quick settings tile host **/
|
/** Platform implementation of the quick settings tile host
|
||||||
|
*
|
||||||
|
* This class keeps track of the set of current tiles and is the in memory source of truth
|
||||||
|
* (ground truth is kept in {@link Secure#QS_TILES}). When the ground truth changes,
|
||||||
|
* {@link #onTuningChanged} will be called and the tiles will be re-created as needed.
|
||||||
|
*
|
||||||
|
* This class also provides the interface for adding/removing/changing tiles.
|
||||||
|
*/
|
||||||
@SysUISingleton
|
@SysUISingleton
|
||||||
public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, Dumpable {
|
public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, Dumpable {
|
||||||
private static final String TAG = "QSTileHost";
|
private static final String TAG = "QSTileHost";
|
||||||
@@ -89,11 +94,11 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D
|
|||||||
private final TunerService mTunerService;
|
private final TunerService mTunerService;
|
||||||
private final PluginManager mPluginManager;
|
private final PluginManager mPluginManager;
|
||||||
private final DumpManager mDumpManager;
|
private final DumpManager mDumpManager;
|
||||||
private final BroadcastDispatcher mBroadcastDispatcher;
|
|
||||||
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 CustomTileStatePersister mCustomTileStatePersister;
|
||||||
|
private final Executor mMainExecutor;
|
||||||
|
|
||||||
private final List<Callback> mCallbacks = new ArrayList<>();
|
private final List<Callback> mCallbacks = new ArrayList<>();
|
||||||
@Nullable
|
@Nullable
|
||||||
@@ -105,6 +110,11 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D
|
|||||||
private Context mUserContext;
|
private Context mUserContext;
|
||||||
private UserTracker mUserTracker;
|
private UserTracker mUserTracker;
|
||||||
private SecureSettings mSecureSettings;
|
private SecureSettings mSecureSettings;
|
||||||
|
// Keep track of whether mTilesList contains the same information as the Settings value.
|
||||||
|
// This is a performance optimization to reduce the number of blocking calls to Settings from
|
||||||
|
// main thread.
|
||||||
|
// This is enforced by only cleaning the flag at the end of a successful run of #onTuningChanged
|
||||||
|
private boolean mTilesListDirty = true;
|
||||||
|
|
||||||
private final TileServiceRequestController mTileServiceRequestController;
|
private final TileServiceRequestController mTileServiceRequestController;
|
||||||
private TileLifecycleManager.Factory mTileLifeCycleManagerFactory;
|
private TileLifecycleManager.Factory mTileLifeCycleManagerFactory;
|
||||||
@@ -113,13 +123,11 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D
|
|||||||
public QSTileHost(Context context,
|
public QSTileHost(Context context,
|
||||||
StatusBarIconController iconController,
|
StatusBarIconController iconController,
|
||||||
QSFactory defaultFactory,
|
QSFactory defaultFactory,
|
||||||
@Main Handler mainHandler,
|
@Main Executor mainExecutor,
|
||||||
@Background Looper bgLooper,
|
|
||||||
PluginManager pluginManager,
|
PluginManager pluginManager,
|
||||||
TunerService tunerService,
|
TunerService tunerService,
|
||||||
Provider<AutoTileManager> autoTiles,
|
Provider<AutoTileManager> autoTiles,
|
||||||
DumpManager dumpManager,
|
DumpManager dumpManager,
|
||||||
BroadcastDispatcher broadcastDispatcher,
|
|
||||||
Optional<CentralSurfaces> centralSurfacesOptional,
|
Optional<CentralSurfaces> centralSurfacesOptional,
|
||||||
QSLogger qsLogger,
|
QSLogger qsLogger,
|
||||||
UiEventLogger uiEventLogger,
|
UiEventLogger uiEventLogger,
|
||||||
@@ -137,7 +145,7 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D
|
|||||||
mDumpManager = dumpManager;
|
mDumpManager = dumpManager;
|
||||||
mQSLogger = qsLogger;
|
mQSLogger = qsLogger;
|
||||||
mUiEventLogger = uiEventLogger;
|
mUiEventLogger = uiEventLogger;
|
||||||
mBroadcastDispatcher = broadcastDispatcher;
|
mMainExecutor = mainExecutor;
|
||||||
mTileServiceRequestController = tileServiceRequestControllerBuilder.create(this);
|
mTileServiceRequestController = tileServiceRequestControllerBuilder.create(this);
|
||||||
mTileLifeCycleManagerFactory = tileLifecycleManagerFactory;
|
mTileLifeCycleManagerFactory = tileLifecycleManagerFactory;
|
||||||
|
|
||||||
@@ -151,7 +159,7 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D
|
|||||||
mSecureSettings = secureSettings;
|
mSecureSettings = secureSettings;
|
||||||
mCustomTileStatePersister = customTileStatePersister;
|
mCustomTileStatePersister = customTileStatePersister;
|
||||||
|
|
||||||
mainHandler.post(() -> {
|
mainExecutor.execute(() -> {
|
||||||
// This is technically a hack to avoid circular dependency of
|
// This is technically a hack to avoid circular dependency of
|
||||||
// QSTileHost -> XXXTile -> QSTileHost. Posting ensures creation
|
// QSTileHost -> XXXTile -> QSTileHost. Posting ensures creation
|
||||||
// finishes before creating any tiles.
|
// finishes before creating any tiles.
|
||||||
@@ -258,6 +266,33 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D
|
|||||||
return mTileSpecs.indexOf(spec);
|
return mTileSpecs.indexOf(spec);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whenever the Secure Setting keeping track of the current tiles changes (or upon start) this
|
||||||
|
* will be called with the new value of the setting.
|
||||||
|
*
|
||||||
|
* This method will do the following:
|
||||||
|
* <ol>
|
||||||
|
* <li>Destroy any existing tile that's not one of the current tiles (in the setting)</li>
|
||||||
|
* <li>Create new tiles for those that don't already exist. If this tiles end up being
|
||||||
|
* not available, they'll also be destroyed.</li>
|
||||||
|
* <li>Save the resolved list of tiles (current tiles that are available) into the setting.
|
||||||
|
* This means that after this call ends, the tiles in the Setting, {@link #mTileSpecs},
|
||||||
|
* and visible tiles ({@link #mTiles}) must match.
|
||||||
|
* </li>
|
||||||
|
* </ol>
|
||||||
|
*
|
||||||
|
* Additionally, if the user has changed, it'll do the following:
|
||||||
|
* <ul>
|
||||||
|
* <li>Change the user for SystemUI tiles: {@link QSTile#userSwitch}.</li>
|
||||||
|
* <li>Destroy any {@link CustomTile} and recreate it for the new user.</li>
|
||||||
|
* </ul>
|
||||||
|
*
|
||||||
|
* This happens in main thread as {@link com.android.systemui.tuner.TunerServiceImpl} dispatches
|
||||||
|
* in main thread.
|
||||||
|
*
|
||||||
|
* @see QSTile#isAvailable
|
||||||
|
*/
|
||||||
|
@MainThread
|
||||||
@Override
|
@Override
|
||||||
public void onTuningChanged(String key, String newValue) {
|
public void onTuningChanged(String key, String newValue) {
|
||||||
if (!TILES_SETTING.equals(key)) {
|
if (!TILES_SETTING.equals(key)) {
|
||||||
@@ -330,34 +365,45 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D
|
|||||||
mCurrentUser = currentUser;
|
mCurrentUser = currentUser;
|
||||||
List<String> currentSpecs = new ArrayList<>(mTileSpecs);
|
List<String> currentSpecs = new ArrayList<>(mTileSpecs);
|
||||||
mTileSpecs.clear();
|
mTileSpecs.clear();
|
||||||
mTileSpecs.addAll(tileSpecs);
|
mTileSpecs.addAll(newTiles.keySet()); // Only add the valid (available) tiles.
|
||||||
mTiles.clear();
|
mTiles.clear();
|
||||||
mTiles.putAll(newTiles);
|
mTiles.putAll(newTiles);
|
||||||
if (newTiles.isEmpty() && !tileSpecs.isEmpty()) {
|
if (newTiles.isEmpty() && !tileSpecs.isEmpty()) {
|
||||||
// If we didn't manage to create any tiles, set it to empty (default)
|
// If we didn't manage to create any tiles, set it to empty (default)
|
||||||
Log.d(TAG, "No valid tiles on tuning changed. Setting to default.");
|
Log.d(TAG, "No valid tiles on tuning changed. Setting to default.");
|
||||||
changeTiles(currentSpecs, loadTileSpecs(mContext, ""));
|
changeTilesByUser(currentSpecs, loadTileSpecs(mContext, ""));
|
||||||
} else {
|
} else {
|
||||||
|
String resolvedTiles = TextUtils.join(",", mTileSpecs);
|
||||||
|
if (!resolvedTiles.equals(newValue)) {
|
||||||
|
// If the resolved tiles (those we actually ended up with) are different than
|
||||||
|
// the ones that are in the setting, update the Setting.
|
||||||
|
saveTilesToSettings(mTileSpecs);
|
||||||
|
}
|
||||||
|
mTilesListDirty = false;
|
||||||
for (int i = 0; i < mCallbacks.size(); i++) {
|
for (int i = 0; i < mCallbacks.size(); i++) {
|
||||||
mCallbacks.get(i).onTilesChanged();
|
mCallbacks.get(i).onTilesChanged();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Only use with [CustomTile] if the tile doesn't exist anymore (and therefore doesn't need
|
||||||
|
* its lifecycle terminated).
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void removeTile(String spec) {
|
public void removeTile(String spec) {
|
||||||
changeTileSpecs(tileSpecs-> tileSpecs.remove(spec));
|
mMainExecutor.execute(() -> changeTileSpecs(tileSpecs-> tileSpecs.remove(spec)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove many tiles at once.
|
* Remove many tiles at once.
|
||||||
*
|
*
|
||||||
* It will only save to settings once (as opposed to {@link QSTileHost#removeTile} called
|
* It will only save to settings once (as opposed to {@link QSTileHost#removeTileByUser} called
|
||||||
* multiple times).
|
* multiple times).
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void removeTiles(Collection<String> specs) {
|
public void removeTiles(Collection<String> specs) {
|
||||||
changeTileSpecs(tileSpecs -> tileSpecs.removeAll(specs));
|
mMainExecutor.execute(() -> changeTileSpecs(tileSpecs -> tileSpecs.removeAll(specs)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -381,31 +427,41 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D
|
|||||||
* @param requestPosition -1 for end, 0 for beginning, or X for insertion at position X
|
* @param requestPosition -1 for end, 0 for beginning, or X for insertion at position X
|
||||||
*/
|
*/
|
||||||
public void addTile(String spec, int requestPosition) {
|
public void addTile(String spec, int requestPosition) {
|
||||||
if (spec.equals("work")) Log.wtfStack(TAG, "Adding work tile");
|
mMainExecutor.execute(() ->
|
||||||
changeTileSpecs(tileSpecs -> {
|
changeTileSpecs(tileSpecs -> {
|
||||||
if (tileSpecs.contains(spec)) return false;
|
if (tileSpecs.contains(spec)) return false;
|
||||||
|
|
||||||
int size = tileSpecs.size();
|
int size = tileSpecs.size();
|
||||||
if (requestPosition == POSITION_AT_END || requestPosition >= size) {
|
if (requestPosition == POSITION_AT_END || requestPosition >= size) {
|
||||||
tileSpecs.add(spec);
|
tileSpecs.add(spec);
|
||||||
} else {
|
} else {
|
||||||
tileSpecs.add(requestPosition, spec);
|
tileSpecs.add(requestPosition, spec);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
});
|
})
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void saveTilesToSettings(List<String> tileSpecs) {
|
|
||||||
if (tileSpecs.contains("work")) Log.wtfStack(TAG, "Saving work tile");
|
// When calling this, you may want to modify mTilesListDirty accordingly.
|
||||||
|
@MainThread
|
||||||
|
private void saveTilesToSettings(List<String> tileSpecs) {
|
||||||
mSecureSettings.putStringForUser(TILES_SETTING, TextUtils.join(",", tileSpecs),
|
mSecureSettings.putStringForUser(TILES_SETTING, TextUtils.join(",", tileSpecs),
|
||||||
null /* tag */, false /* default */, mCurrentUser,
|
null /* tag */, false /* default */, mCurrentUser,
|
||||||
true /* overrideable by restore */);
|
true /* overrideable by restore */);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@MainThread
|
||||||
private void changeTileSpecs(Predicate<List<String>> changeFunction) {
|
private void changeTileSpecs(Predicate<List<String>> changeFunction) {
|
||||||
final String setting = mSecureSettings.getStringForUser(TILES_SETTING, mCurrentUser);
|
final List<String> tileSpecs;
|
||||||
final List<String> tileSpecs = loadTileSpecs(mContext, setting);
|
if (!mTilesListDirty) {
|
||||||
|
tileSpecs = new ArrayList<>(mTileSpecs);
|
||||||
|
} else {
|
||||||
|
tileSpecs = loadTileSpecs(mContext,
|
||||||
|
mSecureSettings.getStringForUser(TILES_SETTING, mCurrentUser));
|
||||||
|
}
|
||||||
if (changeFunction.test(tileSpecs)) {
|
if (changeFunction.test(tileSpecs)) {
|
||||||
|
mTilesListDirty = true;
|
||||||
saveTilesToSettings(tileSpecs);
|
saveTilesToSettings(tileSpecs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -421,29 +477,32 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D
|
|||||||
*/
|
*/
|
||||||
public void addTile(ComponentName tile, boolean end) {
|
public void addTile(ComponentName tile, boolean end) {
|
||||||
String spec = CustomTile.toSpec(tile);
|
String spec = CustomTile.toSpec(tile);
|
||||||
if (!mTileSpecs.contains(spec)) {
|
addTile(spec, end ? POSITION_AT_END : 0);
|
||||||
List<String> newSpecs = new ArrayList<>(mTileSpecs);
|
|
||||||
if (end) {
|
|
||||||
newSpecs.add(spec);
|
|
||||||
} else {
|
|
||||||
newSpecs.add(0, spec);
|
|
||||||
}
|
|
||||||
changeTiles(mTileSpecs, newSpecs);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void removeTile(ComponentName tile) {
|
/**
|
||||||
List<String> newSpecs = new ArrayList<>(mTileSpecs);
|
* This will call through {@link #changeTilesByUser}. It should only be used when a tile is
|
||||||
newSpecs.remove(CustomTile.toSpec(tile));
|
* removed by a <b>user action</b> like {@code adb}.
|
||||||
changeTiles(mTileSpecs, newSpecs);
|
*/
|
||||||
|
public void removeTileByUser(ComponentName tile) {
|
||||||
|
mMainExecutor.execute(() -> {
|
||||||
|
List<String> newSpecs = new ArrayList<>(mTileSpecs);
|
||||||
|
if (newSpecs.remove(CustomTile.toSpec(tile))) {
|
||||||
|
changeTilesByUser(mTileSpecs, newSpecs);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Change the tiles triggered by the user editing.
|
* Change the tiles triggered by the user editing.
|
||||||
* <p>
|
* <p>
|
||||||
* This is not called on device start, or on user change.
|
* This is not called on device start, or on user change.
|
||||||
|
*
|
||||||
|
* {@link android.service.quicksettings.TileService#onTileRemoved} will be called for tiles
|
||||||
|
* that are removed.
|
||||||
*/
|
*/
|
||||||
public void changeTiles(List<String> previousTiles, List<String> newTiles) {
|
@MainThread
|
||||||
|
public void changeTilesByUser(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();
|
||||||
for (int i = 0; i < NP; i++) {
|
for (int i = 0; i < NP; i++) {
|
||||||
@@ -462,6 +521,7 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (DEBUG) Log.d(TAG, "saveCurrentTiles " + newTiles);
|
if (DEBUG) Log.d(TAG, "saveCurrentTiles " + newTiles);
|
||||||
|
mTilesListDirty = true;
|
||||||
saveTilesToSettings(newTiles);
|
saveTilesToSettings(newTiles);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -182,7 +182,7 @@ public class TileAdapter extends RecyclerView.Adapter<Holder> implements TileSta
|
|||||||
for (int i = 1; i < mTiles.size() && mTiles.get(i) != null; i++) {
|
for (int i = 1; i < mTiles.size() && mTiles.get(i) != null; i++) {
|
||||||
newSpecs.add(mTiles.get(i).spec);
|
newSpecs.add(mTiles.get(i).spec);
|
||||||
}
|
}
|
||||||
host.changeTiles(mCurrentSpecs, newSpecs);
|
host.changeTilesByUser(mCurrentSpecs, newSpecs);
|
||||||
mCurrentSpecs = newSpecs;
|
mCurrentSpecs = newSpecs;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -200,7 +200,7 @@ public class TileAdapter extends RecyclerView.Adapter<Holder> implements TileSta
|
|||||||
/** */
|
/** */
|
||||||
public void resetTileSpecs(List<String> specs) {
|
public void resetTileSpecs(List<String> specs) {
|
||||||
// Notify the host so the tiles get removed callbacks.
|
// Notify the host so the tiles get removed callbacks.
|
||||||
mHost.changeTiles(mCurrentSpecs, specs);
|
mHost.changeTilesByUser(mCurrentSpecs, specs);
|
||||||
setTileSpecs(specs);
|
setTileSpecs(specs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -289,7 +289,7 @@ public class TileServiceManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mServices.getHost().removeTile(component);
|
mServices.getHost().removeTile(CustomTile.toSpec(component));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -428,7 +428,7 @@ public class AutoTileManager implements UserAwareController {
|
|||||||
if (isSafetyCenterEnabled && !mAutoTracker.isAdded(mSafetySpec)) {
|
if (isSafetyCenterEnabled && !mAutoTracker.isAdded(mSafetySpec)) {
|
||||||
initSafetyTile();
|
initSafetyTile();
|
||||||
} else if (!isSafetyCenterEnabled && mAutoTracker.isAdded(mSafetySpec)) {
|
} else if (!isSafetyCenterEnabled && mAutoTracker.isAdded(mSafetySpec)) {
|
||||||
mHost.removeTile(CustomTile.getComponentFromSpec(mSafetySpec));
|
mHost.removeTile(mSafetySpec);
|
||||||
mHost.unmarkTileAsAutoAdded(mSafetySpec);
|
mHost.unmarkTileAsAutoAdded(mSafetySpec);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -187,7 +187,7 @@ public class CentralSurfacesCommandQueueCallbacks implements CommandQueue.Callba
|
|||||||
public void remQsTile(ComponentName tile) {
|
public void remQsTile(ComponentName tile) {
|
||||||
QSPanelController qsPanelController = mCentralSurfaces.getQSPanelController();
|
QSPanelController qsPanelController = mCentralSurfaces.getQSPanelController();
|
||||||
if (qsPanelController != null && qsPanelController.getHost() != null) {
|
if (qsPanelController != null && qsPanelController.getHost() != null) {
|
||||||
qsPanelController.getHost().removeTile(tile);
|
qsPanelController.getHost().removeTileByUser(tile);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -32,8 +32,6 @@ import android.app.Fragment;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Handler;
|
|
||||||
import android.os.Looper;
|
|
||||||
import android.testing.AndroidTestingRunner;
|
import android.testing.AndroidTestingRunner;
|
||||||
import android.testing.TestableLooper.RunWithLooper;
|
import android.testing.TestableLooper.RunWithLooper;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
@@ -42,36 +40,23 @@ import android.view.ViewGroup;
|
|||||||
|
|
||||||
import androidx.test.filters.SmallTest;
|
import androidx.test.filters.SmallTest;
|
||||||
|
|
||||||
import com.android.internal.logging.UiEventLogger;
|
|
||||||
import com.android.keyguard.BouncerPanelExpansionCalculator;
|
import com.android.keyguard.BouncerPanelExpansionCalculator;
|
||||||
import com.android.systemui.R;
|
import com.android.systemui.R;
|
||||||
import com.android.systemui.SysuiBaseFragmentTest;
|
import com.android.systemui.SysuiBaseFragmentTest;
|
||||||
import com.android.systemui.animation.ShadeInterpolation;
|
import com.android.systemui.animation.ShadeInterpolation;
|
||||||
import com.android.systemui.broadcast.BroadcastDispatcher;
|
|
||||||
import com.android.systemui.dump.DumpManager;
|
import com.android.systemui.dump.DumpManager;
|
||||||
import com.android.systemui.media.MediaHost;
|
import com.android.systemui.media.MediaHost;
|
||||||
import com.android.systemui.plugins.FalsingManager;
|
import com.android.systemui.plugins.FalsingManager;
|
||||||
import com.android.systemui.plugins.statusbar.StatusBarStateController;
|
import com.android.systemui.plugins.statusbar.StatusBarStateController;
|
||||||
import com.android.systemui.qs.customize.QSCustomizerController;
|
import com.android.systemui.qs.customize.QSCustomizerController;
|
||||||
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.external.TileLifecycleManager;
|
|
||||||
import com.android.systemui.qs.external.TileServiceRequestController;
|
import com.android.systemui.qs.external.TileServiceRequestController;
|
||||||
import com.android.systemui.qs.logging.QSLogger;
|
|
||||||
import com.android.systemui.qs.tileimpl.QSFactoryImpl;
|
|
||||||
import com.android.systemui.settings.UserTracker;
|
|
||||||
import com.android.systemui.shared.plugins.PluginManager;
|
|
||||||
import com.android.systemui.statusbar.CommandQueue;
|
import com.android.systemui.statusbar.CommandQueue;
|
||||||
import com.android.systemui.statusbar.StatusBarState;
|
import com.android.systemui.statusbar.StatusBarState;
|
||||||
import com.android.systemui.statusbar.phone.AutoTileManager;
|
|
||||||
import com.android.systemui.statusbar.phone.CentralSurfaces;
|
|
||||||
import com.android.systemui.statusbar.phone.KeyguardBypassController;
|
import com.android.systemui.statusbar.phone.KeyguardBypassController;
|
||||||
import com.android.systemui.statusbar.phone.StatusBarIconController;
|
|
||||||
import com.android.systemui.statusbar.policy.ConfigurationController;
|
import com.android.systemui.statusbar.policy.ConfigurationController;
|
||||||
import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler;
|
import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler;
|
||||||
import com.android.systemui.tuner.TunerService;
|
|
||||||
import com.android.systemui.util.animation.UniqueObjectHostView;
|
import com.android.systemui.util.animation.UniqueObjectHostView;
|
||||||
import com.android.systemui.util.settings.SecureSettings;
|
|
||||||
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
@@ -79,8 +64,6 @@ import org.junit.runner.RunWith;
|
|||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
import org.mockito.MockitoAnnotations;
|
import org.mockito.MockitoAnnotations;
|
||||||
|
|
||||||
import java.util.Optional;
|
|
||||||
|
|
||||||
@RunWith(AndroidTestingRunner.class)
|
@RunWith(AndroidTestingRunner.class)
|
||||||
@RunWithLooper(setAsMainLooper = true)
|
@RunWithLooper(setAsMainLooper = true)
|
||||||
@SmallTest
|
@SmallTest
|
||||||
@@ -125,34 +108,11 @@ public class QSFragmentTest extends SysuiBaseFragmentTest {
|
|||||||
mFragments.dispatchResume();
|
mFragments.dispatchResume();
|
||||||
processAllMessages();
|
processAllMessages();
|
||||||
|
|
||||||
QSTileHost host =
|
|
||||||
new QSTileHost(
|
|
||||||
mContext,
|
|
||||||
mock(StatusBarIconController.class),
|
|
||||||
mock(QSFactoryImpl.class),
|
|
||||||
new Handler(),
|
|
||||||
Looper.myLooper(),
|
|
||||||
mock(PluginManager.class),
|
|
||||||
mock(TunerService.class),
|
|
||||||
() -> mock(AutoTileManager.class),
|
|
||||||
mock(DumpManager.class),
|
|
||||||
mock(BroadcastDispatcher.class),
|
|
||||||
Optional.of(mock(CentralSurfaces.class)),
|
|
||||||
mock(QSLogger.class),
|
|
||||||
mock(UiEventLogger.class),
|
|
||||||
mock(UserTracker.class),
|
|
||||||
mock(SecureSettings.class),
|
|
||||||
mock(CustomTileStatePersister.class),
|
|
||||||
mTileServiceRequestControllerBuilder,
|
|
||||||
mock(TileLifecycleManager.Factory.class));
|
|
||||||
|
|
||||||
qs.setListening(true);
|
qs.setListening(true);
|
||||||
processAllMessages();
|
processAllMessages();
|
||||||
|
|
||||||
qs.setListening(false);
|
qs.setListening(false);
|
||||||
processAllMessages();
|
processAllMessages();
|
||||||
host.destroy();
|
|
||||||
processAllMessages();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
@@ -32,12 +32,11 @@ import static org.mockito.Mockito.when;
|
|||||||
import android.content.ComponentName;
|
import android.content.ComponentName;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
import android.database.ContentObserver;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
import android.os.UserHandle;
|
import android.os.UserHandle;
|
||||||
import android.testing.AndroidTestingRunner;
|
import android.testing.AndroidTestingRunner;
|
||||||
import android.testing.TestableLooper;
|
|
||||||
import android.testing.TestableLooper.RunWithLooper;
|
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
@@ -48,7 +47,6 @@ import com.android.internal.logging.UiEventLogger;
|
|||||||
import com.android.internal.util.CollectionUtils;
|
import com.android.internal.util.CollectionUtils;
|
||||||
import com.android.systemui.R;
|
import com.android.systemui.R;
|
||||||
import com.android.systemui.SysuiTestCase;
|
import com.android.systemui.SysuiTestCase;
|
||||||
import com.android.systemui.broadcast.BroadcastDispatcher;
|
|
||||||
import com.android.systemui.classifier.FalsingManagerFake;
|
import com.android.systemui.classifier.FalsingManagerFake;
|
||||||
import com.android.systemui.dump.DumpManager;
|
import com.android.systemui.dump.DumpManager;
|
||||||
import com.android.systemui.plugins.ActivityStarter;
|
import com.android.systemui.plugins.ActivityStarter;
|
||||||
@@ -68,8 +66,10 @@ import com.android.systemui.statusbar.phone.AutoTileManager;
|
|||||||
import com.android.systemui.statusbar.phone.CentralSurfaces;
|
import com.android.systemui.statusbar.phone.CentralSurfaces;
|
||||||
import com.android.systemui.statusbar.phone.StatusBarIconController;
|
import com.android.systemui.statusbar.phone.StatusBarIconController;
|
||||||
import com.android.systemui.tuner.TunerService;
|
import com.android.systemui.tuner.TunerService;
|
||||||
|
import com.android.systemui.util.concurrency.FakeExecutor;
|
||||||
import com.android.systemui.util.settings.FakeSettings;
|
import com.android.systemui.util.settings.FakeSettings;
|
||||||
import com.android.systemui.util.settings.SecureSettings;
|
import com.android.systemui.util.settings.SecureSettings;
|
||||||
|
import com.android.systemui.util.time.FakeSystemClock;
|
||||||
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
@@ -81,18 +81,19 @@ import java.io.PrintWriter;
|
|||||||
import java.io.StringWriter;
|
import java.io.StringWriter;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
import java.util.concurrent.Executor;
|
||||||
|
|
||||||
import javax.inject.Provider;
|
import javax.inject.Provider;
|
||||||
|
|
||||||
@RunWith(AndroidTestingRunner.class)
|
@RunWith(AndroidTestingRunner.class)
|
||||||
@SmallTest
|
@SmallTest
|
||||||
@RunWithLooper(setAsMainLooper = true)
|
|
||||||
public class QSTileHostTest extends SysuiTestCase {
|
public class QSTileHostTest extends SysuiTestCase {
|
||||||
|
|
||||||
private static String MOCK_STATE_STRING = "MockState";
|
private static String MOCK_STATE_STRING = "MockState";
|
||||||
private static ComponentName CUSTOM_TILE =
|
private static ComponentName CUSTOM_TILE =
|
||||||
ComponentName.unflattenFromString("TEST_PKG/.TEST_CLS");
|
ComponentName.unflattenFromString("TEST_PKG/.TEST_CLS");
|
||||||
private static final String CUSTOM_TILE_SPEC = CustomTile.toSpec(CUSTOM_TILE);
|
private static final String CUSTOM_TILE_SPEC = CustomTile.toSpec(CUSTOM_TILE);
|
||||||
|
private static final String SETTING = QSTileHost.TILES_SETTING;
|
||||||
|
|
||||||
@Mock
|
@Mock
|
||||||
private StatusBarIconController mIconController;
|
private StatusBarIconController mIconController;
|
||||||
@@ -107,8 +108,6 @@ public class QSTileHostTest extends SysuiTestCase {
|
|||||||
@Mock
|
@Mock
|
||||||
private DumpManager mDumpManager;
|
private DumpManager mDumpManager;
|
||||||
@Mock
|
@Mock
|
||||||
private BroadcastDispatcher mBroadcastDispatcher;
|
|
||||||
@Mock
|
|
||||||
private QSTile.State mMockState;
|
private QSTile.State mMockState;
|
||||||
@Mock
|
@Mock
|
||||||
private CentralSurfaces mCentralSurfaces;
|
private CentralSurfaces mCentralSurfaces;
|
||||||
@@ -132,31 +131,47 @@ public class QSTileHostTest extends SysuiTestCase {
|
|||||||
@Mock
|
@Mock
|
||||||
private TileLifecycleManager mTileLifecycleManager;
|
private TileLifecycleManager mTileLifecycleManager;
|
||||||
|
|
||||||
private Handler mHandler;
|
private FakeExecutor mMainExecutor;
|
||||||
private TestableLooper mLooper;
|
|
||||||
private QSTileHost mQSTileHost;
|
private QSTileHost mQSTileHost;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() {
|
public void setUp() {
|
||||||
MockitoAnnotations.initMocks(this);
|
MockitoAnnotations.initMocks(this);
|
||||||
mLooper = TestableLooper.get(this);
|
mMainExecutor = new FakeExecutor(new FakeSystemClock());
|
||||||
mHandler = new Handler(mLooper.getLooper());
|
|
||||||
when(mTileServiceRequestControllerBuilder.create(any()))
|
when(mTileServiceRequestControllerBuilder.create(any()))
|
||||||
.thenReturn(mTileServiceRequestController);
|
.thenReturn(mTileServiceRequestController);
|
||||||
when(mTileLifecycleManagerFactory.create(any(Intent.class), any(UserHandle.class)))
|
when(mTileLifecycleManagerFactory.create(any(Intent.class), any(UserHandle.class)))
|
||||||
.thenReturn(mTileLifecycleManager);
|
.thenReturn(mTileLifecycleManager);
|
||||||
|
|
||||||
mSecureSettings = new FakeSettings();
|
mSecureSettings = new FakeSettings();
|
||||||
mSecureSettings.putStringForUser(
|
saveSetting("");
|
||||||
QSTileHost.TILES_SETTING, "", "", false, mUserTracker.getUserId(), false);
|
mQSTileHost = new TestQSTileHost(mContext, mIconController, mDefaultFactory, mMainExecutor,
|
||||||
mQSTileHost = new TestQSTileHost(mContext, mIconController, mDefaultFactory, mHandler,
|
mPluginManager, mTunerService, mAutoTiles, mDumpManager, mCentralSurfaces,
|
||||||
mLooper.getLooper(), mPluginManager, mTunerService, mAutoTiles, mDumpManager,
|
mQSLogger, mUiEventLogger, mUserTracker, mSecureSettings, mCustomTileStatePersister,
|
||||||
mBroadcastDispatcher, mCentralSurfaces, mQSLogger, mUiEventLogger, mUserTracker,
|
mTileServiceRequestControllerBuilder, mTileLifecycleManagerFactory);
|
||||||
mSecureSettings, mCustomTileStatePersister, mTileServiceRequestControllerBuilder,
|
|
||||||
mTileLifecycleManagerFactory);
|
mSecureSettings.registerContentObserverForUser(SETTING, new ContentObserver(null) {
|
||||||
|
@Override
|
||||||
|
public void onChange(boolean selfChange) {
|
||||||
|
super.onChange(selfChange);
|
||||||
|
mMainExecutor.execute(() -> mQSTileHost.onTuningChanged(SETTING, getSetting()));
|
||||||
|
mMainExecutor.runAllReady();
|
||||||
|
}
|
||||||
|
}, mUserTracker.getUserId());
|
||||||
setUpTileFactory();
|
setUpTileFactory();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void saveSetting(String value) {
|
||||||
|
mSecureSettings.putStringForUser(
|
||||||
|
SETTING, value, "", false, mUserTracker.getUserId(), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getSetting() {
|
||||||
|
return mSecureSettings.getStringForUser(SETTING, mUserTracker.getUserId());
|
||||||
|
}
|
||||||
|
|
||||||
private void setUpTileFactory() {
|
private void setUpTileFactory() {
|
||||||
when(mMockState.toString()).thenReturn(MOCK_STATE_STRING);
|
when(mMockState.toString()).thenReturn(MOCK_STATE_STRING);
|
||||||
// Only create this kind of tiles
|
// Only create this kind of tiles
|
||||||
@@ -173,6 +188,10 @@ public class QSTileHostTest extends SysuiTestCase {
|
|||||||
return new NotAvailableTile(mQSTileHost);
|
return new NotAvailableTile(mQSTileHost);
|
||||||
} else if (CUSTOM_TILE_SPEC.equals(spec)) {
|
} else if (CUSTOM_TILE_SPEC.equals(spec)) {
|
||||||
return mCustomTile;
|
return mCustomTile;
|
||||||
|
} else if ("internet".equals(spec)
|
||||||
|
|| "wifi".equals(spec)
|
||||||
|
|| "cell".equals(spec)) {
|
||||||
|
return new TestTile1(mQSTileHost);
|
||||||
} else {
|
} else {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -196,14 +215,14 @@ public class QSTileHostTest extends SysuiTestCase {
|
|||||||
public void testInvalidSpecUsesDefault() {
|
public void testInvalidSpecUsesDefault() {
|
||||||
mContext.getOrCreateTestableResources()
|
mContext.getOrCreateTestableResources()
|
||||||
.addOverride(R.string.quick_settings_tiles, "spec1,spec2");
|
.addOverride(R.string.quick_settings_tiles, "spec1,spec2");
|
||||||
mQSTileHost.onTuningChanged(QSTileHost.TILES_SETTING, "not-valid");
|
saveSetting("not-valid");
|
||||||
|
|
||||||
assertEquals(2, mQSTileHost.getTiles().size());
|
assertEquals(2, mQSTileHost.getTiles().size());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRemoveWifiAndCellularWithoutInternet() {
|
public void testRemoveWifiAndCellularWithoutInternet() {
|
||||||
mQSTileHost.onTuningChanged(QSTileHost.TILES_SETTING, "wifi, spec1, cell, spec2");
|
saveSetting("wifi, spec1, cell, spec2");
|
||||||
|
|
||||||
assertEquals("internet", mQSTileHost.mTileSpecs.get(0));
|
assertEquals("internet", mQSTileHost.mTileSpecs.get(0));
|
||||||
assertEquals("spec1", mQSTileHost.mTileSpecs.get(1));
|
assertEquals("spec1", mQSTileHost.mTileSpecs.get(1));
|
||||||
@@ -212,7 +231,7 @@ public class QSTileHostTest extends SysuiTestCase {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRemoveWifiAndCellularWithInternet() {
|
public void testRemoveWifiAndCellularWithInternet() {
|
||||||
mQSTileHost.onTuningChanged(QSTileHost.TILES_SETTING, "wifi, spec1, cell, spec2, internet");
|
saveSetting("wifi, spec1, cell, spec2, internet");
|
||||||
|
|
||||||
assertEquals("spec1", mQSTileHost.mTileSpecs.get(0));
|
assertEquals("spec1", mQSTileHost.mTileSpecs.get(0));
|
||||||
assertEquals("spec2", mQSTileHost.mTileSpecs.get(1));
|
assertEquals("spec2", mQSTileHost.mTileSpecs.get(1));
|
||||||
@@ -221,7 +240,7 @@ public class QSTileHostTest extends SysuiTestCase {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRemoveWifiWithoutInternet() {
|
public void testRemoveWifiWithoutInternet() {
|
||||||
mQSTileHost.onTuningChanged(QSTileHost.TILES_SETTING, "spec1, wifi, spec2");
|
saveSetting("spec1, wifi, spec2");
|
||||||
|
|
||||||
assertEquals("spec1", mQSTileHost.mTileSpecs.get(0));
|
assertEquals("spec1", mQSTileHost.mTileSpecs.get(0));
|
||||||
assertEquals("internet", mQSTileHost.mTileSpecs.get(1));
|
assertEquals("internet", mQSTileHost.mTileSpecs.get(1));
|
||||||
@@ -230,7 +249,7 @@ public class QSTileHostTest extends SysuiTestCase {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRemoveCellWithInternet() {
|
public void testRemoveCellWithInternet() {
|
||||||
mQSTileHost.onTuningChanged(QSTileHost.TILES_SETTING, "spec1, spec2, cell, internet");
|
saveSetting("spec1, spec2, cell, internet");
|
||||||
|
|
||||||
assertEquals("spec1", mQSTileHost.mTileSpecs.get(0));
|
assertEquals("spec1", mQSTileHost.mTileSpecs.get(0));
|
||||||
assertEquals("spec2", mQSTileHost.mTileSpecs.get(1));
|
assertEquals("spec2", mQSTileHost.mTileSpecs.get(1));
|
||||||
@@ -239,7 +258,7 @@ public class QSTileHostTest extends SysuiTestCase {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testNoWifiNoCellularNoInternet() {
|
public void testNoWifiNoCellularNoInternet() {
|
||||||
mQSTileHost.onTuningChanged(QSTileHost.TILES_SETTING, "spec1,spec2");
|
saveSetting("spec1,spec2");
|
||||||
|
|
||||||
assertEquals("spec1", mQSTileHost.mTileSpecs.get(0));
|
assertEquals("spec1", mQSTileHost.mTileSpecs.get(0));
|
||||||
assertEquals("spec2", mQSTileHost.mTileSpecs.get(1));
|
assertEquals("spec2", mQSTileHost.mTileSpecs.get(1));
|
||||||
@@ -249,7 +268,7 @@ public class QSTileHostTest extends SysuiTestCase {
|
|||||||
public void testSpecWithInvalidDoesNotUseDefault() {
|
public void testSpecWithInvalidDoesNotUseDefault() {
|
||||||
mContext.getOrCreateTestableResources()
|
mContext.getOrCreateTestableResources()
|
||||||
.addOverride(R.string.quick_settings_tiles, "spec1,spec2");
|
.addOverride(R.string.quick_settings_tiles, "spec1,spec2");
|
||||||
mQSTileHost.onTuningChanged(QSTileHost.TILES_SETTING, "spec2,not-valid");
|
saveSetting("spec2,not-valid");
|
||||||
|
|
||||||
assertEquals(1, mQSTileHost.getTiles().size());
|
assertEquals(1, mQSTileHost.getTiles().size());
|
||||||
QSTile element = CollectionUtils.firstOrNull(mQSTileHost.getTiles());
|
QSTile element = CollectionUtils.firstOrNull(mQSTileHost.getTiles());
|
||||||
@@ -258,7 +277,7 @@ public class QSTileHostTest extends SysuiTestCase {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDump() {
|
public void testDump() {
|
||||||
mQSTileHost.onTuningChanged(QSTileHost.TILES_SETTING, "spec1,spec2");
|
saveSetting("spec1,spec2");
|
||||||
StringWriter w = new StringWriter();
|
StringWriter w = new StringWriter();
|
||||||
PrintWriter pw = new PrintWriter(w);
|
PrintWriter pw = new PrintWriter(w);
|
||||||
mQSTileHost.dump(pw, new String[]{});
|
mQSTileHost.dump(pw, new String[]{});
|
||||||
@@ -274,7 +293,7 @@ public class QSTileHostTest extends SysuiTestCase {
|
|||||||
public void testDefault() {
|
public void testDefault() {
|
||||||
mContext.getOrCreateTestableResources()
|
mContext.getOrCreateTestableResources()
|
||||||
.addOverride(R.string.quick_settings_tiles_default, "spec1");
|
.addOverride(R.string.quick_settings_tiles_default, "spec1");
|
||||||
mQSTileHost.onTuningChanged(QSTileHost.TILES_SETTING, "default");
|
saveSetting("default");
|
||||||
assertEquals(1, mQSTileHost.getTiles().size());
|
assertEquals(1, mQSTileHost.getTiles().size());
|
||||||
QSTile element = CollectionUtils.firstOrNull(mQSTileHost.getTiles());
|
QSTile element = CollectionUtils.firstOrNull(mQSTileHost.getTiles());
|
||||||
assertTrue(element instanceof TestTile1);
|
assertTrue(element instanceof TestTile1);
|
||||||
@@ -285,7 +304,7 @@ public class QSTileHostTest extends SysuiTestCase {
|
|||||||
public void testNoRepeatedSpecs_addTile() {
|
public void testNoRepeatedSpecs_addTile() {
|
||||||
mContext.getOrCreateTestableResources()
|
mContext.getOrCreateTestableResources()
|
||||||
.addOverride(R.string.quick_settings_tiles, "spec1,spec2");
|
.addOverride(R.string.quick_settings_tiles, "spec1,spec2");
|
||||||
mQSTileHost.onTuningChanged(QSTileHost.TILES_SETTING, "spec1,spec2");
|
saveSetting("spec1,spec2");
|
||||||
|
|
||||||
mQSTileHost.addTile("spec1");
|
mQSTileHost.addTile("spec1");
|
||||||
|
|
||||||
@@ -298,9 +317,10 @@ public class QSTileHostTest extends SysuiTestCase {
|
|||||||
public void testAddTileAtValidPosition() {
|
public void testAddTileAtValidPosition() {
|
||||||
mContext.getOrCreateTestableResources()
|
mContext.getOrCreateTestableResources()
|
||||||
.addOverride(R.string.quick_settings_tiles, "spec1,spec3");
|
.addOverride(R.string.quick_settings_tiles, "spec1,spec3");
|
||||||
mQSTileHost.onTuningChanged(QSTileHost.TILES_SETTING, "spec1,spec3");
|
saveSetting("spec1,spec3");
|
||||||
|
|
||||||
mQSTileHost.addTile("spec2", 1);
|
mQSTileHost.addTile("spec2", 1);
|
||||||
|
mMainExecutor.runAllReady();
|
||||||
|
|
||||||
assertEquals(3, mQSTileHost.mTileSpecs.size());
|
assertEquals(3, mQSTileHost.mTileSpecs.size());
|
||||||
assertEquals("spec1", mQSTileHost.mTileSpecs.get(0));
|
assertEquals("spec1", mQSTileHost.mTileSpecs.get(0));
|
||||||
@@ -312,9 +332,10 @@ public class QSTileHostTest extends SysuiTestCase {
|
|||||||
public void testAddTileAtInvalidPositionAddsToEnd() {
|
public void testAddTileAtInvalidPositionAddsToEnd() {
|
||||||
mContext.getOrCreateTestableResources()
|
mContext.getOrCreateTestableResources()
|
||||||
.addOverride(R.string.quick_settings_tiles, "spec1,spec3");
|
.addOverride(R.string.quick_settings_tiles, "spec1,spec3");
|
||||||
mQSTileHost.onTuningChanged(QSTileHost.TILES_SETTING, "spec1,spec3");
|
saveSetting("spec1,spec3");
|
||||||
|
|
||||||
mQSTileHost.addTile("spec2", 100);
|
mQSTileHost.addTile("spec2", 100);
|
||||||
|
mMainExecutor.runAllReady();
|
||||||
|
|
||||||
assertEquals(3, mQSTileHost.mTileSpecs.size());
|
assertEquals(3, mQSTileHost.mTileSpecs.size());
|
||||||
assertEquals("spec1", mQSTileHost.mTileSpecs.get(0));
|
assertEquals("spec1", mQSTileHost.mTileSpecs.get(0));
|
||||||
@@ -326,9 +347,10 @@ public class QSTileHostTest extends SysuiTestCase {
|
|||||||
public void testAddTileAtEnd() {
|
public void testAddTileAtEnd() {
|
||||||
mContext.getOrCreateTestableResources()
|
mContext.getOrCreateTestableResources()
|
||||||
.addOverride(R.string.quick_settings_tiles, "spec1,spec3");
|
.addOverride(R.string.quick_settings_tiles, "spec1,spec3");
|
||||||
mQSTileHost.onTuningChanged(QSTileHost.TILES_SETTING, "spec1,spec3");
|
saveSetting("spec1,spec3");
|
||||||
|
|
||||||
mQSTileHost.addTile("spec2", QSTileHost.POSITION_AT_END);
|
mQSTileHost.addTile("spec2", QSTileHost.POSITION_AT_END);
|
||||||
|
mMainExecutor.runAllReady();
|
||||||
|
|
||||||
assertEquals(3, mQSTileHost.mTileSpecs.size());
|
assertEquals(3, mQSTileHost.mTileSpecs.size());
|
||||||
assertEquals("spec1", mQSTileHost.mTileSpecs.get(0));
|
assertEquals("spec1", mQSTileHost.mTileSpecs.get(0));
|
||||||
@@ -338,9 +360,10 @@ public class QSTileHostTest extends SysuiTestCase {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testNoRepeatedSpecs_customTile() {
|
public void testNoRepeatedSpecs_customTile() {
|
||||||
mQSTileHost.onTuningChanged(QSTileHost.TILES_SETTING, CUSTOM_TILE_SPEC);
|
saveSetting(CUSTOM_TILE_SPEC);
|
||||||
|
|
||||||
mQSTileHost.addTile(CUSTOM_TILE, /* end */ false);
|
mQSTileHost.addTile(CUSTOM_TILE, /* end */ false);
|
||||||
|
mMainExecutor.runAllReady();
|
||||||
|
|
||||||
assertEquals(1, mQSTileHost.mTileSpecs.size());
|
assertEquals(1, mQSTileHost.mTileSpecs.size());
|
||||||
assertEquals(CUSTOM_TILE_SPEC, mQSTileHost.mTileSpecs.get(0));
|
assertEquals(CUSTOM_TILE_SPEC, mQSTileHost.mTileSpecs.get(0));
|
||||||
@@ -348,9 +371,10 @@ public class QSTileHostTest extends SysuiTestCase {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testAddedAtBeginningOnDefault_customTile() {
|
public void testAddedAtBeginningOnDefault_customTile() {
|
||||||
mQSTileHost.onTuningChanged(QSTileHost.TILES_SETTING, "spec1"); // seed
|
saveSetting("spec1"); // seed
|
||||||
|
|
||||||
mQSTileHost.addTile(CUSTOM_TILE);
|
mQSTileHost.addTile(CUSTOM_TILE);
|
||||||
|
mMainExecutor.runAllReady();
|
||||||
|
|
||||||
assertEquals(2, mQSTileHost.mTileSpecs.size());
|
assertEquals(2, mQSTileHost.mTileSpecs.size());
|
||||||
assertEquals(CUSTOM_TILE_SPEC, mQSTileHost.mTileSpecs.get(0));
|
assertEquals(CUSTOM_TILE_SPEC, mQSTileHost.mTileSpecs.get(0));
|
||||||
@@ -358,9 +382,10 @@ public class QSTileHostTest extends SysuiTestCase {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testAddedAtBeginning_customTile() {
|
public void testAddedAtBeginning_customTile() {
|
||||||
mQSTileHost.onTuningChanged(QSTileHost.TILES_SETTING, "spec1"); // seed
|
saveSetting("spec1"); // seed
|
||||||
|
|
||||||
mQSTileHost.addTile(CUSTOM_TILE, /* end */ false);
|
mQSTileHost.addTile(CUSTOM_TILE, /* end */ false);
|
||||||
|
mMainExecutor.runAllReady();
|
||||||
|
|
||||||
assertEquals(2, mQSTileHost.mTileSpecs.size());
|
assertEquals(2, mQSTileHost.mTileSpecs.size());
|
||||||
assertEquals(CUSTOM_TILE_SPEC, mQSTileHost.mTileSpecs.get(0));
|
assertEquals(CUSTOM_TILE_SPEC, mQSTileHost.mTileSpecs.get(0));
|
||||||
@@ -368,9 +393,10 @@ public class QSTileHostTest extends SysuiTestCase {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testAddedAtEnd_customTile() {
|
public void testAddedAtEnd_customTile() {
|
||||||
mQSTileHost.onTuningChanged(QSTileHost.TILES_SETTING, "spec1"); // seed
|
saveSetting("spec1"); // seed
|
||||||
|
|
||||||
mQSTileHost.addTile(CUSTOM_TILE, /* end */ true);
|
mQSTileHost.addTile(CUSTOM_TILE, /* end */ true);
|
||||||
|
mMainExecutor.runAllReady();
|
||||||
|
|
||||||
assertEquals(2, mQSTileHost.mTileSpecs.size());
|
assertEquals(2, mQSTileHost.mTileSpecs.size());
|
||||||
assertEquals(CUSTOM_TILE_SPEC, mQSTileHost.mTileSpecs.get(1));
|
assertEquals(CUSTOM_TILE_SPEC, mQSTileHost.mTileSpecs.get(1));
|
||||||
@@ -409,13 +435,13 @@ public class QSTileHostTest extends SysuiTestCase {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testNotAvailableTile_specNotNull() {
|
public void testNotAvailableTile_specNotNull() {
|
||||||
mQSTileHost.onTuningChanged(QSTileHost.TILES_SETTING, "na");
|
saveSetting("na");
|
||||||
verify(mQSLogger, never()).logTileDestroyed(isNull(), anyString());
|
verify(mQSLogger, never()).logTileDestroyed(isNull(), anyString());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCustomTileRemoved_stateDeleted() {
|
public void testCustomTileRemoved_stateDeleted() {
|
||||||
mQSTileHost.changeTiles(List.of(CUSTOM_TILE_SPEC), List.of());
|
mQSTileHost.changeTilesByUser(List.of(CUSTOM_TILE_SPEC), List.of());
|
||||||
|
|
||||||
verify(mCustomTileStatePersister)
|
verify(mCustomTileStatePersister)
|
||||||
.removeState(new TileServiceKey(CUSTOM_TILE, mQSTileHost.getUserId()));
|
.removeState(new TileServiceKey(CUSTOM_TILE, mQSTileHost.getUserId()));
|
||||||
@@ -423,29 +449,99 @@ public class QSTileHostTest extends SysuiTestCase {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRemoveTiles() {
|
public void testRemoveTiles() {
|
||||||
List<String> tiles = List.of("spec1", "spec2", "spec3");
|
saveSetting("spec1,spec2,spec3");
|
||||||
mQSTileHost.saveTilesToSettings(tiles);
|
|
||||||
|
|
||||||
mQSTileHost.removeTiles(List.of("spec1", "spec2"));
|
mQSTileHost.removeTiles(List.of("spec1", "spec2"));
|
||||||
|
|
||||||
|
mMainExecutor.runAllReady();
|
||||||
assertEquals(List.of("spec3"), mQSTileHost.mTileSpecs);
|
assertEquals(List.of("spec3"), mQSTileHost.mTileSpecs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testTilesRemovedInQuickSuccession() {
|
||||||
|
saveSetting("spec1,spec2,spec3");
|
||||||
|
mQSTileHost.removeTile("spec1");
|
||||||
|
mQSTileHost.removeTile("spec3");
|
||||||
|
|
||||||
|
mMainExecutor.runAllReady();
|
||||||
|
assertEquals(List.of("spec2"), mQSTileHost.mTileSpecs);
|
||||||
|
assertEquals("spec2", getSetting());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAddTileInMainThread() {
|
||||||
|
saveSetting("spec1,spec2");
|
||||||
|
|
||||||
|
mQSTileHost.addTile("spec3");
|
||||||
|
assertEquals(List.of("spec1", "spec2"), mQSTileHost.mTileSpecs);
|
||||||
|
|
||||||
|
mMainExecutor.runAllReady();
|
||||||
|
assertEquals(List.of("spec1", "spec2", "spec3"), mQSTileHost.mTileSpecs);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRemoveTileInMainThread() {
|
||||||
|
saveSetting("spec1,spec2");
|
||||||
|
|
||||||
|
mQSTileHost.removeTile("spec1");
|
||||||
|
assertEquals(List.of("spec1", "spec2"), mQSTileHost.mTileSpecs);
|
||||||
|
|
||||||
|
mMainExecutor.runAllReady();
|
||||||
|
assertEquals(List.of("spec2"), mQSTileHost.mTileSpecs);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRemoveTilesInMainThread() {
|
||||||
|
saveSetting("spec1,spec2,spec3");
|
||||||
|
|
||||||
|
mQSTileHost.removeTiles(List.of("spec3", "spec1"));
|
||||||
|
assertEquals(List.of("spec1", "spec2", "spec3"), mQSTileHost.mTileSpecs);
|
||||||
|
|
||||||
|
mMainExecutor.runAllReady();
|
||||||
|
assertEquals(List.of("spec2"), mQSTileHost.mTileSpecs);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRemoveTileByUserInMainThread() {
|
||||||
|
saveSetting("spec1," + CUSTOM_TILE_SPEC);
|
||||||
|
|
||||||
|
mQSTileHost.removeTileByUser(CUSTOM_TILE);
|
||||||
|
assertEquals(List.of("spec1", CUSTOM_TILE_SPEC), mQSTileHost.mTileSpecs);
|
||||||
|
|
||||||
|
mMainExecutor.runAllReady();
|
||||||
|
assertEquals(List.of("spec1"), mQSTileHost.mTileSpecs);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNonValidTileNotStoredInSettings() {
|
||||||
|
saveSetting("spec1,not-valid");
|
||||||
|
|
||||||
|
assertEquals(List.of("spec1"), mQSTileHost.mTileSpecs);
|
||||||
|
assertEquals("spec1", getSetting());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNotAvailableTileNotStoredInSettings() {
|
||||||
|
saveSetting("spec1,na");
|
||||||
|
|
||||||
|
assertEquals(List.of("spec1"), mQSTileHost.mTileSpecs);
|
||||||
|
assertEquals("spec1", getSetting());
|
||||||
|
}
|
||||||
|
|
||||||
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, Executor mainExecutor,
|
||||||
PluginManager pluginManager, TunerService tunerService,
|
PluginManager pluginManager, TunerService tunerService,
|
||||||
Provider<AutoTileManager> autoTiles, DumpManager dumpManager,
|
Provider<AutoTileManager> autoTiles, DumpManager dumpManager,
|
||||||
BroadcastDispatcher broadcastDispatcher, CentralSurfaces centralSurfaces,
|
CentralSurfaces centralSurfaces, QSLogger qsLogger, UiEventLogger uiEventLogger,
|
||||||
QSLogger qsLogger, UiEventLogger uiEventLogger, UserTracker userTracker,
|
UserTracker userTracker, SecureSettings secureSettings,
|
||||||
SecureSettings secureSettings, CustomTileStatePersister customTileStatePersister,
|
CustomTileStatePersister customTileStatePersister,
|
||||||
TileServiceRequestController.Builder tileServiceRequestControllerBuilder,
|
TileServiceRequestController.Builder tileServiceRequestControllerBuilder,
|
||||||
TileLifecycleManager.Factory tileLifecycleManagerFactory) {
|
TileLifecycleManager.Factory tileLifecycleManagerFactory) {
|
||||||
super(context, iconController, defaultFactory, mainHandler, bgLooper, pluginManager,
|
super(context, iconController, defaultFactory, mainExecutor, pluginManager,
|
||||||
tunerService, autoTiles, dumpManager, broadcastDispatcher,
|
tunerService, autoTiles, dumpManager, Optional.of(centralSurfaces), qsLogger,
|
||||||
Optional.of(centralSurfaces), qsLogger, uiEventLogger, userTracker,
|
uiEventLogger, userTracker, secureSettings, customTileStatePersister,
|
||||||
secureSettings, customTileStatePersister, tileServiceRequestControllerBuilder,
|
tileServiceRequestControllerBuilder, tileLifecycleManagerFactory);
|
||||||
tileLifecycleManagerFactory);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -455,25 +551,16 @@ public class QSTileHostTest extends SysuiTestCase {
|
|||||||
@Override
|
@Override
|
||||||
public void onPluginDisconnected(QSFactory plugin) {
|
public void onPluginDisconnected(QSFactory plugin) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
void saveTilesToSettings(List<String> tileSpecs) {
|
|
||||||
super.saveTilesToSettings(tileSpecs);
|
|
||||||
// After tiles are changed, make sure to call onTuningChanged with the new setting if it
|
|
||||||
// changed
|
|
||||||
String specs = mSecureSettings.getStringForUser(
|
|
||||||
QSTileHost.TILES_SETTING, mUserTracker.getUserId());
|
|
||||||
onTuningChanged(TILES_SETTING, specs);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private class TestTile extends QSTileImpl<QSTile.State> {
|
private class TestTile extends QSTileImpl<QSTile.State> {
|
||||||
|
|
||||||
protected TestTile(QSHost host) {
|
protected TestTile(QSHost host) {
|
||||||
super(
|
super(
|
||||||
host,
|
host,
|
||||||
mLooper.getLooper(),
|
mock(Looper.class),
|
||||||
new Handler(mLooper.getLooper()),
|
mock(Handler.class),
|
||||||
new FalsingManagerFake(),
|
new FalsingManagerFake(),
|
||||||
mock(MetricsLogger.class),
|
mock(MetricsLogger.class),
|
||||||
mock(StatusBarStateController.class),
|
mock(StatusBarStateController.class),
|
||||||
|
|||||||
@@ -55,6 +55,6 @@ public class TileAdapterTest extends SysuiTestCase {
|
|||||||
@Test
|
@Test
|
||||||
public void testResetNotifiesHost() {
|
public void testResetNotifiesHost() {
|
||||||
mTileAdapter.resetTileSpecs(Collections.emptyList());
|
mTileAdapter.resetTileSpecs(Collections.emptyList());
|
||||||
verify(mQSTileHost).changeTiles(any(), any());
|
verify(mQSTileHost).changeTilesByUser(any(), any());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ import static org.mockito.Mockito.when;
|
|||||||
import android.content.ComponentName;
|
import android.content.ComponentName;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
|
import android.os.HandlerExecutor;
|
||||||
import android.os.RemoteException;
|
import android.os.RemoteException;
|
||||||
import android.os.UserHandle;
|
import android.os.UserHandle;
|
||||||
import android.service.quicksettings.IQSTileService;
|
import android.service.quicksettings.IQSTileService;
|
||||||
@@ -65,6 +66,7 @@ import org.mockito.MockitoAnnotations;
|
|||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
import java.util.concurrent.Executor;
|
||||||
|
|
||||||
import javax.inject.Provider;
|
import javax.inject.Provider;
|
||||||
|
|
||||||
@@ -130,17 +132,16 @@ public class TileServicesTest extends SysuiTestCase {
|
|||||||
.thenReturn(mTileLifecycleManager);
|
.thenReturn(mTileLifecycleManager);
|
||||||
|
|
||||||
Provider<Handler> provider = () -> new Handler(mTestableLooper.getLooper());
|
Provider<Handler> provider = () -> new Handler(mTestableLooper.getLooper());
|
||||||
|
Executor executor = new HandlerExecutor(provider.get());
|
||||||
|
|
||||||
QSTileHost host = new QSTileHost(mContext,
|
QSTileHost host = new QSTileHost(mContext,
|
||||||
mStatusBarIconController,
|
mStatusBarIconController,
|
||||||
mQSFactory,
|
mQSFactory,
|
||||||
provider.get(),
|
executor,
|
||||||
mTestableLooper.getLooper(),
|
|
||||||
mPluginManager,
|
mPluginManager,
|
||||||
mTunerService,
|
mTunerService,
|
||||||
() -> mAutoTileManager,
|
() -> mAutoTileManager,
|
||||||
mDumpManager,
|
mDumpManager,
|
||||||
mock(BroadcastDispatcher.class),
|
|
||||||
Optional.of(mCentralSurfaces),
|
Optional.of(mCentralSurfaces),
|
||||||
mQSLogger,
|
mQSLogger,
|
||||||
mUiEventLogger,
|
mUiEventLogger,
|
||||||
|
|||||||
@@ -490,7 +490,7 @@ public class AutoTileManagerTest extends SysuiTestCase {
|
|||||||
mAutoTileManager.init();
|
mAutoTileManager.init();
|
||||||
when(mAutoAddTracker.isAdded(TEST_CUSTOM_SAFETY_SPEC)).thenReturn(true);
|
when(mAutoAddTracker.isAdded(TEST_CUSTOM_SAFETY_SPEC)).thenReturn(true);
|
||||||
mAutoTileManager.mSafetyCallback.onSafetyCenterEnableChanged(false);
|
mAutoTileManager.mSafetyCallback.onSafetyCenterEnableChanged(false);
|
||||||
verify(mQsTileHost, times(1)).removeTile(safetyComponent);
|
verify(mQsTileHost, times(1)).removeTile(TEST_CUSTOM_SAFETY_SPEC);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
Reference in New Issue
Block a user