Current user and work profile availability in peoplehub

Fixes: 144285253
Test: manual, atest
Change-Id: I94afce96f6e164e7f4d4bb212920e3de8c5c1208
This commit is contained in:
Steve Elliott
2019-12-19 12:39:26 -05:00
parent 20cc19de8f
commit b47f1c7d83
7 changed files with 166 additions and 68 deletions

View File

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

View File

@@ -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<UserInfo> 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<UserInfo> currentProfiles) {}
}
}

View File

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

View File

@@ -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. */

View File

@@ -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<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 @@ 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<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 @@ 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<PersonKey, PersonModel>()
private val inactivePeople = ArrayDeque<PersonModel>(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(

View File

@@ -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
}
})
}
/**

View File

@@ -178,9 +178,10 @@ private fun <T> 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<T> : DataListener<T> {
override fun onDataChanged(data: T) {
lastSeen = Maybe.Just(data)
}
}
}