Merge "When a user is removed make sure we remove their persisted bubbles" into tm-dev am: f0f1105de7

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

Change-Id: Iabbdc36ec81659a3294d646a854e7dbd6dd731c9
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
Mady Mellor
2022-05-18 20:55:16 +00:00
committed by Automerger Merge Worker
14 changed files with 345 additions and 24 deletions

View File

@@ -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
@@ -1808,6 +1828,13 @@ public class BubbleController {
});
}
@Override
public void onUserRemoved(int removedUserId) {
mMainExecutor.execute(() -> {
BubbleController.this.onUserRemoved(removedUserId);
});
}
@Override
public void onConfigChanged(Configuration newConfig) {
mMainExecutor.execute(() -> {

View File

@@ -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;

View File

@@ -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(

View File

@@ -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
@@ -242,6 +243,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.
*

View File

@@ -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 },

View File

@@ -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);

View File

@@ -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);

View File

@@ -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 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(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 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"

View File

@@ -98,6 +98,7 @@ public interface NotificationLockscreenUserManager {
interface UserChangedListener {
default void onUserChanged(int userId) {}
default void onCurrentProfilesChanged(SparseArray<UserInfo> currentProfiles) {}
default void onUserRemoved(int userId) {}
}
/** Used to hide notifications on the lockscreen */

View File

@@ -152,6 +152,15 @@ public class NotificationLockscreenUserManagerImpl implements
listener.onUserChanged(mCurrentUserId);
}
break;
case Intent.ACTION_USER_REMOVED:
int removedUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
if (removedUserId != -1) {
for (UserChangedListener listener : mListeners) {
listener.onUserRemoved(removedUserId);
}
}
updateCurrentProfilesCache();
break;
case Intent.ACTION_USER_ADDED:
case Intent.ACTION_MANAGED_PROFILE_AVAILABLE:
case Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE:
@@ -303,6 +312,7 @@ public class NotificationLockscreenUserManagerImpl implements
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_USER_SWITCHED);
filter.addAction(Intent.ACTION_USER_ADDED);
filter.addAction(Intent.ACTION_USER_REMOVED);
filter.addAction(Intent.ACTION_USER_UNLOCKED);
filter.addAction(Intent.ACTION_MANAGED_PROFILE_AVAILABLE);
filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE);

View File

@@ -271,6 +271,11 @@ public class BubblesManager implements Dumpable {
mBubbles.onCurrentProfilesChanged(currentProfiles);
}
@Override
public void onUserRemoved(int userId) {
mBubbles.onUserRemoved(userId);
}
});
mSysuiProxy = new Bubbles.SysuiProxy() {

View File

@@ -66,6 +66,7 @@ import android.hardware.face.FaceManager;
import android.os.Handler;
import android.os.PowerManager;
import android.os.UserHandle;
import android.os.UserManager;
import android.service.dreams.IDreamManager;
import android.service.notification.NotificationListenerService;
import android.service.notification.ZenModeConfig;
@@ -365,6 +366,7 @@ public class BubblesTest extends SysuiTestCase {
mStatusBarService,
mWindowManager,
mWindowManagerShellWrapper,
mock(UserManager.class),
mLauncherApps,
mBubbleLogger,
mTaskStackListener,

View File

@@ -55,6 +55,7 @@ import android.hardware.display.AmbientDisplayConfiguration;
import android.os.Handler;
import android.os.PowerManager;
import android.os.UserHandle;
import android.os.UserManager;
import android.service.dreams.IDreamManager;
import android.service.notification.NotificationListenerService;
import android.service.notification.ZenModeConfig;
@@ -330,6 +331,7 @@ public class NewNotifPipelineBubblesTest extends SysuiTestCase {
mStatusBarService,
mWindowManager,
mWindowManagerShellWrapper,
mock(UserManager.class),
mLauncherApps,
mBubbleLogger,
mTaskStackListener,

View File

@@ -19,6 +19,7 @@ package com.android.systemui.wmshell;
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.statusbar.IStatusBarService;
@@ -53,6 +54,7 @@ public class TestableBubbleController extends BubbleController {
IStatusBarService statusBarService,
WindowManager windowManager,
WindowManagerShellWrapper windowManagerShellWrapper,
UserManager userManager,
LauncherApps launcherApps,
BubbleLogger bubbleLogger,
TaskStackListenerImpl taskStackListener,
@@ -66,10 +68,10 @@ public class TestableBubbleController extends BubbleController {
TaskViewTransitions taskViewTransitions,
SyncTransactionQueue syncQueue) {
super(context, data, Runnable::run, floatingContentCoordinator, dataRepository,
statusBarService, windowManager, windowManagerShellWrapper, launcherApps,
bubbleLogger, taskStackListener, shellTaskOrganizer, positioner, displayController,
oneHandedOptional, dragAndDropController, shellMainExecutor, shellMainHandler,
new SyncExecutor(), taskViewTransitions, syncQueue);
statusBarService, windowManager, windowManagerShellWrapper, userManager,
launcherApps, bubbleLogger, taskStackListener, shellTaskOrganizer, positioner,
displayController, oneHandedOptional, dragAndDropController, shellMainExecutor,
shellMainHandler, new SyncExecutor(), taskViewTransitions, syncQueue);
setInflateSynchronously(true);
initialize();
}