summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Selim Cinek <cinek@google.com> 2020-04-04 00:30:10 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2020-04-04 00:30:10 +0000
commit822b72843d828f1ecd05418ed40677f47ac57eb1 (patch)
tree7b9662a754baea5966acef6256a6e1d750cd7b97
parent2c3bc7ccf6d9b18c1e301e3f4fa647294f7d48a6 (diff)
parentba069aeea388c572fb787dd865b91545e7d5c545 (diff)
Merge "Isolating important conversations" into rvc-dev
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java30
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/ConversationNotifications.kt13
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/VisualStabilityManager.java59
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinator.kt44
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleNotificationIdentifier.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java94
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/VisualStabilityManagerTest.java12
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinatorTest.kt77
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java25
-rwxr-xr-xservices/core/java/com/android/server/notification/NotificationManagerService.java25
16 files changed, 290 insertions, 108 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
index fe2f1f3eefc5..1297f996b743 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
@@ -177,12 +177,32 @@ public class NotificationViewHierarchyManager implements DynamicPrivacyControlle
currentUserId);
ent.setSensitive(sensitive, deviceSensitive);
ent.getRow().setNeedsRedaction(needsRedaction);
- if (mGroupManager.isChildInGroupWithSummary(ent.getSbn())) {
- NotificationEntry summary = mGroupManager.getGroupSummary(ent.getSbn());
- List<NotificationEntry> orderedChildren = mTmpChildOrderMap.get(summary);
+ boolean isChildInGroup = mGroupManager.isChildInGroupWithSummary(ent.getSbn());
+
+ boolean groupChangesAllowed = mVisualStabilityManager.areGroupChangesAllowed()
+ || !ent.hasFinishedInitialization();
+ NotificationEntry parent = mGroupManager.getGroupSummary(ent.getSbn());
+ if (!groupChangesAllowed) {
+ // We don't to change groups while the user is looking at them
+ boolean wasChildInGroup = ent.isChildInGroup();
+ if (isChildInGroup && !wasChildInGroup) {
+ isChildInGroup = wasChildInGroup;
+ mVisualStabilityManager.addGroupChangesAllowedCallback(mEntryManager);
+ } else if (!isChildInGroup && wasChildInGroup) {
+ // We allow grouping changes if the group was collapsed
+ if (mGroupManager.isLogicalGroupExpanded(ent.getSbn())) {
+ isChildInGroup = wasChildInGroup;
+ parent = ent.getRow().getNotificationParent().getEntry();
+ mVisualStabilityManager.addGroupChangesAllowedCallback(mEntryManager);
+ }
+ }
+ }
+
+ if (isChildInGroup) {
+ List<NotificationEntry> orderedChildren = mTmpChildOrderMap.get(parent);
if (orderedChildren == null) {
orderedChildren = new ArrayList<>();
- mTmpChildOrderMap.put(summary, orderedChildren);
+ mTmpChildOrderMap.put(parent, orderedChildren);
}
orderedChildren.add(ent);
} else {
@@ -205,7 +225,7 @@ public class NotificationViewHierarchyManager implements DynamicPrivacyControlle
}
for (ExpandableNotificationRow viewToRemove : viewsToRemove) {
- if (mGroupManager.isChildInGroupWithSummary(viewToRemove.getEntry().getSbn())) {
+ if (mEntryManager.getPendingOrActiveNotif(viewToRemove.getEntry().getKey()) != null) {
// we are only transferring this notification to its parent, don't generate an
// animation
mListContainer.setChildTransferInProgress(true);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ConversationNotifications.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ConversationNotifications.kt
index 7ef1d0eba3f1..1696f0715865 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ConversationNotifications.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ConversationNotifications.kt
@@ -26,6 +26,7 @@ import com.android.internal.widget.ConversationLayout
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
import com.android.systemui.statusbar.notification.row.NotificationContentView
+import com.android.systemui.statusbar.phone.NotificationGroupManager
import java.util.concurrent.ConcurrentHashMap
import javax.inject.Inject
import javax.inject.Singleton
@@ -60,6 +61,7 @@ class ConversationNotificationProcessor @Inject constructor(
@Singleton
class ConversationNotificationManager @Inject constructor(
private val notificationEntryManager: NotificationEntryManager,
+ private val notificationGroupManager: NotificationGroupManager,
private val context: Context
) {
// Need this state to be thread safe, since it's accessed from the ui thread
@@ -81,10 +83,19 @@ class ConversationNotificationManager @Inject constructor(
if (rankingMap.getRanking(entry.sbn.key, ranking) &&
ranking.isConversation) {
val important = ranking.channel.isImportantConversation
+ var changed = false
entry.row?.layouts?.asSequence()
?.flatMap(::getLayouts)
?.mapNotNull { it as? ConversationLayout }
- ?.forEach { it.setIsImportantConversation(important) }
+ ?.forEach {
+ if (important != it.isImportantConversation) {
+ it.setIsImportantConversation(important)
+ changed = true
+ }
+ }
+ if (changed) {
+ notificationGroupManager.updateIsolation(entry)
+ }
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
index 77376e595819..295adae9c9ee 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
@@ -252,7 +252,7 @@ public class NotificationEntryManager implements
}
@Override
- public void onReorderingAllowed() {
+ public void onChangeAllowed() {
updateNotifications("reordering is now allowed");
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/VisualStabilityManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/VisualStabilityManager.java
index b357ada7bcf1..7ac59954cb57 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/VisualStabilityManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/VisualStabilityManager.java
@@ -42,12 +42,14 @@ public class VisualStabilityManager implements OnHeadsUpChangedListener, Dumpabl
private static final long TEMPORARY_REORDERING_ALLOWED_DURATION = 1000;
- private final ArrayList<Callback> mCallbacks = new ArrayList<>();
+ private final ArrayList<Callback> mReorderingAllowedCallbacks = new ArrayList<>();
+ private final ArrayList<Callback> mGroupChangesAllowedCallbacks = new ArrayList<>();
private final Handler mHandler;
private boolean mPanelExpanded;
private boolean mScreenOn;
private boolean mReorderingAllowed;
+ private boolean mGroupChangedAllowed;
private boolean mIsTemporaryReorderingAllowed;
private long mTemporaryReorderingStart;
private VisibilityLocationProvider mVisibilityLocationProvider;
@@ -83,13 +85,22 @@ public class VisualStabilityManager implements OnHeadsUpChangedListener, Dumpabl
/**
* Add a callback to invoke when reordering is allowed again.
- * @param callback
*/
public void addReorderingAllowedCallback(Callback callback) {
- if (mCallbacks.contains(callback)) {
+ if (mReorderingAllowedCallbacks.contains(callback)) {
return;
}
- mCallbacks.add(callback);
+ mReorderingAllowedCallbacks.add(callback);
+ }
+
+ /**
+ * Add a callback to invoke when group changes are allowed again.
+ */
+ public void addGroupChangesAllowedCallback(Callback callback) {
+ if (mGroupChangesAllowedCallbacks.contains(callback)) {
+ return;
+ }
+ mGroupChangesAllowedCallbacks.add(callback);
}
/**
@@ -97,7 +108,7 @@ public class VisualStabilityManager implements OnHeadsUpChangedListener, Dumpabl
*/
public void setPanelExpanded(boolean expanded) {
mPanelExpanded = expanded;
- updateReorderingAllowed();
+ updateAllowedStates();
}
/**
@@ -105,7 +116,7 @@ public class VisualStabilityManager implements OnHeadsUpChangedListener, Dumpabl
*/
public void setScreenOn(boolean screenOn) {
mScreenOn = screenOn;
- updateReorderingAllowed();
+ updateAllowedStates();
}
/**
@@ -116,25 +127,30 @@ public class VisualStabilityManager implements OnHeadsUpChangedListener, Dumpabl
return;
}
mPulsing = pulsing;
- updateReorderingAllowed();
+ updateAllowedStates();
}
- private void updateReorderingAllowed() {
+ private void updateAllowedStates() {
boolean reorderingAllowed =
(!mScreenOn || !mPanelExpanded || mIsTemporaryReorderingAllowed) && !mPulsing;
boolean changedToTrue = reorderingAllowed && !mReorderingAllowed;
mReorderingAllowed = reorderingAllowed;
if (changedToTrue) {
- notifyCallbacks();
+ notifyChangeAllowed(mReorderingAllowedCallbacks);
+ }
+ boolean groupChangesAllowed = (!mScreenOn || !mPanelExpanded) && !mPulsing;
+ changedToTrue = groupChangesAllowed && !mGroupChangedAllowed;
+ mGroupChangedAllowed = groupChangesAllowed;
+ if (changedToTrue) {
+ notifyChangeAllowed(mGroupChangesAllowedCallbacks);
}
}
- private void notifyCallbacks() {
- for (int i = 0; i < mCallbacks.size(); i++) {
- Callback callback = mCallbacks.get(i);
- callback.onReorderingAllowed();
+ private void notifyChangeAllowed(ArrayList<Callback> callbacks) {
+ for (int i = 0; i < callbacks.size(); i++) {
+ callbacks.get(i).onChangeAllowed();
}
- mCallbacks.clear();
+ callbacks.clear();
}
/**
@@ -145,6 +161,13 @@ public class VisualStabilityManager implements OnHeadsUpChangedListener, Dumpabl
}
/**
+ * @return whether changes in the grouping should be allowed right now.
+ */
+ public boolean areGroupChangesAllowed() {
+ return mGroupChangedAllowed;
+ }
+
+ /**
* @return whether a specific notification is allowed to reorder. Certain notifications are
* allowed to reorder even if {@link #isReorderingAllowed()} returns false, like newly added
* notifications or heads-up notifications that are out of view.
@@ -197,12 +220,12 @@ public class VisualStabilityManager implements OnHeadsUpChangedListener, Dumpabl
mTemporaryReorderingStart = SystemClock.elapsedRealtime();
}
mIsTemporaryReorderingAllowed = true;
- updateReorderingAllowed();
+ updateAllowedStates();
}
private final Runnable mOnTemporaryReorderingExpired = () -> {
mIsTemporaryReorderingAllowed = false;
- updateReorderingAllowed();
+ updateAllowedStates();
};
/**
@@ -229,9 +252,9 @@ public class VisualStabilityManager implements OnHeadsUpChangedListener, Dumpabl
public interface Callback {
/**
- * Called when reordering is allowed again.
+ * Called when changing is allowed again.
*/
- void onReorderingAllowed();
+ void onChangeAllowed();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
index d22564b2a811..dd7be2775209 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
@@ -136,7 +136,6 @@ public final class NotificationEntry extends ListEntry {
*/
public EditedSuggestionInfo editedSuggestionInfo;
- private NotificationEntry parent; // our parent (if we're in a group)
private ExpandableNotificationRow row; // the outer expanded view
private ExpandableNotificationRowController mRowController;
@@ -710,7 +709,7 @@ public final class NotificationEntry extends ListEntry {
}
public boolean isChildInGroup() {
- return parent == null;
+ return row != null && row.isChildInGroup();
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinator.kt
new file mode 100644
index 000000000000..1bac938a9fca
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinator.kt
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar.notification.collection.coordinator
+
+import com.android.systemui.statusbar.notification.collection.NotifPipeline
+import com.android.systemui.statusbar.notification.collection.NotificationEntry
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifPromoter
+import javax.inject.Inject
+import javax.inject.Singleton
+
+/**
+ * A coordinator that elevates important conversation notifications
+ */
+@Singleton
+class ConversationCoordinator @Inject constructor() : Coordinator {
+
+ private val notificationPromoter = object : NotifPromoter(TAG) {
+ override fun shouldPromoteToTopLevel(entry: NotificationEntry): Boolean {
+ return entry.channel?.isImportantConversation == true
+ }
+ }
+
+ override fun attach(pipeline: NotifPipeline) {
+ pipeline.addPromoter(notificationPromoter)
+ }
+
+ companion object {
+ private const val TAG = "ConversationCoordinator"
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.java
index 03c0ae6fde50..2b279bbd553a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.java
@@ -56,6 +56,7 @@ public class NotifCoordinators implements Dumpable {
DeviceProvisionedCoordinator deviceProvisionedCoordinator,
BubbleCoordinator bubbleCoordinator,
HeadsUpCoordinator headsUpCoordinator,
+ ConversationCoordinator conversationCoordinator,
PreparationCoordinator preparationCoordinator) {
dumpManager.registerDumpable(TAG, this);
mCoordinators.add(new HideLocallyDismissedNotifsCoordinator());
@@ -66,6 +67,7 @@ public class NotifCoordinators implements Dumpable {
mCoordinators.add(deviceProvisionedCoordinator);
mCoordinators.add(bubbleCoordinator);
if (featureFlags.isNewNotifPipelineRenderingEnabled()) {
+ mCoordinators.add(conversationCoordinator);
mCoordinators.add(headsUpCoordinator);
mCoordinators.add(preparationCoordinator);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleNotificationIdentifier.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleNotificationIdentifier.kt
index be3873a5fd77..88cca43fd1a9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleNotificationIdentifier.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleNotificationIdentifier.kt
@@ -96,7 +96,7 @@ class PeopleNotificationIdentifierImpl @Inject constructor(
return TYPE_NON_PERSON
}
- val childTypes = groupManager.getLogicalChildren(statusBarNotification)
+ val childTypes = groupManager.getChildren(statusBarNotification)
?.asSequence()
?.map { getPeopleNotificationType(it.sbn, it.ranking) }
?: return TYPE_NON_PERSON
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java
index 8e2bfb84e2dd..6fc1264d69e2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java
@@ -20,7 +20,6 @@ import static android.app.Notification.EXTRA_IS_GROUP_CONVERSATION;
import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
import static android.app.NotificationManager.IMPORTANCE_LOW;
import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED;
-import static android.provider.Settings.Secure.BUBBLE_IMPORTANT_CONVERSATIONS;
import static com.android.systemui.Interpolators.FAST_OUT_SLOW_IN;
@@ -44,7 +43,6 @@ import android.os.Handler;
import android.os.Parcelable;
import android.os.RemoteException;
import android.os.UserHandle;
-import android.provider.Settings;
import android.service.notification.StatusBarNotification;
import android.text.TextUtils;
import android.transition.ChangeBounds;
@@ -56,15 +54,12 @@ import android.util.Log;
import android.util.Slog;
import android.view.View;
import android.view.accessibility.AccessibilityEvent;
-import android.widget.Button;
-import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.android.internal.annotations.VisibleForTesting;
import com.android.settingslib.notification.ConversationIconFactory;
-import com.android.settingslib.utils.ThreadUtils;
import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.statusbar.notification.VisualStabilityManager;
@@ -517,7 +512,6 @@ public class NotificationConversationInfo extends LinearLayout implements
bgHandler.post(
new UpdateChannelRunnable(mINotificationManager, mPackageName,
mAppUid, mSelectedAction, mNotificationChannel));
- mVisualStabilityManager.temporarilyAllowReordering();
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
index 63fe7005e703..6b0df95f54dd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
@@ -337,7 +337,7 @@ public class HeadsUpManagerPhone extends HeadsUpManager implements Dumpable,
// VisualStabilityManager.Callback overrides:
@Override
- public void onReorderingAllowed() {
+ public void onChangeAllowed() {
mAnimationStateHandler.setHeadsUpGoingAwayAnimationsAllowed(false);
for (NotificationEntry entry : mEntriesToRemoveWhenReorderingAllowed) {
if (isAlerting(entry.getKey())) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java
index ccf670708e44..84dd48b6eb6b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java
@@ -17,6 +17,7 @@
package com.android.systemui.statusbar.phone;
import android.annotation.Nullable;
+import android.app.NotificationChannel;
import android.service.notification.StatusBarNotification;
import android.util.ArraySet;
import android.util.Log;
@@ -85,6 +86,17 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener, State
return group.expanded;
}
+ /**
+ * @return if the group that this notification is associated with logically is expanded
+ */
+ public boolean isLogicalGroupExpanded(StatusBarNotification sbn) {
+ NotificationGroup group = mGroupMap.get(sbn.getGroupKey());
+ if (group == null) {
+ return false;
+ }
+ return group.expanded;
+ }
+
public void setGroupExpanded(StatusBarNotification sbn, boolean expanded) {
NotificationGroup group = mGroupMap.get(getGroupKey(sbn));
if (group == null) {
@@ -147,7 +159,15 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener, State
}
}
+ /**
+ * Notify the group manager that a new entry was added
+ */
public void onEntryAdded(final NotificationEntry added) {
+ updateIsolation(added);
+ onEntryAddedInternal(added);
+ }
+
+ private void onEntryAddedInternal(final NotificationEntry added) {
if (added.isRowRemoved()) {
added.setDebugThrowable(new Throwable());
}
@@ -193,9 +213,7 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener, State
}
private void onEntryBecomingChild(NotificationEntry entry) {
- if (shouldIsolate(entry)) {
- isolateNotification(entry);
- }
+ updateIsolation(entry);
}
private void updateSuppression(NotificationGroup group) {
@@ -242,15 +260,6 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener, State
return count;
}
- private NotificationEntry getIsolatedChild(String groupKey) {
- for (StatusBarNotification sbn : mIsolatedEntries.values()) {
- if (sbn.getGroupKey().equals(groupKey) && isIsolated(sbn.getKey())) {
- return mGroupMap.get(sbn.getKey()).summary;
- }
- }
- return null;
- }
-
/**
* Update an entry's group information
* @param entry notification entry to update
@@ -278,7 +287,7 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener, State
if (mGroupMap.get(getGroupKey(entry.getKey(), oldGroupKey)) != null) {
onEntryRemovedInternal(entry, oldGroupKey, oldIsGroup, oldIsGroupSummary);
}
- onEntryAdded(entry);
+ onEntryAddedInternal(entry);
mIsUpdatingUnchangedGroup = false;
if (isIsolated(entry.getSbn().getKey())) {
mIsolatedEntries.put(entry.getKey(), entry.getSbn());
@@ -413,14 +422,29 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener, State
return null;
}
ArrayList<NotificationEntry> children = new ArrayList<>(group.children.values());
- NotificationEntry isolatedChild = getIsolatedChild(summary.getGroupKey());
- if (isolatedChild != null) {
- children.add(isolatedChild);
+ for (StatusBarNotification sbn : mIsolatedEntries.values()) {
+ if (sbn.getGroupKey().equals(summary.getGroupKey())) {
+ children.add(mGroupMap.get(sbn.getKey()).summary);
+ }
}
return children;
}
/**
+ * Get the children that are in the summary's group, not including those isolated.
+ *
+ * @param summary summary of a group
+ * @return list of the children
+ */
+ public @Nullable ArrayList<NotificationEntry> getChildren(StatusBarNotification summary) {
+ NotificationGroup group = mGroupMap.get(summary.getGroupKey());
+ if (group == null) {
+ return null;
+ }
+ return new ArrayList<>(group.children.values());
+ }
+
+ /**
* If there is a {@link NotificationGroup} associated with the provided entry, this method
* will update the suppression of that group.
*/
@@ -495,17 +519,7 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener, State
@Override
public void onHeadsUpStateChanged(NotificationEntry entry, boolean isHeadsUp) {
- onAlertStateChanged(entry, isHeadsUp);
- }
-
- private void onAlertStateChanged(NotificationEntry entry, boolean isAlerting) {
- if (isAlerting) {
- if (shouldIsolate(entry)) {
- isolateNotification(entry);
- }
- } else {
- stopIsolatingNotification(entry);
- }
+ updateIsolation(entry);
}
/**
@@ -519,13 +533,17 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener, State
private boolean shouldIsolate(NotificationEntry entry) {
StatusBarNotification sbn = entry.getSbn();
- NotificationGroup notificationGroup = mGroupMap.get(sbn.getGroupKey());
if (!sbn.isGroup() || sbn.getNotification().isGroupSummary()) {
return false;
}
+ NotificationChannel channel = entry.getChannel();
+ if (channel != null && channel.isImportantConversation()) {
+ return true;
+ }
if (mHeadsUpManager != null && !mHeadsUpManager.isAlerting(entry.getKey())) {
return false;
}
+ NotificationGroup notificationGroup = mGroupMap.get(sbn.getGroupKey());
return (sbn.getNotification().fullScreenIntent != null
|| notificationGroup == null
|| !notificationGroup.expanded
@@ -545,7 +563,7 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener, State
mIsolatedEntries.put(sbn.getKey(), sbn);
- onEntryAdded(entry);
+ onEntryAddedInternal(entry);
// We also need to update the suppression of the old group, because this call comes
// even before the groupManager knows about the notification at all.
// When the notification gets added afterwards it is already isolated and therefore
@@ -557,17 +575,31 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener, State
}
/**
+ * Update the isolation of an entry, splitting it from the group.
+ */
+ public void updateIsolation(NotificationEntry entry) {
+ boolean isIsolated = isIsolated(entry.getSbn().getKey());
+ if (shouldIsolate(entry)) {
+ if (!isIsolated) {
+ isolateNotification(entry);
+ }
+ } else if (isIsolated) {
+ stopIsolatingNotification(entry);
+ }
+ }
+
+ /**
* Stop isolating a notification and re-group it with its original logical group.
*
* @param entry the notification to un-isolate
*/
private void stopIsolatingNotification(NotificationEntry entry) {
StatusBarNotification sbn = entry.getSbn();
- if (mIsolatedEntries.containsKey(sbn.getKey())) {
+ if (isIsolated(sbn.getKey())) {
// not isolated anymore, we need to update the groups
onEntryRemovedInternal(entry, entry.getSbn());
mIsolatedEntries.remove(sbn.getKey());
- onEntryAdded(entry);
+ onEntryAddedInternal(entry);
for (OnGroupChangeListener listener : mListeners) {
listener.onGroupsChanged();
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java
index ea68516e639c..e55ea41d94e5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java
@@ -98,6 +98,8 @@ public class NotificationViewHierarchyManagerTest extends SysuiTestCase {
mLockscreenUserManager);
mDependency.injectTestDependency(NotificationGroupManager.class, mGroupManager);
mDependency.injectTestDependency(VisualStabilityManager.class, mVisualStabilityManager);
+ when(mVisualStabilityManager.areGroupChangesAllowed()).thenReturn(true);
+ when(mVisualStabilityManager.isReorderingAllowed()).thenReturn(true);
mHelper = new NotificationTestHelper(mContext, mDependency, TestableLooper.get(this));
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/VisualStabilityManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/VisualStabilityManagerTest.java
index 9079223649ff..3d06c57cac37 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/VisualStabilityManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/VisualStabilityManagerTest.java
@@ -110,7 +110,7 @@ public class VisualStabilityManagerTest extends SysuiTestCase {
mVisualStabilityManager.setScreenOn(true);
mVisualStabilityManager.addReorderingAllowedCallback(mCallback);
mVisualStabilityManager.setScreenOn(false);
- verify(mCallback).onReorderingAllowed();
+ verify(mCallback).onChangeAllowed();
}
@Test
@@ -119,7 +119,7 @@ public class VisualStabilityManagerTest extends SysuiTestCase {
mVisualStabilityManager.setScreenOn(true);
mVisualStabilityManager.addReorderingAllowedCallback(mCallback);
mVisualStabilityManager.setPanelExpanded(false);
- verify(mCallback).onReorderingAllowed();
+ verify(mCallback).onChangeAllowed();
}
@Test
@@ -130,7 +130,7 @@ public class VisualStabilityManagerTest extends SysuiTestCase {
mVisualStabilityManager.setScreenOn(false);
mVisualStabilityManager.setScreenOn(true);
mVisualStabilityManager.setScreenOn(false);
- verify(mCallback).onReorderingAllowed();
+ verify(mCallback).onChangeAllowed();
}
@Test
@@ -190,7 +190,7 @@ public class VisualStabilityManagerTest extends SysuiTestCase {
mVisualStabilityManager.setPulsing(true);
mVisualStabilityManager.addReorderingAllowedCallback(mCallback);
mVisualStabilityManager.setPulsing(false);
- verify(mCallback).onReorderingAllowed();
+ verify(mCallback).onChangeAllowed();
}
@Test
@@ -204,7 +204,7 @@ public class VisualStabilityManagerTest extends SysuiTestCase {
mVisualStabilityManager.temporarilyAllowReordering();
// THEN callbacks are notified that reordering is allowed
- verify(mCallback).onReorderingAllowed();
+ verify(mCallback).onChangeAllowed();
assertTrue(mVisualStabilityManager.isReorderingAllowed());
}
@@ -218,7 +218,7 @@ public class VisualStabilityManagerTest extends SysuiTestCase {
mVisualStabilityManager.temporarilyAllowReordering();
// THEN reordering is still not allowed
- verify(mCallback, never()).onReorderingAllowed();
+ verify(mCallback, never()).onChangeAllowed();
assertFalse(mVisualStabilityManager.isReorderingAllowed());
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinatorTest.kt
new file mode 100644
index 000000000000..dfc627e14d8c
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinatorTest.kt
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.collection.coordinator
+
+import android.app.NotificationChannel
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.statusbar.notification.collection.NotifPipeline
+import com.android.systemui.statusbar.notification.collection.NotificationEntry
+import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifPromoter
+import org.junit.Assert.assertFalse
+import org.junit.Assert.assertTrue
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentCaptor
+import org.mockito.Mock
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+import org.mockito.Mockito.`when` as whenever
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+@TestableLooper.RunWithLooper
+class ConversationCoordinatorTest : SysuiTestCase() {
+
+ private var coordinator: ConversationCoordinator = ConversationCoordinator()
+
+ // captured listeners and pluggables:
+ private var promoter: NotifPromoter? = null
+
+ @Mock
+ private val pipeline: NotifPipeline? = null
+ @Mock
+ private val channel: NotificationChannel? = null
+ private var entry: NotificationEntry? = null
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+ whenever(channel!!.isImportantConversation).thenReturn(true)
+
+ coordinator.attach(pipeline!!)
+
+ // capture arguments:
+ val notifPromoterCaptor = ArgumentCaptor.forClass(NotifPromoter::class.java)
+ verify(pipeline).addPromoter(notifPromoterCaptor.capture())
+ promoter = notifPromoterCaptor.value
+
+ entry = NotificationEntryBuilder().setChannel(channel).build()
+ }
+
+ @Test
+ fun testPromotesCurrentHUN() {
+
+ // only promote important conversations
+ assertTrue(promoter!!.shouldPromoteToTopLevel(entry))
+ assertFalse(promoter!!.shouldPromoteToTopLevel(NotificationEntryBuilder().build()))
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java
index 6998edda3127..b6bd5e213dd4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java
@@ -816,29 +816,4 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
verify(mMockINotificationManager, never()).createConversationNotificationChannelForPackage(
anyString(), anyInt(), anyString(), any(), eq(CONVERSATION_ID));
}
-
- @Test
- public void testAdjustImportanceTemporarilyAllowsReordering() {
- mNotificationChannel.setImportance(IMPORTANCE_DEFAULT);
- mConversationChannel.setImportance(IMPORTANCE_DEFAULT);
- mNotificationInfo.bindNotification(
- mShortcutManager,
- mMockPackageManager,
- mMockINotificationManager,
- mVisualStabilityManager,
- TEST_PACKAGE_NAME,
- mNotificationChannel,
- mEntry,
- null,
- null,
- mIconFactory,
- true);
-
- mNotificationInfo.findViewById(R.id.silence).performClick();
- mNotificationInfo.findViewById(R.id.done).performClick();
-
- mTestableLooper.processAllMessages();
-
- verify(mVisualStabilityManager).temporarilyAllowReordering();
- }
}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index e8d8ed7a462d..ed3b9f1fc265 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -6227,7 +6227,7 @@ public class NotificationManagerService extends SystemService {
cancelNotificationLocked(
r, mSendDelete, mReason, mRank, mCount, wasPosted, listenerName);
cancelGroupChildrenLocked(r, mCallingUid, mCallingPid, listenerName,
- mSendDelete, childrenFlagChecker);
+ mSendDelete, childrenFlagChecker, mReason);
updateLightsLocked();
if (mShortcutHelper != null) {
mShortcutHelper.maybeListenForShortcutChangesForBubbles(r,
@@ -6687,7 +6687,7 @@ public class NotificationManagerService extends SystemService {
// notification was a summary and its group key changed.
if (oldIsSummary && (!isSummary || !oldGroup.equals(group))) {
cancelGroupChildrenLocked(old, callingUid, callingPid, null, false /* sendDelete */,
- null);
+ null, REASON_APP_CANCEL);
}
}
@@ -7892,7 +7892,7 @@ public class NotificationManagerService extends SystemService {
final int M = canceledNotifications.size();
for (int i = 0; i < M; i++) {
cancelGroupChildrenLocked(canceledNotifications.get(i), callingUid, callingPid,
- listenerName, false /* sendDelete */, flagChecker);
+ listenerName, false /* sendDelete */, flagChecker, reason);
}
updateLightsLocked();
}
@@ -7963,7 +7963,7 @@ public class NotificationManagerService extends SystemService {
// Warning: The caller is responsible for invoking updateLightsLocked().
@GuardedBy("mNotificationLock")
private void cancelGroupChildrenLocked(NotificationRecord r, int callingUid, int callingPid,
- String listenerName, boolean sendDelete, FlagChecker flagChecker) {
+ String listenerName, boolean sendDelete, FlagChecker flagChecker, int reason) {
Notification n = r.getNotification();
if (!n.isGroupSummary()) {
return;
@@ -7977,30 +7977,33 @@ public class NotificationManagerService extends SystemService {
}
cancelGroupChildrenByListLocked(mNotificationList, r, callingUid, callingPid, listenerName,
- sendDelete, true, flagChecker);
+ sendDelete, true, flagChecker, reason);
cancelGroupChildrenByListLocked(mEnqueuedNotifications, r, callingUid, callingPid,
- listenerName, sendDelete, false, flagChecker);
+ listenerName, sendDelete, false, flagChecker, reason);
}
@GuardedBy("mNotificationLock")
private void cancelGroupChildrenByListLocked(ArrayList<NotificationRecord> notificationList,
NotificationRecord parentNotification, int callingUid, int callingPid,
- String listenerName, boolean sendDelete, boolean wasPosted, FlagChecker flagChecker) {
+ String listenerName, boolean sendDelete, boolean wasPosted, FlagChecker flagChecker,
+ int reason) {
final String pkg = parentNotification.getSbn().getPackageName();
final int userId = parentNotification.getUserId();
- final int reason = REASON_GROUP_SUMMARY_CANCELED;
+ final int childReason = REASON_GROUP_SUMMARY_CANCELED;
for (int i = notificationList.size() - 1; i >= 0; i--) {
final NotificationRecord childR = notificationList.get(i);
final StatusBarNotification childSbn = childR.getSbn();
if ((childSbn.isGroup() && !childSbn.getNotification().isGroupSummary()) &&
childR.getGroupKey().equals(parentNotification.getGroupKey())
&& (childR.getFlags() & FLAG_FOREGROUND_SERVICE) == 0
- && (flagChecker == null || flagChecker.apply(childR.getFlags()))) {
+ && (flagChecker == null || flagChecker.apply(childR.getFlags()))
+ && (!childR.getChannel().isImportantConversation()
+ || reason != REASON_CANCEL)) {
EventLogTags.writeNotificationCancel(callingUid, callingPid, pkg, childSbn.getId(),
- childSbn.getTag(), userId, 0, 0, reason, listenerName);
+ childSbn.getTag(), userId, 0, 0, childReason, listenerName);
notificationList.remove(i);
mNotificationsByKey.remove(childR.getKey());
- cancelNotificationLocked(childR, sendDelete, reason, wasPosted, listenerName);
+ cancelNotificationLocked(childR, sendDelete, childReason, wasPosted, listenerName);
}
}
}