Merge "Isolating important conversations" into rvc-dev am: 822b72843d am: ac09b9168e

Change-Id: I5137c82673513f902fcf68b9da4f4eb84b1625d1
This commit is contained in:
Selim Cinek
2020-04-04 00:46:23 +00:00
committed by Automerger Merge Worker
16 changed files with 290 additions and 108 deletions

View File

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

View File

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

View File

@@ -252,7 +252,7 @@ public class NotificationEntryManager implements
}
@Override
public void onReorderingAllowed() {
public void onChangeAllowed() {
updateNotifications("reordering is now allowed");
}

View File

@@ -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();
}
/**
@@ -144,6 +160,13 @@ public class VisualStabilityManager implements OnHeadsUpChangedListener, Dumpabl
return mReorderingAllowed;
}
/**
* @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
@@ -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();
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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,13 +422,28 @@ 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
@@ -556,6 +574,20 @@ 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.
*
@@ -563,11 +595,11 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener, State
*/
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();
}

View File

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

View File

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

View File

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

View File

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

View File

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