summaryrefslogtreecommitdiff
path: root/libs
diff options
context:
space:
mode:
Diffstat (limited to 'libs')
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java31
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java46
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleDataRepository.kt17
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java10
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/storage/BubbleVolatileRepository.kt56
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java4
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java1
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleDataTest.java35
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/storage/BubbleVolatileRepositoryTest.kt142
9 files changed, 321 insertions, 21 deletions
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
index a45931953c0b..f427a2c4bc95 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
@@ -66,6 +66,7 @@ import android.os.Handler;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
+import android.os.UserManager;
import android.service.notification.NotificationListenerService;
import android.service.notification.NotificationListenerService.RankingMap;
import android.util.ArraySet;
@@ -147,6 +148,7 @@ public class BubbleController {
private final FloatingContentCoordinator mFloatingContentCoordinator;
private final BubbleDataRepository mDataRepository;
private final WindowManagerShellWrapper mWindowManagerShellWrapper;
+ private final UserManager mUserManager;
private final LauncherApps mLauncherApps;
private final IStatusBarService mBarService;
private final WindowManager mWindowManager;
@@ -231,6 +233,7 @@ public class BubbleController {
@Nullable IStatusBarService statusBarService,
WindowManager windowManager,
WindowManagerShellWrapper windowManagerShellWrapper,
+ UserManager userManager,
LauncherApps launcherApps,
TaskStackListenerImpl taskStackListener,
UiEventLogger uiEventLogger,
@@ -248,8 +251,8 @@ public class BubbleController {
BubbleData data = new BubbleData(context, logger, positioner, mainExecutor);
return new BubbleController(context, data, synchronizer, floatingContentCoordinator,
new BubbleDataRepository(context, launcherApps, mainExecutor),
- statusBarService, windowManager, windowManagerShellWrapper, launcherApps,
- logger, taskStackListener, organizer, positioner, displayController,
+ statusBarService, windowManager, windowManagerShellWrapper, userManager,
+ launcherApps, logger, taskStackListener, organizer, positioner, displayController,
oneHandedOptional, dragAndDropController, mainExecutor, mainHandler, bgExecutor,
taskViewTransitions, syncQueue);
}
@@ -266,6 +269,7 @@ public class BubbleController {
@Nullable IStatusBarService statusBarService,
WindowManager windowManager,
WindowManagerShellWrapper windowManagerShellWrapper,
+ UserManager userManager,
LauncherApps launcherApps,
BubbleLogger bubbleLogger,
TaskStackListenerImpl taskStackListener,
@@ -287,6 +291,7 @@ public class BubbleController {
: statusBarService;
mWindowManager = windowManager;
mWindowManagerShellWrapper = windowManagerShellWrapper;
+ mUserManager = userManager;
mFloatingContentCoordinator = floatingContentCoordinator;
mDataRepository = dataRepository;
mLogger = bubbleLogger;
@@ -447,6 +452,10 @@ public class BubbleController {
mOneHandedOptional.ifPresent(this::registerOneHandedState);
mDragAndDropController.addListener(this::collapseStack);
+
+ // Clear out any persisted bubbles on disk that no longer have a valid user.
+ List<UserInfo> users = mUserManager.getAliveUsers();
+ mDataRepository.sanitizeBubbles(users);
}
@VisibleForTesting
@@ -590,6 +599,17 @@ public class BubbleController {
mCurrentProfiles = currentProfiles;
}
+ /** Called when a user is removed from the device, including work profiles. */
+ public void onUserRemoved(int removedUserId) {
+ UserInfo parent = mUserManager.getProfileParent(removedUserId);
+ int parentUserId = parent != null ? parent.getUserHandle().getIdentifier() : -1;
+ mBubbleData.removeBubblesForUser(removedUserId);
+ // Typically calls from BubbleData would remove bubbles from the DataRepository as well,
+ // however, this gets complicated when users are removed (mCurrentUserId won't necessarily
+ // be correct for this) so we update the repo directly.
+ mDataRepository.removeBubblesForUser(removedUserId, parentUserId);
+ }
+
/** Whether this userId belongs to the current user. */
private boolean isCurrentProfile(int userId) {
return userId == UserHandle.USER_ALL
@@ -1809,6 +1829,13 @@ public class BubbleController {
}
@Override
+ public void onUserRemoved(int removedUserId) {
+ mMainExecutor.execute(() -> {
+ BubbleController.this.onUserRemoved(removedUserId);
+ });
+ }
+
+ @Override
public void onConfigChanged(Configuration newConfig) {
mMainExecutor.execute(() -> {
BubbleController.this.onConfigChanged(newConfig);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java
index e4a0fd03860c..fa86c8436647 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java
@@ -465,7 +465,7 @@ public class BubbleData {
getOverflowBubbles(), invalidBubblesFromPackage, removeBubble);
}
- /** Dismisses all bubbles from the given package. */
+ /** Removes all bubbles from the given package. */
public void removeBubblesWithPackageName(String packageName, int reason) {
final Predicate<Bubble> bubbleMatchesPackage = bubble ->
bubble.getPackageName().equals(packageName);
@@ -477,6 +477,18 @@ public class BubbleData {
performActionOnBubblesMatching(getOverflowBubbles(), bubbleMatchesPackage, removeBubble);
}
+ /** Removes all bubbles for the given user. */
+ public void removeBubblesForUser(int userId) {
+ List<Bubble> removedBubbles = filterAllBubbles(bubble ->
+ userId == bubble.getUser().getIdentifier());
+ for (Bubble b : removedBubbles) {
+ doRemove(b.getKey(), Bubbles.DISMISS_USER_REMOVED);
+ }
+ if (!removedBubbles.isEmpty()) {
+ dispatchPendingChanges();
+ }
+ }
+
private void doAdd(Bubble bubble) {
if (DEBUG_BUBBLE_DATA) {
Log.d(TAG, "doAdd: " + bubble);
@@ -552,7 +564,8 @@ public class BubbleData {
|| reason == Bubbles.DISMISS_BLOCKED
|| reason == Bubbles.DISMISS_SHORTCUT_REMOVED
|| reason == Bubbles.DISMISS_PACKAGE_REMOVED
- || reason == Bubbles.DISMISS_USER_CHANGED;
+ || reason == Bubbles.DISMISS_USER_CHANGED
+ || reason == Bubbles.DISMISS_USER_REMOVED;
int indexToRemove = indexForKey(key);
if (indexToRemove == -1) {
@@ -1073,6 +1086,35 @@ public class BubbleData {
return null;
}
+ /**
+ * Returns a list of bubbles that match the provided predicate. This checks all types of
+ * bubbles (i.e. pending, suppressed, active, and overflowed).
+ */
+ private List<Bubble> filterAllBubbles(Predicate<Bubble> predicate) {
+ ArrayList<Bubble> matchingBubbles = new ArrayList<>();
+ for (Bubble b : mPendingBubbles.values()) {
+ if (predicate.test(b)) {
+ matchingBubbles.add(b);
+ }
+ }
+ for (Bubble b : mSuppressedBubbles.values()) {
+ if (predicate.test(b)) {
+ matchingBubbles.add(b);
+ }
+ }
+ for (Bubble b : mBubbles) {
+ if (predicate.test(b)) {
+ matchingBubbles.add(b);
+ }
+ }
+ for (Bubble b : mOverflowBubbles) {
+ if (predicate.test(b)) {
+ matchingBubbles.add(b);
+ }
+ }
+ return matchingBubbles;
+ }
+
@VisibleForTesting(visibility = PRIVATE)
void setTimeSource(TimeSource timeSource) {
mTimeSource = timeSource;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleDataRepository.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleDataRepository.kt
index 9d9e442affd3..97560f44fb06 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleDataRepository.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleDataRepository.kt
@@ -22,6 +22,7 @@ import android.content.pm.LauncherApps
import android.content.pm.LauncherApps.ShortcutQuery.FLAG_MATCH_CACHED
import android.content.pm.LauncherApps.ShortcutQuery.FLAG_MATCH_DYNAMIC
import android.content.pm.LauncherApps.ShortcutQuery.FLAG_MATCH_PINNED_BY_ANY_LAUNCHER
+import android.content.pm.UserInfo
import android.os.UserHandle
import android.util.Log
import com.android.wm.shell.bubbles.storage.BubbleEntity
@@ -73,6 +74,22 @@ internal class BubbleDataRepository(
if (entities.isNotEmpty()) persistToDisk()
}
+ /**
+ * Removes all the bubbles associated with the provided user from memory. Then persists the
+ * snapshot to disk asynchronously.
+ */
+ fun removeBubblesForUser(@UserIdInt userId: Int, @UserIdInt parentId: Int) {
+ if (volatileRepository.removeBubblesForUser(userId, parentId)) persistToDisk()
+ }
+
+ /**
+ * Remove any bubbles that don't have a user id from the provided list of users.
+ */
+ fun sanitizeBubbles(users: List<UserInfo>) {
+ val userIds = users.map { u -> u.id }
+ if (volatileRepository.sanitizeBubbles(userIds)) persistToDisk()
+ }
+
private fun transform(bubbles: List<Bubble>): List<BubbleEntity> {
return bubbles.mapNotNull { b ->
BubbleEntity(
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java
index c7db8d8d1646..8a0db0a12711 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java
@@ -57,7 +57,7 @@ public interface Bubbles {
DISMISS_NOTIF_CANCEL, DISMISS_ACCESSIBILITY_ACTION, DISMISS_NO_LONGER_BUBBLE,
DISMISS_USER_CHANGED, DISMISS_GROUP_CANCELLED, DISMISS_INVALID_INTENT,
DISMISS_OVERFLOW_MAX_REACHED, DISMISS_SHORTCUT_REMOVED, DISMISS_PACKAGE_REMOVED,
- DISMISS_NO_BUBBLE_UP, DISMISS_RELOAD_FROM_DISK})
+ DISMISS_NO_BUBBLE_UP, DISMISS_RELOAD_FROM_DISK, DISMISS_USER_REMOVED})
@Target({FIELD, LOCAL_VARIABLE, PARAMETER})
@interface DismissReason {}
@@ -76,6 +76,7 @@ public interface Bubbles {
int DISMISS_PACKAGE_REMOVED = 13;
int DISMISS_NO_BUBBLE_UP = 14;
int DISMISS_RELOAD_FROM_DISK = 15;
+ int DISMISS_USER_REMOVED = 16;
/**
* @return {@code true} if there is a bubble associated with the provided key and if its
@@ -243,6 +244,13 @@ public interface Bubbles {
void onCurrentProfilesChanged(SparseArray<UserInfo> currentProfiles);
/**
+ * Called when a user is removed.
+ *
+ * @param removedUserId the id of the removed user.
+ */
+ void onUserRemoved(int removedUserId);
+
+ /**
* Called when config changed.
*
* @param newConfig the new config.
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/storage/BubbleVolatileRepository.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/storage/BubbleVolatileRepository.kt
index a5267d8be9fe..0d3ba9a78e35 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/storage/BubbleVolatileRepository.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/storage/BubbleVolatileRepository.kt
@@ -15,6 +15,7 @@
*/
package com.android.wm.shell.bubbles.storage
+import android.annotation.UserIdInt
import android.content.pm.LauncherApps
import android.os.UserHandle
import android.util.SparseArray
@@ -95,10 +96,63 @@ class BubbleVolatileRepository(private val launcherApps: LauncherApps) {
}
@Synchronized
- fun removeBubbles(userId: Int, bubbles: List<BubbleEntity>) =
+ fun removeBubbles(@UserIdInt userId: Int, bubbles: List<BubbleEntity>) =
uncache(bubbles.filter { b: BubbleEntity ->
getEntities(userId).removeIf { e: BubbleEntity -> b.key == e.key } })
+ /**
+ * Removes all the bubbles associated with the provided userId.
+ * @return whether bubbles were removed or not.
+ */
+ @Synchronized
+ fun removeBubblesForUser(@UserIdInt userId: Int, @UserIdInt parentUserId: Int): Boolean {
+ if (parentUserId != -1) {
+ return removeBubblesForUserWithParent(userId, parentUserId)
+ } else {
+ val entities = entitiesByUser.get(userId)
+ entitiesByUser.remove(userId)
+ return entities != null
+ }
+ }
+
+ /**
+ * Removes all the bubbles associated with the provided userId when that userId is part of
+ * a profile (e.g. managed account).
+ *
+ * @return whether bubbles were removed or not.
+ */
+ @Synchronized
+ private fun removeBubblesForUserWithParent(
+ @UserIdInt userId: Int,
+ @UserIdInt parentUserId: Int
+ ): Boolean {
+ return entitiesByUser.get(parentUserId).removeIf { b: BubbleEntity -> b.userId == userId }
+ }
+
+ /**
+ * Goes through all the persisted bubbles and removes them if the user is not in the active
+ * list of users.
+ *
+ * @return whether the list of bubbles changed or not (i.e. was a removal made).
+ */
+ @Synchronized
+ fun sanitizeBubbles(activeUsers: List<Int>): Boolean {
+ for (i in 0 until entitiesByUser.size()) {
+ // First check if the user is a parent / top-level user
+ val parentUserId = entitiesByUser.keyAt(i)
+ if (!activeUsers.contains(parentUserId)) {
+ return removeBubblesForUser(parentUserId, -1)
+ } else {
+ // Then check if each of the bubbles in the top-level user, still has a valid user
+ // as it could belong to a profile and have a different id from the parent.
+ return entitiesByUser.get(parentUserId).removeIf { b: BubbleEntity ->
+ !activeUsers.contains(b.userId)
+ }
+ }
+ }
+ return false
+ }
+
private fun cache(bubbles: List<BubbleEntity>) {
bubbles.groupBy { ShortcutKey(it.userId, it.packageName) }.forEach { (key, bubbles) ->
launcherApps.cacheShortcuts(key.pkg, bubbles.map { it.shortcutId },
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
index 98de60c419b3..b3799e2cf8d9 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
@@ -20,6 +20,7 @@ import android.animation.AnimationHandler;
import android.content.Context;
import android.content.pm.LauncherApps;
import android.os.Handler;
+import android.os.UserManager;
import android.view.WindowManager;
import com.android.internal.jank.InteractionJankMonitor;
@@ -106,6 +107,7 @@ public class WMShellModule {
IStatusBarService statusBarService,
WindowManager windowManager,
WindowManagerShellWrapper windowManagerShellWrapper,
+ UserManager userManager,
LauncherApps launcherApps,
TaskStackListenerImpl taskStackListener,
UiEventLogger uiEventLogger,
@@ -120,7 +122,7 @@ public class WMShellModule {
SyncTransactionQueue syncQueue) {
return BubbleController.create(context, null /* synchronizer */,
floatingContentCoordinator, statusBarService, windowManager,
- windowManagerShellWrapper, launcherApps, taskStackListener,
+ windowManagerShellWrapper, userManager, launcherApps, taskStackListener,
uiEventLogger, organizer, displayController, oneHandedOptional,
dragAndDropController, mainExecutor, mainHandler, bgExecutor,
taskViewTransitions, syncQueue);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java
index c3369e4bb90b..49b6968f9417 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java
@@ -254,6 +254,7 @@ public class BackAnimationControllerTest {
verify(mIOnBackInvokedCallback, never()).onBackInvoked();
}
+ @Test
public void ignoresGesture_transitionInProgress() throws RemoteException {
mController.setBackToLauncherCallback(mIOnBackInvokedCallback);
RemoteAnimationTarget animationTarget = createAnimationTarget();
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleDataTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleDataTest.java
index bde94d9d6c29..e6711aca19c1 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleDataTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleDataTest.java
@@ -129,8 +129,8 @@ public class BubbleDataTest extends ShellTestCase {
mEntryA3 = createBubbleEntry(1, "a3", "package.a", null);
mEntryB1 = createBubbleEntry(1, "b1", "package.b", null);
mEntryB2 = createBubbleEntry(1, "b2", "package.b", null);
- mEntryB3 = createBubbleEntry(1, "b3", "package.b", null);
- mEntryC1 = createBubbleEntry(1, "c1", "package.c", null);
+ mEntryB3 = createBubbleEntry(11, "b3", "package.b", null);
+ mEntryC1 = createBubbleEntry(11, "c1", "package.c", null);
NotificationListenerService.Ranking ranking =
mock(NotificationListenerService.Ranking.class);
@@ -1058,6 +1058,37 @@ public class BubbleDataTest extends ShellTestCase {
assertBubbleListContains(mBubbleA2, mBubbleA1, mBubbleLocusId);
}
+ @Test
+ public void test_removeBubblesForUser() {
+ // A is user 1
+ sendUpdatedEntryAtTime(mEntryA1, 2000);
+ sendUpdatedEntryAtTime(mEntryA2, 3000);
+ // B & C belong to user 11
+ sendUpdatedEntryAtTime(mEntryB3, 4000);
+ sendUpdatedEntryAtTime(mEntryC1, 5000);
+ mBubbleData.setListener(mListener);
+
+ mBubbleData.dismissBubbleWithKey(mEntryA1.getKey(), Bubbles.DISMISS_USER_GESTURE);
+ verifyUpdateReceived();
+ assertOverflowChangedTo(ImmutableList.of(mBubbleA1));
+ assertBubbleListContains(mBubbleC1, mBubbleB3, mBubbleA2);
+
+ // Remove all the A bubbles
+ mBubbleData.removeBubblesForUser(1);
+ verifyUpdateReceived();
+
+ // Verify the update has the removals.
+ BubbleData.Update update = mUpdateCaptor.getValue();
+ assertThat(update.removedBubbles.get(0)).isEqualTo(
+ Pair.create(mBubbleA2, Bubbles.DISMISS_USER_REMOVED));
+ assertThat(update.removedBubbles.get(1)).isEqualTo(
+ Pair.create(mBubbleA1, Bubbles.DISMISS_USER_REMOVED));
+
+ // Verify no A bubbles in active or overflow.
+ assertBubbleListContains(mBubbleC1, mBubbleB3);
+ assertOverflowChangedTo(ImmutableList.of());
+ }
+
private void verifyUpdateReceived() {
verify(mListener).applyUpdate(mUpdateCaptor.capture());
reset(mListener);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/storage/BubbleVolatileRepositoryTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/storage/BubbleVolatileRepositoryTest.kt
index bfdf5208bbf0..77c70557fb70 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/storage/BubbleVolatileRepositoryTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/storage/BubbleVolatileRepositoryTest.kt
@@ -23,14 +23,19 @@ import android.testing.AndroidTestingRunner
import androidx.test.filters.SmallTest
import org.junit.Test
import com.android.wm.shell.ShellTestCase
+import com.google.common.truth.Truth.assertThat
import junit.framework.Assert.assertEquals
import org.junit.Before
import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers.any
+import org.mockito.ArgumentMatchers.anyInt
+import org.mockito.ArgumentMatchers.anyString
import org.mockito.ArgumentMatchers.eq
import org.mockito.Mockito
import org.mockito.Mockito.mock
-import org.mockito.Mockito.verify
+import org.mockito.Mockito.never
import org.mockito.Mockito.reset
+import org.mockito.Mockito.verify
@SmallTest
@RunWith(AndroidTestingRunner::class)
@@ -41,17 +46,17 @@ class BubbleVolatileRepositoryTest : ShellTestCase() {
private val user11 = UserHandle.of(11)
// user, package, shortcut, notification key, height, res-height, title, taskId, locusId
- private val bubble1 = BubbleEntity(0, "com.example.messenger", "shortcut-1",
- "0key-1", 120, 0, null, 1, null)
- private val bubble2 = BubbleEntity(10, "com.example.chat", "alice and bob",
- "10key-2", 0, 16537428, "title", 2, null)
- private val bubble3 = BubbleEntity(0, "com.example.messenger", "shortcut-2",
- "0key-3", 120, 0, null, INVALID_TASK_ID, null)
-
- private val bubble11 = BubbleEntity(11, "com.example.messenger",
- "shortcut-1", "01key-1", 120, 0, null, 3)
- private val bubble12 = BubbleEntity(11, "com.example.chat", "alice and bob",
- "11key-2", 0, 16537428, "title", INVALID_TASK_ID)
+ private val bubble1 = BubbleEntity(user0.identifier,
+ "com.example.messenger", "shortcut-1", "0key-1", 120, 0, null, 1, null)
+ private val bubble2 = BubbleEntity(user10_managed.identifier,
+ "com.example.chat", "alice and bob", "10key-2", 0, 16537428, "title", 2, null)
+ private val bubble3 = BubbleEntity(user0.identifier,
+ "com.example.messenger", "shortcut-2", "0key-3", 120, 0, null, INVALID_TASK_ID, null)
+
+ private val bubble11 = BubbleEntity(user11.identifier,
+ "com.example.messenger", "shortcut-1", "01key-1", 120, 0, null, 3)
+ private val bubble12 = BubbleEntity(user11.identifier,
+ "com.example.chat", "alice and bob", "11key-2", 0, 16537428, "title", INVALID_TASK_ID)
private val user0bubbles = listOf(bubble1, bubble2, bubble3)
private val user11bubbles = listOf(bubble11, bubble12)
@@ -151,6 +156,119 @@ class BubbleVolatileRepositoryTest : ShellTestCase() {
repository.addBubbles(user0.identifier, listOf(bubbleModified))
assertEquals(bubbleModified, repository.getEntities(user0.identifier).get(0))
}
+
+ @Test
+ fun testRemoveBubblesForUser() {
+ repository.addBubbles(user0.identifier, user0bubbles)
+ assertThat(repository.getEntities(user0.identifier).toList())
+ .isEqualTo(listOf(bubble1, bubble2, bubble3))
+
+ val ret = repository.removeBubblesForUser(user0.identifier, -1)
+ assertThat(ret).isTrue() // bubbles were removed
+
+ assertThat(repository.getEntities(user0.identifier).toList()).isEmpty()
+ verify(launcherApps, never()).uncacheShortcuts(anyString(),
+ any(),
+ any(UserHandle::class.java), anyInt())
+ }
+
+ @Test
+ fun testRemoveBubblesForUser_parentUserRemoved() {
+ repository.addBubbles(user0.identifier, user0bubbles)
+ // bubble2 is the work profile bubble
+ assertThat(repository.getEntities(user0.identifier).toList())
+ .isEqualTo(listOf(bubble1, bubble2, bubble3))
+
+ val ret = repository.removeBubblesForUser(user10_managed.identifier, user0.identifier)
+ assertThat(ret).isTrue() // bubbles were removed
+
+ assertThat(repository.getEntities(user0.identifier).toList())
+ .isEqualTo(listOf(bubble1, bubble3))
+ verify(launcherApps, never()).uncacheShortcuts(anyString(),
+ any(),
+ any(UserHandle::class.java), anyInt())
+ }
+
+ @Test
+ fun testRemoveBubblesForUser_withoutBubbles() {
+ repository.addBubbles(user0.identifier, user0bubbles)
+ assertThat(repository.getEntities(user0.identifier).toList())
+ .isEqualTo(listOf(bubble1, bubble2, bubble3))
+
+ val ret = repository.removeBubblesForUser(user11.identifier, -1)
+ assertThat(ret).isFalse() // bubbles were NOT removed
+
+ assertThat(repository.getEntities(user0.identifier).toList())
+ .isEqualTo(listOf(bubble1, bubble2, bubble3))
+ verify(launcherApps, never()).uncacheShortcuts(anyString(),
+ any(),
+ any(UserHandle::class.java), anyInt())
+ }
+
+ @Test
+ fun testSanitizeBubbles_noChanges() {
+ repository.addBubbles(user0.identifier, user0bubbles)
+ assertThat(repository.getEntities(user0.identifier).toList())
+ .isEqualTo(listOf(bubble1, bubble2, bubble3))
+ repository.addBubbles(user11.identifier, user11bubbles)
+ assertThat(repository.getEntities(user11.identifier).toList())
+ .isEqualTo(listOf(bubble11, bubble12))
+
+ val ret = repository.sanitizeBubbles(listOf(user0.identifier,
+ user10_managed.identifier,
+ user11.identifier))
+ assertThat(ret).isFalse() // bubbles were NOT removed
+
+ verify(launcherApps, never()).uncacheShortcuts(anyString(),
+ any(),
+ any(UserHandle::class.java), anyInt())
+ }
+
+ @Test
+ fun testSanitizeBubbles_userRemoved() {
+ repository.addBubbles(user0.identifier, user0bubbles)
+ assertThat(repository.getEntities(user0.identifier).toList())
+ .isEqualTo(listOf(bubble1, bubble2, bubble3))
+ repository.addBubbles(user11.identifier, user11bubbles)
+ assertThat(repository.getEntities(user11.identifier).toList())
+ .isEqualTo(listOf(bubble11, bubble12))
+
+ val ret = repository.sanitizeBubbles(listOf(user11.identifier))
+ assertThat(ret).isTrue() // bubbles were removed
+
+ assertThat(repository.getEntities(user0.identifier).toList()).isEmpty()
+ verify(launcherApps, never()).uncacheShortcuts(anyString(),
+ any(),
+ any(UserHandle::class.java), anyInt())
+
+ // User 11 bubbles should still be here
+ assertThat(repository.getEntities(user11.identifier).toList())
+ .isEqualTo(listOf(bubble11, bubble12))
+ }
+
+ @Test
+ fun testSanitizeBubbles_userParentRemoved() {
+ repository.addBubbles(user0.identifier, user0bubbles)
+ assertThat(repository.getEntities(user0.identifier).toList())
+ .isEqualTo(listOf(bubble1, bubble2, bubble3))
+
+ repository.addBubbles(user11.identifier, user11bubbles)
+ assertThat(repository.getEntities(user11.identifier).toList())
+ .isEqualTo(listOf(bubble11, bubble12))
+
+ val ret = repository.sanitizeBubbles(listOf(user0.identifier, user11.identifier))
+ assertThat(ret).isTrue() // bubbles were removed
+ // bubble2 is the work profile bubble and should be removed
+ assertThat(repository.getEntities(user0.identifier).toList())
+ .isEqualTo(listOf(bubble1, bubble3))
+ verify(launcherApps, never()).uncacheShortcuts(anyString(),
+ any(),
+ any(UserHandle::class.java), anyInt())
+
+ // User 11 bubbles should still be here
+ assertThat(repository.getEntities(user11.identifier).toList())
+ .isEqualTo(listOf(bubble11, bubble12))
+ }
}
private const val PKG_MESSENGER = "com.example.messenger"