diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java index 7cd29ea48199f..c7492a233a2b1 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java @@ -344,11 +344,14 @@ public class BubbleController implements ConfigurationController.ConfigurationLi mSavedBubbleKeysPerUser = new SparseSetArray<>(); mCurrentUserId = mNotifUserManager.getCurrentUserId(); mNotifUserManager.addUserChangedListener( - newUserId -> { - saveBubbles(mCurrentUserId); - mBubbleData.dismissAll(DISMISS_USER_CHANGED); - restoreBubbles(newUserId); - mCurrentUserId = newUserId; + new NotificationLockscreenUserManager.UserChangedListener() { + @Override + public void onUserChanged(int newUserId) { + BubbleController.this.saveBubbles(mCurrentUserId); + mBubbleData.dismissAll(DISMISS_USER_CHANGED); + BubbleController.this.restoreBubbles(newUserId); + mCurrentUserId = newUserId; + } }); mUserCreatedBubbles = new HashSet<>(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java index ff4ce94920824..ebf7c2d58c2d9 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java @@ -49,6 +49,12 @@ public interface NotificationLockscreenUserManager { /** Adds a listener to be notified when the current user changes. */ void addUserChangedListener(UserChangedListener listener); + /** + * Removes a listener previously registered with + * {@link #addUserChangedListener(UserChangedListener)} + */ + void removeUserChangedListener(UserChangedListener listener); + SparseArray getCurrentProfiles(); void setLockscreenPublicMode(boolean isProfilePublic, int userId); @@ -79,6 +85,7 @@ public interface NotificationLockscreenUserManager { /** Notified when the current user changes. */ interface UserChangedListener { - void onUserChanged(int userId); + default void onUserChanged(int userId) {} + default void onCurrentProfilesChanged(SparseArray currentProfiles) {} } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java index 0f3f6b7d92225..f878d36a841f7 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java @@ -117,51 +117,63 @@ public class NotificationLockscreenUserManagerImpl implements @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); - if (Intent.ACTION_USER_SWITCHED.equals(action)) { - mCurrentUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1); - updateCurrentProfilesCache(); - Log.v(TAG, "userId " + mCurrentUserId + " is in the house"); + switch (action) { + case Intent.ACTION_USER_SWITCHED: + mCurrentUserId = intent.getIntExtra( + Intent.EXTRA_USER_HANDLE, UserHandle.USER_ALL); + updateCurrentProfilesCache(); - updateLockscreenNotificationSetting(); - updatePublicMode(); - // The filtering needs to happen before the update call below in order to make sure - // the presenter has the updated notifications from the new user - getEntryManager().reapplyFilterAndSort("user switched"); - mPresenter.onUserSwitched(mCurrentUserId); + Log.v(TAG, "userId " + mCurrentUserId + " is in the house"); - for (UserChangedListener listener : mListeners) { - listener.onUserChanged(mCurrentUserId); - } - } else if (Intent.ACTION_USER_ADDED.equals(action)) { - updateCurrentProfilesCache(); - } else if (Intent.ACTION_USER_UNLOCKED.equals(action)) { - // Start the overview connection to the launcher service - Dependency.get(OverviewProxyService.class).startConnectionToCurrentUser(); - } else if (NOTIFICATION_UNLOCKED_BY_WORK_CHALLENGE_ACTION.equals(action)) { - final IntentSender intentSender = intent.getParcelableExtra(Intent.EXTRA_INTENT); - final String notificationKey = intent.getStringExtra(Intent.EXTRA_INDEX); - if (intentSender != null) { - try { - mContext.startIntentSender(intentSender, null, 0, 0, 0); - } catch (IntentSender.SendIntentException e) { - /* ignore */ + updateLockscreenNotificationSetting(); + updatePublicMode(); + // The filtering needs to happen before the update call below in order to + // make sure + // the presenter has the updated notifications from the new user + getEntryManager().reapplyFilterAndSort("user switched"); + mPresenter.onUserSwitched(mCurrentUserId); + + for (UserChangedListener listener : mListeners) { + listener.onUserChanged(mCurrentUserId); } - } - if (notificationKey != null) { - NotificationEntry entry = - getEntryManager().getActiveNotificationUnfiltered(notificationKey); - final int count = getEntryManager().getActiveNotificationsCount(); - final int rank = entry != null ? entry.getRanking().getRank() : 0; - NotificationVisibility.NotificationLocation location = - NotificationLogger.getNotificationLocation(entry); - final NotificationVisibility nv = NotificationVisibility.obtain(notificationKey, - rank, count, true, location); - try { - mBarService.onNotificationClick(notificationKey, nv); - } catch (RemoteException exception) { - /* ignore */ + break; + case Intent.ACTION_USER_ADDED: + case Intent.ACTION_MANAGED_PROFILE_AVAILABLE: + case Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE: + updateCurrentProfilesCache(); + break; + case Intent.ACTION_USER_UNLOCKED: + // Start the overview connection to the launcher service + Dependency.get(OverviewProxyService.class).startConnectionToCurrentUser(); + break; + case NOTIFICATION_UNLOCKED_BY_WORK_CHALLENGE_ACTION: + final IntentSender intentSender = intent.getParcelableExtra( + Intent.EXTRA_INTENT); + final String notificationKey = intent.getStringExtra(Intent.EXTRA_INDEX); + if (intentSender != null) { + try { + mContext.startIntentSender(intentSender, null, 0, 0, 0); + } catch (IntentSender.SendIntentException e) { + /* ignore */ + } } - } + if (notificationKey != null) { + NotificationEntry entry = + getEntryManager().getActiveNotificationUnfiltered(notificationKey); + final int count = getEntryManager().getActiveNotificationsCount(); + final int rank = entry != null ? entry.getRanking().getRank() : 0; + NotificationVisibility.NotificationLocation location = + NotificationLogger.getNotificationLocation(entry); + final NotificationVisibility nv = NotificationVisibility.obtain( + notificationKey, + rank, count, true, location); + try { + mBarService.onNotificationClick(notificationKey, nv); + } catch (RemoteException exception) { + /* ignore */ + } + } + break; } } }; @@ -266,6 +278,8 @@ public class NotificationLockscreenUserManagerImpl implements filter.addAction(Intent.ACTION_USER_SWITCHED); filter.addAction(Intent.ACTION_USER_ADDED); filter.addAction(Intent.ACTION_USER_UNLOCKED); + filter.addAction(Intent.ACTION_MANAGED_PROFILE_AVAILABLE); + filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE); mBroadcastDispatcher.registerReceiver(mBaseBroadcastReceiver, filter); IntentFilter internalFilter = new IntentFilter(); @@ -489,6 +503,11 @@ public class NotificationLockscreenUserManagerImpl implements } } } + mMainHandler.post(() -> { + for (UserChangedListener listener : mListeners) { + listener.onCurrentProfilesChanged(mCurrentProfiles); + } + }); } public boolean isAnyProfilePublicMode() { @@ -555,6 +574,11 @@ public class NotificationLockscreenUserManagerImpl implements mListeners.add(listener); } + @Override + public void removeUserChangedListener(UserChangedListener listener) { + mListeners.remove(listener); + } + // public void updatePublicMode() { // //TODO: I think there may be a race condition where mKeyguardViewManager.isShowing() returns // // false when it should be true. Therefore, if we are not on the SHADE, don't even bother diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHub.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHub.kt index 2c0c9420a8c4b..e81d361f58f7f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHub.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHub.kt @@ -37,7 +37,8 @@ data class PersonModel( val key: PersonKey, val name: CharSequence, val avatar: Drawable, - val clickIntent: PendingIntent + val clickIntent: PendingIntent, + val userId: Int ) /** Unique identifier for a Person in PeopleHub. */ diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHubNotificationListener.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHubNotificationListener.kt index 784673e64ff8c..45d8c9705b0df 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHubNotificationListener.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHubNotificationListener.kt @@ -18,13 +18,16 @@ package com.android.systemui.statusbar.notification.people import android.app.Notification import android.content.Context +import android.content.pm.UserInfo import android.graphics.Canvas import android.graphics.ColorFilter import android.graphics.PixelFormat import android.graphics.drawable.BitmapDrawable import android.graphics.drawable.Drawable import android.os.UserHandle +import android.os.UserManager import android.service.notification.StatusBarNotification +import android.util.SparseArray import android.util.TypedValue import android.view.View import android.view.ViewGroup @@ -33,12 +36,16 @@ import com.android.internal.statusbar.NotificationVisibility import com.android.internal.widget.MessagingGroup import com.android.launcher3.icons.BaseIconFactory import com.android.systemui.R +import com.android.systemui.dagger.qualifiers.Background +import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.plugins.NotificationPersonExtractorPlugin +import com.android.systemui.statusbar.NotificationLockscreenUserManager import com.android.systemui.statusbar.notification.NotificationEntryListener import com.android.systemui.statusbar.notification.NotificationEntryManager import com.android.systemui.statusbar.notification.collection.NotificationEntry import com.android.systemui.statusbar.policy.ExtensionController import java.util.ArrayDeque +import java.util.concurrent.Executor import javax.inject.Inject import javax.inject.Singleton @@ -72,7 +79,7 @@ class NotificationPersonExtractorPluginBoundary @Inject constructor( override fun extractPerson(sbn: StatusBarNotification) = plugin?.extractPerson(sbn)?.let { data -> val badged = addBadgeToDrawable(data.avatar, context, sbn.packageName, sbn.user) - PersonModel(data.key, data.name, badged, data.clickIntent) + PersonModel(data.key, data.name, badged, data.clickIntent, sbn.user.identifier) } override fun extractPersonKey(sbn: StatusBarNotification) = plugin?.extractPersonKey(sbn) @@ -84,11 +91,16 @@ class NotificationPersonExtractorPluginBoundary @Inject constructor( @Singleton class PeopleHubDataSourceImpl @Inject constructor( private val notificationEntryManager: NotificationEntryManager, - private val peopleHubManager: PeopleHubManager, - private val extractor: NotificationPersonExtractor + private val extractor: NotificationPersonExtractor, + private val userManager: UserManager, + @Background private val bgExecutor: Executor, + @Main private val mainExecutor: Executor, + private val notifLockscreenUserMgr: NotificationLockscreenUserManager ) : DataSource { + private var userChangeSubscription: Subscription? = null private val dataListeners = mutableListOf>() + private val peopleHubManagerForUser = SparseArray() private val notificationEntryListener = object : NotificationEntryListener { override fun onEntryInflated(entry: NotificationEntry, inflatedFlags: Int) = @@ -106,31 +118,56 @@ class PeopleHubDataSourceImpl @Inject constructor( } private fun removeVisibleEntry(entry: NotificationEntry) { - val key = extractor.extractPersonKey(entry.sbn) ?: entry.extractPersonKey() - if (key?.let(peopleHubManager::removeActivePerson) == true) { - updateUi() + (extractor.extractPersonKey(entry.sbn) ?: entry.extractPersonKey())?.let { key -> + val userId = entry.sbn.user.identifier + bgExecutor.execute { + val parentId = userManager.getProfileParent(userId)?.id ?: userId + mainExecutor.execute { + if (peopleHubManagerForUser[parentId]?.removeActivePerson(key) == true) { + updateUi() + } + } + } } } private fun addVisibleEntry(entry: NotificationEntry) { - val personModel = extractor.extractPerson(entry.sbn) ?: entry.extractPerson() - if (personModel?.let(peopleHubManager::addActivePerson) == true) { - updateUi() + (extractor.extractPerson(entry.sbn) ?: entry.extractPerson())?.let { personModel -> + val userId = entry.sbn.user.identifier + bgExecutor.execute { + val parentId = userManager.getProfileParent(userId)?.id ?: userId + mainExecutor.execute { + val manager = peopleHubManagerForUser[parentId] + ?: PeopleHubManager().also { peopleHubManagerForUser.put(parentId, it) } + if (manager.addActivePerson(personModel)) { + updateUi() + } + } + } } } override fun registerListener(listener: DataListener): Subscription { - val registerWithNotificationEntryManager = dataListeners.isEmpty() + val register = dataListeners.isEmpty() dataListeners.add(listener) - if (registerWithNotificationEntryManager) { + if (register) { + userChangeSubscription = notifLockscreenUserMgr.registerListener( + object : NotificationLockscreenUserManager.UserChangedListener { + override fun onUserChanged(userId: Int) = updateUi() + override fun onCurrentProfilesChanged( + currentProfiles: SparseArray? + ) = updateUi() + }) notificationEntryManager.addNotificationEntryListener(notificationEntryListener) } else { - listener.onDataChanged(peopleHubManager.getPeopleHubModel()) + getPeopleHubModelForCurrentUser()?.let(listener::onDataChanged) } return object : Subscription { override fun unsubscribe() { dataListeners.remove(listener) if (dataListeners.isEmpty()) { + userChangeSubscription?.unsubscribe() + userChangeSubscription = null notificationEntryManager .removeNotificationEntryListener(notificationEntryListener) } @@ -138,16 +175,36 @@ class PeopleHubDataSourceImpl @Inject constructor( } } + private fun getPeopleHubModelForCurrentUser(): PeopleHubModel? { + val currentUserId = notifLockscreenUserMgr.currentUserId + val model = peopleHubManagerForUser[currentUserId]?.getPeopleHubModel() + ?: return null + val currentProfiles = notifLockscreenUserMgr.currentProfiles + return model.copy(people = model.people.filter { person -> + currentProfiles[person.userId]?.isQuietModeEnabled == false + }) + } + private fun updateUi() { - val model = peopleHubManager.getPeopleHubModel() + val model = getPeopleHubModelForCurrentUser() ?: return for (listener in dataListeners) { listener.onDataChanged(model) } } } -@Singleton -class PeopleHubManager @Inject constructor() { +private fun NotificationLockscreenUserManager.registerListener( + listener: NotificationLockscreenUserManager.UserChangedListener +): Subscription { + addUserChangedListener(listener) + return object : Subscription { + override fun unsubscribe() { + removeUserChangedListener(listener) + } + } +} + +class PeopleHubManager { private val activePeople = mutableMapOf() private val inactivePeople = ArrayDeque(MAX_STORED_INACTIVE_PEOPLE) @@ -191,7 +248,7 @@ private fun NotificationEntry.extractPerson(): PersonModel? { ?: return null val drawable = extractAvatarFromRow(this) ?: return null val badgedAvatar = addBadgeToDrawable(drawable, row.context, sbn.packageName, sbn.user) - return PersonModel(key, name, badgedAvatar, clickIntent) + return PersonModel(key, name, badgedAvatar, clickIntent, sbn.user.identifier) } private fun addBadgeToDrawable( diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt index f7d52b5f5ab0d..ad1aa8370495c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt @@ -98,7 +98,12 @@ class KeyguardBypassController : Dumpable { bypassEnabled = tunerService.getValue(key, dismissByDefault) != 0 } }, Settings.Secure.FACE_UNLOCK_DISMISSES_KEYGUARD) - lockscreenUserManager.addUserChangedListener { pendingUnlockType = null } + lockscreenUserManager.addUserChangedListener( + object : NotificationLockscreenUserManager.UserChangedListener { + override fun onUserChanged(userId: Int) { + pendingUnlockType = null + } + }) } /** diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/people/PeopleHubViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/people/PeopleHubViewControllerTest.kt index 0764d0cd4b880..867a9b97d6229 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/people/PeopleHubViewControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/people/PeopleHubViewControllerTest.kt @@ -178,9 +178,10 @@ private fun castNull(): T = null as T private fun fakePersonModel( id: String, name: CharSequence, - clickIntent: PendingIntent + clickIntent: PendingIntent, + userId: Int = 0 ): PersonModel = - PersonModel(id, name, mock(Drawable::class.java), clickIntent) + PersonModel(id, name, mock(Drawable::class.java), clickIntent, userId) private fun fakePersonViewModel(name: CharSequence): PersonViewModel = PersonViewModel(name, mock(Drawable::class.java), mock({}.javaClass)) @@ -207,4 +208,4 @@ class FakeDataListener : DataListener { override fun onDataChanged(data: T) { lastSeen = Maybe.Just(data) } -} \ No newline at end of file +}