Current user and work profile availability in peoplehub

Fixes: 144285253
Test: manual, atest
Change-Id: I94afce96f6e164e7f4d4bb212920e3de8c5c1208
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
index 7cd29ea..c7492a2 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 @@
         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 ff4ce94..ebf7c2d 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 @@
     /** 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<UserInfo> getCurrentProfiles();
 
     void setLockscreenPublicMode(boolean isProfilePublic, int userId);
@@ -79,6 +85,7 @@
 
     /** Notified when the current user changes. */
     interface UserChangedListener {
-        void onUserChanged(int userId);
+        default void onUserChanged(int userId) {}
+        default void onCurrentProfilesChanged(SparseArray<UserInfo> currentProfiles) {}
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
index 0f3f6b7..f878d36 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 @@
         @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 @@
         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 @@
                 }
             }
         }
+        mMainHandler.post(() -> {
+            for (UserChangedListener listener : mListeners) {
+                listener.onCurrentProfilesChanged(mCurrentProfiles);
+            }
+        });
     }
 
     public boolean isAnyProfilePublicMode() {
@@ -555,6 +574,11 @@
         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 2c0c942..e81d361 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 @@
     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 784673e..45d8c97 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 @@
 
 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.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 @@
     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 @@
 @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<PeopleHubModel> {
 
+    private var userChangeSubscription: Subscription? = null
     private val dataListeners = mutableListOf<DataListener<PeopleHubModel>>()
+    private val peopleHubManagerForUser = SparseArray<PeopleHubManager>()
 
     private val notificationEntryListener = object : NotificationEntryListener {
         override fun onEntryInflated(entry: NotificationEntry, inflatedFlags: Int) =
@@ -106,31 +118,56 @@
     }
 
     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<PeopleHubModel>): 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<UserInfo>?
+                        ) = 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 @@
         }
     }
 
+    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<PersonKey, PersonModel>()
     private val inactivePeople = ArrayDeque<PersonModel>(MAX_STORED_INACTIVE_PEOPLE)
@@ -191,7 +248,7 @@
             ?: 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 f7d52b5..ad1aa83 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 @@
                 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 0764d0c..867a9b9 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 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 @@
     override fun onDataChanged(data: T) {
         lastSeen = Maybe.Just(data)
     }
-}
\ No newline at end of file
+}