Merge changes from topic "FK_168687572" into sc-qpr1-dev am: 3ab3c04d28

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/15545838

Change-Id: Icc82dbbfe1a61aa4c0aa55764fab61667df8ab00
This commit is contained in:
Fabian Kozynski
2021-08-18 18:51:48 +00:00
committed by Automerger Merge Worker
8 changed files with 527 additions and 219 deletions

View File

@@ -101,6 +101,7 @@ public class SecureSettings {
Settings.Secure.CAMERA_DOUBLE_TAP_POWER_GESTURE_DISABLED,
Settings.Secure.SYSTEM_NAVIGATION_KEYS_ENABLED,
Settings.Secure.QS_TILES,
Settings.Secure.QS_AUTO_ADDED_TILES,
Settings.Secure.CONTROLS_ENABLED,
Settings.Secure.POWER_MENU_LOCKED_SHOW_CONTENT,
Settings.Secure.DOZE_ENABLED,
@@ -118,7 +119,6 @@ public class SecureSettings {
Settings.Secure.VR_DISPLAY_MODE,
Settings.Secure.NOTIFICATION_BADGING,
Settings.Secure.NOTIFICATION_DISMISS_RTL,
Settings.Secure.QS_AUTO_ADDED_TILES,
Settings.Secure.SCREENSAVER_ENABLED,
Settings.Secure.SCREENSAVER_COMPONENTS,
Settings.Secure.SCREENSAVER_ACTIVATE_ON_DOCK,

View File

@@ -72,8 +72,9 @@ public class SettingsHelper {
* {@hide}
*/
private static final ArraySet<String> sBroadcastOnRestore;
private static final ArraySet<String> sBroadcastOnRestoreSystemUI;
static {
sBroadcastOnRestore = new ArraySet<String>(4);
sBroadcastOnRestore = new ArraySet<String>(9);
sBroadcastOnRestore.add(Settings.Secure.ENABLED_NOTIFICATION_LISTENERS);
sBroadcastOnRestore.add(Settings.Secure.ENABLED_VR_LISTENERS);
sBroadcastOnRestore.add(Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES);
@@ -83,6 +84,9 @@ public class SettingsHelper {
sBroadcastOnRestore.add(Settings.Secure.DARK_THEME_CUSTOM_END_TIME);
sBroadcastOnRestore.add(Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED);
sBroadcastOnRestore.add(Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS);
sBroadcastOnRestoreSystemUI = new ArraySet<String>(2);
sBroadcastOnRestoreSystemUI.add(Settings.Secure.QS_TILES);
sBroadcastOnRestoreSystemUI.add(Settings.Secure.QS_AUTO_ADDED_TILES);
}
private interface SettingsLookup {
@@ -133,6 +137,7 @@ public class SettingsHelper {
// Will we need a post-restore broadcast for this element?
String oldValue = null;
boolean sendBroadcast = false;
boolean sendBroadcastSystemUI = false;
final SettingsLookup table;
if (destination.equals(Settings.Secure.CONTENT_URI)) {
@@ -143,10 +148,12 @@ public class SettingsHelper {
table = sGlobalLookup;
}
if (sBroadcastOnRestore.contains(name)) {
sendBroadcast = sBroadcastOnRestore.contains(name);
sendBroadcastSystemUI = sBroadcastOnRestoreSystemUI.contains(name);
if (sendBroadcast || sendBroadcastSystemUI) {
// TODO: http://b/22388012
oldValue = table.lookup(cr, name, UserHandle.USER_SYSTEM);
sendBroadcast = true;
}
try {
@@ -193,18 +200,28 @@ public class SettingsHelper {
} catch (Exception e) {
// If we fail to apply the setting, by definition nothing happened
sendBroadcast = false;
sendBroadcastSystemUI = false;
} finally {
// If this was an element of interest, send the "we just restored it"
// broadcast with the historical value now that the new value has
// been committed and observers kicked off.
if (sendBroadcast) {
if (sendBroadcast || sendBroadcastSystemUI) {
Intent intent = new Intent(Intent.ACTION_SETTING_RESTORED)
.setPackage("android").addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY)
.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY)
.putExtra(Intent.EXTRA_SETTING_NAME, name)
.putExtra(Intent.EXTRA_SETTING_NEW_VALUE, value)
.putExtra(Intent.EXTRA_SETTING_PREVIOUS_VALUE, oldValue)
.putExtra(Intent.EXTRA_SETTING_RESTORED_FROM_SDK_INT, restoredFromSdkInt);
context.sendBroadcastAsUser(intent, UserHandle.SYSTEM, null);
if (sendBroadcast) {
intent.setPackage("android");
context.sendBroadcastAsUser(intent, UserHandle.SYSTEM, null);
}
if (sendBroadcastSystemUI) {
intent.setPackage(
context.getString(com.android.internal.R.string.config_systemUi));
context.sendBroadcastAsUser(intent, UserHandle.SYSTEM, null);
}
}
}
}

View File

@@ -1,156 +0,0 @@
/*
* Copyright (C) 2017 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;
import static com.android.systemui.statusbar.phone.AutoTileManager.HOTSPOT;
import static com.android.systemui.statusbar.phone.AutoTileManager.INVERSION;
import static com.android.systemui.statusbar.phone.AutoTileManager.NIGHT;
import static com.android.systemui.statusbar.phone.AutoTileManager.SAVER;
import static com.android.systemui.statusbar.phone.AutoTileManager.WORK;
import android.content.Context;
import android.database.ContentObserver;
import android.os.Handler;
import android.os.UserHandle;
import android.provider.Settings.Secure;
import android.text.TextUtils;
import android.util.ArraySet;
import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.Prefs;
import com.android.systemui.Prefs.Key;
import com.android.systemui.util.UserAwareController;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import javax.inject.Inject;
public class AutoAddTracker implements UserAwareController {
private static final String[][] CONVERT_PREFS = {
{Key.QS_HOTSPOT_ADDED, HOTSPOT},
{Key.QS_DATA_SAVER_ADDED, SAVER},
{Key.QS_INVERT_COLORS_ADDED, INVERSION},
{Key.QS_WORK_ADDED, WORK},
{Key.QS_NIGHTDISPLAY_ADDED, NIGHT},
};
private final ArraySet<String> mAutoAdded;
private final Context mContext;
private int mUserId;
public AutoAddTracker(Context context, int userId) {
mContext = context;
mUserId = userId;
mAutoAdded = new ArraySet<>(getAdded());
}
/**
* Init method must be called after construction to start listening
*/
public void initialize() {
// TODO: remove migration code and shared preferences keys after P release
if (mUserId == UserHandle.USER_SYSTEM) {
for (String[] convertPref : CONVERT_PREFS) {
if (Prefs.getBoolean(mContext, convertPref[0], false)) {
setTileAdded(convertPref[1]);
Prefs.remove(mContext, convertPref[0]);
}
}
}
mContext.getContentResolver().registerContentObserver(
Secure.getUriFor(Secure.QS_AUTO_ADDED_TILES), false, mObserver,
UserHandle.USER_ALL);
}
@Override
public void changeUser(UserHandle newUser) {
if (newUser.getIdentifier() == mUserId) {
return;
}
mUserId = newUser.getIdentifier();
mAutoAdded.clear();
mAutoAdded.addAll(getAdded());
}
@Override
public int getCurrentUserId() {
return mUserId;
}
public boolean isAdded(String tile) {
return mAutoAdded.contains(tile);
}
public void setTileAdded(String tile) {
if (mAutoAdded.add(tile)) {
saveTiles();
}
}
public void setTileRemoved(String tile) {
if (mAutoAdded.remove(tile)) {
saveTiles();
}
}
public void destroy() {
mContext.getContentResolver().unregisterContentObserver(mObserver);
}
private void saveTiles() {
Secure.putStringForUser(mContext.getContentResolver(), Secure.QS_AUTO_ADDED_TILES,
TextUtils.join(",", mAutoAdded), mUserId);
}
private Collection<String> getAdded() {
String current = Secure.getStringForUser(mContext.getContentResolver(),
Secure.QS_AUTO_ADDED_TILES, mUserId);
if (current == null) {
return Collections.emptyList();
}
return Arrays.asList(current.split(","));
}
@VisibleForTesting
protected final ContentObserver mObserver = new ContentObserver(new Handler()) {
@Override
public void onChange(boolean selfChange) {
mAutoAdded.clear();
mAutoAdded.addAll(getAdded());
}
};
public static class Builder {
private final Context mContext;
private int mUserId;
@Inject
public Builder(Context context) {
mContext = context;
}
public Builder setUserId(int userId) {
mUserId = userId;
return this;
}
public AutoAddTracker build() {
return new AutoAddTracker(mContext, mUserId);
}
}
}

View File

@@ -0,0 +1,285 @@
/*
* 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
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.database.ContentObserver
import android.net.Uri
import android.os.Handler
import android.os.UserHandle
import android.provider.Settings
import android.text.TextUtils
import android.util.ArraySet
import android.util.Log
import androidx.annotation.GuardedBy
import androidx.annotation.VisibleForTesting
import com.android.systemui.Dumpable
import com.android.systemui.broadcast.BroadcastDispatcher
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.dump.DumpManager
import com.android.systemui.util.UserAwareController
import com.android.systemui.util.settings.SecureSettings
import java.io.FileDescriptor
import java.io.PrintWriter
import java.util.concurrent.Executor
import javax.inject.Inject
private const val TAG = "AutoAddTracker"
/**
* Class to track tiles that have been auto-added
*
* The list is backed by [Settings.Secure.QS_AUTO_ADDED_TILES].
*
* It also handles restore gracefully.
*/
class AutoAddTracker @VisibleForTesting constructor(
private val secureSettings: SecureSettings,
private val broadcastDispatcher: BroadcastDispatcher,
private val qsHost: QSHost,
private val dumpManager: DumpManager,
private val mainHandler: Handler?,
private val backgroundExecutor: Executor,
private var userId: Int
) : UserAwareController, Dumpable {
companion object {
private val FILTER = IntentFilter(Intent.ACTION_SETTING_RESTORED)
}
@GuardedBy("autoAdded")
private val autoAdded = ArraySet<String>()
private var restoredTiles: Set<String>? = null
override val currentUserId: Int
get() = userId
private val contentObserver = object : ContentObserver(mainHandler) {
override fun onChange(
selfChange: Boolean,
uris: Collection<Uri>,
flags: Int,
_userId: Int
) {
if (_userId != userId) {
// Ignore changes outside of our user. We'll load the correct value on user change
return
}
loadTiles()
}
}
private val restoreReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
if (intent.action != Intent.ACTION_SETTING_RESTORED) return
processRestoreIntent(intent)
}
}
private fun processRestoreIntent(intent: Intent) {
when (intent.getStringExtra(Intent.EXTRA_SETTING_NAME)) {
Settings.Secure.QS_TILES -> {
restoredTiles = intent.getStringExtra(Intent.EXTRA_SETTING_NEW_VALUE)
?.split(",")
?.toSet()
?: run {
Log.w(TAG, "Null restored tiles for user $userId")
emptySet()
}
}
Settings.Secure.QS_AUTO_ADDED_TILES -> {
restoredTiles?.let { tiles ->
val restoredAutoAdded = intent
.getStringExtra(Intent.EXTRA_SETTING_NEW_VALUE)
?.split(",")
?: emptyList()
val autoAddedBeforeRestore = intent
.getStringExtra(Intent.EXTRA_SETTING_PREVIOUS_VALUE)
?.split(",")
?: emptyList()
val tilesToRemove = restoredAutoAdded.filter { it !in tiles }
if (tilesToRemove.isNotEmpty()) {
qsHost.removeTiles(tilesToRemove)
}
val tiles = synchronized(autoAdded) {
autoAdded.clear()
autoAdded.addAll(restoredAutoAdded + autoAddedBeforeRestore)
getTilesFromListLocked()
}
saveTiles(tiles)
} ?: run {
Log.w(TAG, "${Settings.Secure.QS_AUTO_ADDED_TILES} restored before " +
"${Settings.Secure.QS_TILES} for user $userId")
}
}
else -> {} // Do nothing for other Settings
}
}
/**
* Init method must be called after construction to start listening
*/
fun initialize() {
dumpManager.registerDumpable(TAG, this)
loadTiles()
secureSettings.registerContentObserverForUser(
secureSettings.getUriFor(Settings.Secure.QS_AUTO_ADDED_TILES),
contentObserver,
UserHandle.USER_ALL
)
registerBroadcastReceiver()
}
/**
* Unregister listeners, receivers and observers
*/
fun destroy() {
dumpManager.unregisterDumpable(TAG)
secureSettings.unregisterContentObserver(contentObserver)
unregisterBroadcastReceiver()
}
private fun registerBroadcastReceiver() {
broadcastDispatcher.registerReceiver(
restoreReceiver,
FILTER,
backgroundExecutor,
UserHandle.of(userId)
)
}
private fun unregisterBroadcastReceiver() {
broadcastDispatcher.unregisterReceiver(restoreReceiver)
}
override fun changeUser(newUser: UserHandle) {
if (newUser.identifier == userId) return
unregisterBroadcastReceiver()
userId = newUser.identifier
restoredTiles = null
loadTiles()
registerBroadcastReceiver()
}
/**
* Returns `true` if the tile has been auto-added before
*/
fun isAdded(tile: String): Boolean {
return synchronized(autoAdded) {
tile in autoAdded
}
}
/**
* Sets a tile as auto-added.
*
* From here on, [isAdded] will return true for that tile.
*/
fun setTileAdded(tile: String) {
val tiles = synchronized(autoAdded) {
if (autoAdded.add(tile)) {
getTilesFromListLocked()
} else {
null
}
}
tiles?.let { saveTiles(it) }
}
/**
* Removes a tile from the list of auto-added.
*
* This allows for this tile to be auto-added again in the future.
*/
fun setTileRemoved(tile: String) {
val tiles = synchronized(autoAdded) {
if (autoAdded.remove(tile)) {
getTilesFromListLocked()
} else {
null
}
}
tiles?.let { saveTiles(it) }
}
private fun getTilesFromListLocked(): String {
return TextUtils.join(",", autoAdded)
}
private fun saveTiles(tiles: String) {
secureSettings.putStringForUser(
Settings.Secure.QS_AUTO_ADDED_TILES,
tiles,
/* tag */ null,
/* makeDefault */ false,
userId,
/* overrideableByRestore */ true
)
}
private fun loadTiles() {
synchronized(autoAdded) {
autoAdded.clear()
autoAdded.addAll(getAdded())
}
}
private fun getAdded(): Collection<String> {
val current = secureSettings.getStringForUser(Settings.Secure.QS_AUTO_ADDED_TILES, userId)
return current?.split(",") ?: emptySet()
}
override fun dump(fd: FileDescriptor, pw: PrintWriter, args: Array<out String>) {
pw.println("Current user: $userId")
pw.println("Added tiles: $autoAdded")
}
@SysUISingleton
class Builder @Inject constructor(
private val secureSettings: SecureSettings,
private val broadcastDispatcher: BroadcastDispatcher,
private val qsHost: QSHost,
private val dumpManager: DumpManager,
@Main private val handler: Handler,
@Background private val executor: Executor
) {
private var userId: Int = 0
fun setUserId(_userId: Int): Builder {
userId = _userId
return this
}
fun build(): AutoAddTracker {
return AutoAddTracker(
secureSettings,
broadcastDispatcher,
qsHost,
dumpManager,
handler,
executor,
userId
)
}
}
}

View File

@@ -37,6 +37,7 @@ public interface QSHost {
void removeCallback(Callback callback);
TileServices getTileServices();
void removeTile(String tileSpec);
void removeTiles(Collection<String> specs);
void unmarkTileAsAutoAdded(String tileSpec);
int indexOf(String tileSpec);

View File

@@ -348,6 +348,17 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D
changeTileSpecs(tileSpecs-> tileSpecs.remove(spec));
}
/**
* Remove many tiles at once.
*
* It will only save to settings once (as opposed to {@link QSTileHost#removeTile} called
* multiple times).
*/
@Override
public void removeTiles(Collection<String> specs) {
changeTileSpecs(tileSpecs -> tileSpecs.removeAll(specs));
}
@Override
public void unmarkTileAsAutoAdded(String spec) {
if (mAutoTiles != null) mAutoTiles.unmarkTileAsAutoAdded(spec);
@@ -369,6 +380,7 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D
* @param requestPosition -1 for end, 0 for beginning, or X for insertion at position X
*/
public void addTile(String spec, int requestPosition) {
if (spec.equals("work")) Log.wtfStack(TAG, "Adding work tile");
changeTileSpecs(tileSpecs -> {
if (tileSpecs.contains(spec)) return false;
@@ -383,6 +395,7 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D
}
void saveTilesToSettings(List<String> tileSpecs) {
if (tileSpecs.contains("work")) Log.wtfStack(TAG, "Saving work tile");
mSecureSettings.putStringForUser(TILES_SETTING, TextUtils.join(",", tileSpecs),
null /* tag */, false /* default */, mCurrentUser,
true /* overrideable by restore */);

View File

@@ -14,13 +14,19 @@
package com.android.systemui.qs;
import static com.android.systemui.statusbar.phone.AutoTileManager.INVERSION;
import static com.android.systemui.statusbar.phone.AutoTileManager.SAVER;
import static com.android.systemui.statusbar.phone.AutoTileManager.WORK;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import android.content.BroadcastReceiver;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.UserHandle;
import android.provider.Settings.Secure;
import android.testing.AndroidTestingRunner;
@@ -28,13 +34,24 @@ import android.testing.TestableLooper.RunWithLooper;
import androidx.test.filters.SmallTest;
import com.android.systemui.Prefs;
import com.android.systemui.Prefs.Key;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.util.settings.FakeSettings;
import com.android.systemui.util.settings.SecureSettings;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.InOrder;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import java.util.List;
import java.util.concurrent.Executor;
@RunWith(AndroidTestingRunner.class)
@RunWithLooper
@@ -43,42 +60,38 @@ public class AutoAddTrackerTest extends SysuiTestCase {
private static final int USER = 0;
@Mock
private BroadcastDispatcher mBroadcastDispatcher;
@Mock
private QSHost mQSHost;
@Mock
private DumpManager mDumpManager;
@Captor
private ArgumentCaptor<BroadcastReceiver> mBroadcastReceiverArgumentCaptor;
@Captor
private ArgumentCaptor<IntentFilter> mIntentFilterArgumentCaptor;
private Executor mBackgroundExecutor = Runnable::run; // Direct executor
private AutoAddTracker mAutoTracker;
private SecureSettings mSecureSettings;
@Before
public void setUp() {
Secure.putString(mContext.getContentResolver(), Secure.QS_AUTO_ADDED_TILES, "");
}
MockitoAnnotations.initMocks(this);
@Test
public void testMigration() {
Prefs.putBoolean(mContext, Key.QS_DATA_SAVER_ADDED, true);
Prefs.putBoolean(mContext, Key.QS_WORK_ADDED, true);
mAutoTracker = new AutoAddTracker(mContext, USER);
mSecureSettings = new FakeSettings();
mSecureSettings.putStringForUser(Secure.QS_AUTO_ADDED_TILES, null, USER);
mAutoTracker = createAutoAddTracker(USER);
mAutoTracker.initialize();
assertTrue(mAutoTracker.isAdded(SAVER));
assertTrue(mAutoTracker.isAdded(WORK));
assertFalse(mAutoTracker.isAdded(INVERSION));
// These keys have been removed; retrieving their values should always return the default.
assertTrue(Prefs.getBoolean(mContext, Key.QS_DATA_SAVER_ADDED, true ));
assertFalse(Prefs.getBoolean(mContext, Key.QS_DATA_SAVER_ADDED, false));
assertTrue(Prefs.getBoolean(mContext, Key.QS_WORK_ADDED, true));
assertFalse(Prefs.getBoolean(mContext, Key.QS_WORK_ADDED, false));
mAutoTracker.destroy();
}
@Test
public void testChangeFromBackup() {
mAutoTracker = new AutoAddTracker(mContext, USER);
mAutoTracker.initialize();
assertFalse(mAutoTracker.isAdded(SAVER));
Secure.putString(mContext.getContentResolver(), Secure.QS_AUTO_ADDED_TILES, SAVER);
mAutoTracker.mObserver.onChange(false);
mSecureSettings.putStringForUser(Secure.QS_AUTO_ADDED_TILES, SAVER, USER);
assertTrue(mAutoTracker.isAdded(SAVER));
@@ -87,9 +100,6 @@ public class AutoAddTrackerTest extends SysuiTestCase {
@Test
public void testSetAdded() {
mAutoTracker = new AutoAddTracker(mContext, USER);
mAutoTracker.initialize();
assertFalse(mAutoTracker.isAdded(SAVER));
mAutoTracker.setTileAdded(SAVER);
@@ -100,14 +110,12 @@ public class AutoAddTrackerTest extends SysuiTestCase {
@Test
public void testPersist() {
mAutoTracker = new AutoAddTracker(mContext, USER);
mAutoTracker.initialize();
assertFalse(mAutoTracker.isAdded(SAVER));
mAutoTracker.setTileAdded(SAVER);
mAutoTracker.destroy();
mAutoTracker = new AutoAddTracker(mContext, USER);
mAutoTracker = createAutoAddTracker(USER);
mAutoTracker.initialize();
assertTrue(mAutoTracker.isAdded(SAVER));
@@ -116,22 +124,158 @@ public class AutoAddTrackerTest extends SysuiTestCase {
@Test
public void testIndependentUsers() {
mAutoTracker = new AutoAddTracker(mContext, USER);
mAutoTracker.initialize();
mAutoTracker.setTileAdded(SAVER);
mAutoTracker = new AutoAddTracker(mContext, USER + 1);
mAutoTracker = createAutoAddTracker(USER + 1);
mAutoTracker.initialize();
assertFalse(mAutoTracker.isAdded(SAVER));
}
@Test
public void testChangeUser() {
mAutoTracker = new AutoAddTracker(mContext, USER);
mAutoTracker.initialize();
mAutoTracker.setTileAdded(SAVER);
mAutoTracker = new AutoAddTracker(mContext, USER + 1);
mAutoTracker = createAutoAddTracker(USER + 1);
mAutoTracker.changeUser(UserHandle.of(USER));
assertTrue(mAutoTracker.isAdded(SAVER));
}
@Test
public void testBroadcastReceiverRegistered() {
verify(mBroadcastDispatcher).registerReceiver(
any(), mIntentFilterArgumentCaptor.capture(), any(), eq(UserHandle.of(USER)));
assertTrue(
mIntentFilterArgumentCaptor.getValue().hasAction(Intent.ACTION_SETTING_RESTORED));
}
@Test
public void testBroadcastReceiverChangesWithUser() {
mAutoTracker.changeUser(UserHandle.of(USER + 1));
InOrder inOrder = Mockito.inOrder(mBroadcastDispatcher);
inOrder.verify(mBroadcastDispatcher).unregisterReceiver(any());
inOrder.verify(mBroadcastDispatcher)
.registerReceiver(any(), any(), any(), eq(UserHandle.of(USER + 1)));
}
@Test
public void testSettingRestoredWithTilesNotRemovedInSource_noAutoAddedInTarget() {
verify(mBroadcastDispatcher).registerReceiver(
mBroadcastReceiverArgumentCaptor.capture(), any(), any(), any());
// These tiles were present in the original device
String restoredTiles = "saver,work,internet,cast";
Intent restoreTilesIntent = makeRestoreIntent(Secure.QS_TILES, null, restoredTiles);
mBroadcastReceiverArgumentCaptor.getValue().onReceive(mContext, restoreTilesIntent);
// And these tiles have been auto-added in the original device
// (no auto-added before restore)
String restoredAutoAddTiles = "work";
Intent restoreAutoAddTilesIntent =
makeRestoreIntent(Secure.QS_AUTO_ADDED_TILES, null, restoredAutoAddTiles);
mBroadcastReceiverArgumentCaptor.getValue().onReceive(mContext, restoreAutoAddTilesIntent);
// Then, don't remove any current tiles
verify(mQSHost, never()).removeTiles(any());
assertEquals(restoredAutoAddTiles,
mSecureSettings.getStringForUser(Secure.QS_AUTO_ADDED_TILES, USER));
}
@Test
public void testSettingRestoredWithTilesRemovedInSource_noAutoAddedInTarget() {
verify(mBroadcastDispatcher)
.registerReceiver(mBroadcastReceiverArgumentCaptor.capture(), any(), any(), any());
// These tiles were present in the original device
String restoredTiles = "saver,internet,cast";
Intent restoreTilesIntent = makeRestoreIntent(Secure.QS_TILES, null, restoredTiles);
mBroadcastReceiverArgumentCaptor.getValue().onReceive(mContext, restoreTilesIntent);
// And these tiles have been auto-added in the original device
// (no auto-added before restore)
String restoredAutoAddTiles = "work";
Intent restoreAutoAddTilesIntent =
makeRestoreIntent(Secure.QS_AUTO_ADDED_TILES, null, restoredAutoAddTiles);
mBroadcastReceiverArgumentCaptor.getValue().onReceive(mContext, restoreAutoAddTilesIntent);
// Then, remove work tile
verify(mQSHost).removeTiles(List.of("work"));
assertEquals(restoredAutoAddTiles,
mSecureSettings.getStringForUser(Secure.QS_AUTO_ADDED_TILES, USER));
}
@Test
public void testSettingRestoredWithTilesRemovedInSource_sameAutoAddedinTarget() {
verify(mBroadcastDispatcher)
.registerReceiver(mBroadcastReceiverArgumentCaptor.capture(), any(), any(), any());
// These tiles were present in the original device
String restoredTiles = "saver,internet,cast";
Intent restoreTilesIntent =
makeRestoreIntent(Secure.QS_TILES, "saver, internet, cast, work", restoredTiles);
mBroadcastReceiverArgumentCaptor.getValue().onReceive(mContext, restoreTilesIntent);
// And these tiles have been auto-added in the original device
// (no auto-added before restore)
String restoredAutoAddTiles = "work";
Intent restoreAutoAddTilesIntent =
makeRestoreIntent(Secure.QS_AUTO_ADDED_TILES, "work", restoredAutoAddTiles);
mBroadcastReceiverArgumentCaptor.getValue().onReceive(mContext, restoreAutoAddTilesIntent);
// Then, remove work tile
verify(mQSHost).removeTiles(List.of("work"));
assertEquals(restoredAutoAddTiles,
mSecureSettings.getStringForUser(Secure.QS_AUTO_ADDED_TILES, USER));
}
@Test
public void testSettingRestoredWithTilesRemovedInSource_othersAutoAddedinTarget() {
verify(mBroadcastDispatcher)
.registerReceiver(mBroadcastReceiverArgumentCaptor.capture(), any(), any(), any());
// These tiles were present in the original device
String restoredTiles = "saver,internet,cast";
Intent restoreTilesIntent =
makeRestoreIntent(Secure.QS_TILES, "saver, internet, cast, work", restoredTiles);
mBroadcastReceiverArgumentCaptor.getValue().onReceive(mContext, restoreTilesIntent);
// And these tiles have been auto-added in the original device
// (no auto-added before restore)
String restoredAutoAddTiles = "work";
Intent restoreAutoAddTilesIntent =
makeRestoreIntent(Secure.QS_AUTO_ADDED_TILES, "inversion", restoredAutoAddTiles);
mBroadcastReceiverArgumentCaptor.getValue().onReceive(mContext, restoreAutoAddTilesIntent);
// Then, remove work tile
verify(mQSHost).removeTiles(List.of("work"));
String setting = mSecureSettings.getStringForUser(Secure.QS_AUTO_ADDED_TILES, USER);
assertEquals(2, setting.split(",").length);
assertTrue(setting.contains("work"));
assertTrue(setting.contains("inversion"));
}
private Intent makeRestoreIntent(
String settingName, String previousValue, String restoredValue) {
Intent intent = new Intent(Intent.ACTION_SETTING_RESTORED);
intent.putExtra(Intent.EXTRA_SETTING_NAME, settingName);
intent.putExtra(Intent.EXTRA_SETTING_PREVIOUS_VALUE, previousValue);
intent.putExtra(Intent.EXTRA_SETTING_NEW_VALUE, restoredValue);
return intent;
}
private AutoAddTracker createAutoAddTracker(int user) {
// Null handler wil dispatch sync.
return new AutoAddTracker(
mSecureSettings,
mBroadcastDispatcher,
mQSHost,
mDumpManager,
null,
mBackgroundExecutor,
user
);
}
}

View File

@@ -18,14 +18,11 @@ package com.android.systemui.qs;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;
import static junit.framework.TestCase.assertFalse;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.isNull;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
@@ -68,12 +65,12 @@ import com.android.systemui.statusbar.phone.AutoTileManager;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.phone.StatusBarIconController;
import com.android.systemui.tuner.TunerService;
import com.android.systemui.util.settings.FakeSettings;
import com.android.systemui.util.settings.SecureSettings;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@@ -121,7 +118,6 @@ public class QSTileHostTest extends SysuiTestCase {
private UiEventLogger mUiEventLogger;
@Mock
private UserTracker mUserTracker;
@Mock
private SecureSettings mSecureSettings;
@Mock
private CustomTileStatePersister mCustomTileStatePersister;
@@ -135,14 +131,15 @@ public class QSTileHostTest extends SysuiTestCase {
MockitoAnnotations.initMocks(this);
mLooper = TestableLooper.get(this);
mHandler = new Handler(mLooper.getLooper());
mSecureSettings = new FakeSettings();
mSecureSettings.putStringForUser(
QSTileHost.TILES_SETTING, "", "", false, mUserTracker.getUserId(), false);
mQSTileHost = new TestQSTileHost(mContext, mIconController, mDefaultFactory, mHandler,
mLooper.getLooper(), mPluginManager, mTunerService, mAutoTiles, mDumpManager,
mBroadcastDispatcher, mStatusBar, mQSLogger, mUiEventLogger, mUserTracker,
mSecureSettings, mCustomTileStatePersister);
setUpTileFactory();
when(mSecureSettings.getStringForUser(eq(QSTileHost.TILES_SETTING), anyInt()))
.thenReturn("");
}
private void setUpTileFactory() {
@@ -365,6 +362,16 @@ public class QSTileHostTest extends SysuiTestCase {
.removeState(new TileServiceKey(CUSTOM_TILE, mQSTileHost.getUserId()));
}
@Test
public void testRemoveTiles() {
List<String> tiles = List.of("spec1", "spec2", "spec3");
mQSTileHost.saveTilesToSettings(tiles);
mQSTileHost.removeTiles(List.of("spec1", "spec2"));
assertEquals(List.of("spec3"), mQSTileHost.mTileSpecs);
}
private class TestQSTileHost extends QSTileHost {
TestQSTileHost(Context context, StatusBarIconController iconController,
QSFactory defaultFactory, Handler mainHandler, Looper bgLooper,
@@ -390,14 +397,11 @@ public class QSTileHostTest extends SysuiTestCase {
@Override
void saveTilesToSettings(List<String> tileSpecs) {
super.saveTilesToSettings(tileSpecs);
ArgumentCaptor<String> specs = ArgumentCaptor.forClass(String.class);
verify(mSecureSettings, atLeastOnce()).putStringForUser(eq(QSTileHost.TILES_SETTING),
specs.capture(), isNull(), eq(false), anyInt(), eq(true));
// After tiles are changed, make sure to call onTuningChanged with the new setting if it
// changed
onTuningChanged(TILES_SETTING, specs.getValue());
String specs = mSecureSettings.getStringForUser(
QSTileHost.TILES_SETTING, mUserTracker.getUserId());
onTuningChanged(TILES_SETTING, specs);
}
}