Properly end lifetimeExtention for ongoing notifications
Fixes: 209816888 Test: HeadsupCoordinatiorTest Change-Id: I620ec940ec3a836c36d71af327bd74a2640bf76f
This commit is contained in:
@@ -257,6 +257,30 @@ public abstract class AlertingNotificationManager implements NotificationLifetim
|
||||
return !canRemoveImmediately(entry.getKey());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param key
|
||||
* @return true if the entry is pinned
|
||||
*/
|
||||
public boolean isSticky(String key) {
|
||||
AlertEntry alerting = mAlertEntries.get(key);
|
||||
if (alerting != null) {
|
||||
return alerting.isSticky();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param key
|
||||
* @return When a HUN entry should be removed in milliseconds from now
|
||||
*/
|
||||
public long getEarliestRemovalTime(String key) {
|
||||
AlertEntry alerting = mAlertEntries.get(key);
|
||||
if (alerting != null) {
|
||||
return Math.max(0, alerting.mEarliestRemovaltime - mClock.currentTimeMillis());
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setShouldManageLifetime(NotificationEntry entry, boolean shouldExtend) {
|
||||
if (shouldExtend) {
|
||||
|
||||
@@ -19,9 +19,12 @@ package com.android.systemui.statusbar.notification.collection.coordinator;
|
||||
import static com.android.systemui.statusbar.NotificationRemoteInputManager.FORCE_REMOTE_INPUT_HISTORY;
|
||||
import static com.android.systemui.statusbar.notification.interruption.HeadsUpController.alertAgain;
|
||||
|
||||
import android.util.ArraySet;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.android.systemui.dagger.qualifiers.Main;
|
||||
import com.android.systemui.statusbar.NotificationRemoteInputManager;
|
||||
import com.android.systemui.statusbar.notification.collection.ListEntry;
|
||||
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
|
||||
@@ -38,8 +41,7 @@ import com.android.systemui.statusbar.notification.interruption.NotificationInte
|
||||
import com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt;
|
||||
import com.android.systemui.statusbar.policy.HeadsUpManager;
|
||||
import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
|
||||
|
||||
import java.util.Objects;
|
||||
import com.android.systemui.util.concurrency.DelayableExecutor;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
@@ -66,12 +68,11 @@ public class HeadsUpCoordinator implements Coordinator {
|
||||
private final NotificationInterruptStateProvider mNotificationInterruptStateProvider;
|
||||
private final NotificationRemoteInputManager mRemoteInputManager;
|
||||
private final NodeController mIncomingHeaderController;
|
||||
|
||||
// tracks the current HeadUpNotification reported by HeadsUpManager
|
||||
private @Nullable NotificationEntry mCurrentHun;
|
||||
private final DelayableExecutor mExecutor;
|
||||
|
||||
private NotifLifetimeExtender.OnEndLifetimeExtensionCallback mEndLifetimeExtension;
|
||||
private NotificationEntry mNotifExtendingLifetime; // notif we've extended the lifetime for
|
||||
// notifs we've extended the lifetime for
|
||||
private final ArraySet<NotificationEntry> mNotifsExtendingLifetime = new ArraySet<>();
|
||||
|
||||
@Inject
|
||||
public HeadsUpCoordinator(
|
||||
@@ -79,12 +80,14 @@ public class HeadsUpCoordinator implements Coordinator {
|
||||
HeadsUpViewBinder headsUpViewBinder,
|
||||
NotificationInterruptStateProvider notificationInterruptStateProvider,
|
||||
NotificationRemoteInputManager remoteInputManager,
|
||||
@IncomingHeader NodeController incomingHeaderController) {
|
||||
@IncomingHeader NodeController incomingHeaderController,
|
||||
@Main DelayableExecutor executor) {
|
||||
mHeadsUpManager = headsUpManager;
|
||||
mHeadsUpViewBinder = headsUpViewBinder;
|
||||
mNotificationInterruptStateProvider = notificationInterruptStateProvider;
|
||||
mRemoteInputManager = remoteInputManager;
|
||||
mIncomingHeaderController = incomingHeaderController;
|
||||
mExecutor = executor;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -178,16 +181,26 @@ public class HeadsUpCoordinator implements Coordinator {
|
||||
public boolean shouldExtendLifetime(@NonNull NotificationEntry entry, int reason) {
|
||||
boolean isShowingHun = isCurrentlyShowingHun(entry);
|
||||
if (isShowingHun) {
|
||||
mNotifExtendingLifetime = entry;
|
||||
if (isSticky(entry)) {
|
||||
long removeAfterMillis = mHeadsUpManager.getEarliestRemovalTime(entry.getKey());
|
||||
if (removeAfterMillis <= 0) return false;
|
||||
mExecutor.executeDelayed(() -> {
|
||||
// make sure that the entry was not updated
|
||||
long removeAfterMillis2 =
|
||||
mHeadsUpManager.getEarliestRemovalTime(entry.getKey());
|
||||
if (mNotifsExtendingLifetime.contains(entry) && removeAfterMillis2 <= 0) {
|
||||
mHeadsUpManager.removeNotification(entry.getKey(), true);
|
||||
}
|
||||
}, removeAfterMillis);
|
||||
}
|
||||
mNotifsExtendingLifetime.add(entry);
|
||||
}
|
||||
return isShowingHun;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancelLifetimeExtension(@NonNull NotificationEntry entry) {
|
||||
if (Objects.equals(mNotifExtendingLifetime, entry)) {
|
||||
mNotifExtendingLifetime = null;
|
||||
}
|
||||
mNotifsExtendingLifetime.remove(entry);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -220,27 +233,24 @@ public class HeadsUpCoordinator implements Coordinator {
|
||||
new OnHeadsUpChangedListener() {
|
||||
@Override
|
||||
public void onHeadsUpStateChanged(NotificationEntry entry, boolean isHeadsUp) {
|
||||
NotificationEntry newHUN = mHeadsUpManager.getTopEntry();
|
||||
if (!Objects.equals(mCurrentHun, newHUN)) {
|
||||
mCurrentHun = newHUN;
|
||||
endNotifLifetimeExtension();
|
||||
}
|
||||
if (!isHeadsUp) {
|
||||
mHeadsUpViewBinder.unbindHeadsUpView(entry);
|
||||
endNotifLifetimeExtensionIfExtended(entry);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private boolean isCurrentlyShowingHun(ListEntry entry) {
|
||||
return mCurrentHun == entry.getRepresentativeEntry();
|
||||
private boolean isSticky(NotificationEntry entry) {
|
||||
return mHeadsUpManager.isSticky(entry.getKey());
|
||||
}
|
||||
|
||||
private void endNotifLifetimeExtension() {
|
||||
if (mNotifExtendingLifetime != null) {
|
||||
mEndLifetimeExtension.onEndLifetimeExtension(
|
||||
mLifetimeExtender,
|
||||
mNotifExtendingLifetime);
|
||||
mNotifExtendingLifetime = null;
|
||||
private boolean isCurrentlyShowingHun(ListEntry entry) {
|
||||
return mHeadsUpManager.isAlerting(entry.getKey());
|
||||
}
|
||||
|
||||
private void endNotifLifetimeExtensionIfExtended(NotificationEntry entry) {
|
||||
if (mNotifsExtendingLifetime.remove(entry)) {
|
||||
mEndLifetimeExtension.onEndLifetimeExtension(mLifetimeExtender, entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,8 +19,11 @@ package com.android.systemui.statusbar.notification.collection.coordinator;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@@ -44,6 +47,8 @@ import com.android.systemui.statusbar.notification.interruption.NotificationInte
|
||||
import com.android.systemui.statusbar.notification.row.NotifBindPipeline.BindCallback;
|
||||
import com.android.systemui.statusbar.policy.HeadsUpManager;
|
||||
import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
|
||||
import com.android.systemui.util.concurrency.FakeExecutor;
|
||||
import com.android.systemui.util.time.FakeSystemClock;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
@@ -52,6 +57,8 @@ import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
@SmallTest
|
||||
@RunWith(AndroidTestingRunner.class)
|
||||
@TestableLooper.RunWithLooper
|
||||
@@ -75,6 +82,9 @@ public class HeadsUpCoordinatorTest extends SysuiTestCase {
|
||||
@Mock private NodeController mHeaderController;
|
||||
|
||||
private NotificationEntry mEntry;
|
||||
private final FakeSystemClock mClock = new FakeSystemClock();
|
||||
private final FakeExecutor mExecutor = new FakeExecutor(mClock);
|
||||
private final ArrayList<NotificationEntry> mHuns = new ArrayList();
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
@@ -85,7 +95,8 @@ public class HeadsUpCoordinatorTest extends SysuiTestCase {
|
||||
mHeadsUpViewBinder,
|
||||
mNotificationInterruptStateProvider,
|
||||
mRemoteInputManager,
|
||||
mHeaderController);
|
||||
mHeaderController,
|
||||
mExecutor);
|
||||
|
||||
mCoordinator.attach(mNotifPipeline);
|
||||
|
||||
@@ -105,6 +116,16 @@ public class HeadsUpCoordinatorTest extends SysuiTestCase {
|
||||
notifLifetimeExtenderCaptor.capture());
|
||||
verify(mHeadsUpManager).addListener(headsUpChangedListenerCaptor.capture());
|
||||
|
||||
given(mHeadsUpManager.getAllEntries()).willAnswer(i -> mHuns.stream());
|
||||
given(mHeadsUpManager.isAlerting(anyString())).willAnswer(i -> {
|
||||
String key = i.getArgument(0);
|
||||
for (NotificationEntry entry : mHuns) {
|
||||
if (entry.getKey().equals(key)) return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
when(mHeadsUpManager.getEarliestRemovalTime(anyString())).thenReturn(1000L);
|
||||
|
||||
mCollectionListener = notifCollectionCaptor.getValue();
|
||||
mNotifPromoter = notifPromoterCaptor.getValue();
|
||||
mNotifLifetimeExtender = notifLifetimeExtenderCaptor.getValue();
|
||||
@@ -115,64 +136,65 @@ public class HeadsUpCoordinatorTest extends SysuiTestCase {
|
||||
mEntry = new NotificationEntryBuilder().build();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCancelStickyNotification() {
|
||||
when(mHeadsUpManager.isSticky(anyString())).thenReturn(true);
|
||||
addHUN(mEntry);
|
||||
when(mHeadsUpManager.getEarliestRemovalTime(anyString())).thenReturn(1000L, 0L);
|
||||
assertTrue(mNotifLifetimeExtender.shouldExtendLifetime(mEntry, 0));
|
||||
mClock.advanceTime(1000L);
|
||||
mExecutor.runAllReady();
|
||||
verify(mHeadsUpManager, times(1))
|
||||
.removeNotification(anyString(), eq(true));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCancelUpdatedStickyNotification() {
|
||||
when(mHeadsUpManager.isSticky(anyString())).thenReturn(true);
|
||||
addHUN(mEntry);
|
||||
when(mHeadsUpManager.getEarliestRemovalTime(anyString())).thenReturn(1000L, 500L);
|
||||
assertTrue(mNotifLifetimeExtender.shouldExtendLifetime(mEntry, 0));
|
||||
mClock.advanceTime(1000L);
|
||||
mExecutor.runAllReady();
|
||||
verify(mHeadsUpManager, times(0))
|
||||
.removeNotification(anyString(), eq(true));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPromotesCurrentHUN() {
|
||||
// GIVEN the current HUN is set to mEntry
|
||||
setCurrentHUN(mEntry);
|
||||
addHUN(mEntry);
|
||||
|
||||
// THEN only promote the current HUN, mEntry
|
||||
assertTrue(mNotifPromoter.shouldPromoteToTopLevel(mEntry));
|
||||
assertFalse(mNotifPromoter.shouldPromoteToTopLevel(new NotificationEntryBuilder().build()));
|
||||
assertFalse(mNotifPromoter.shouldPromoteToTopLevel(new NotificationEntryBuilder()
|
||||
.setPkg("test-package2")
|
||||
.build()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIncludeInSectionCurrentHUN() {
|
||||
// GIVEN the current HUN is set to mEntry
|
||||
setCurrentHUN(mEntry);
|
||||
addHUN(mEntry);
|
||||
|
||||
// THEN only section the current HUN, mEntry
|
||||
assertTrue(mNotifSectioner.isInSection(mEntry));
|
||||
assertFalse(mNotifSectioner.isInSection(new NotificationEntryBuilder().build()));
|
||||
assertFalse(mNotifSectioner.isInSection(new NotificationEntryBuilder()
|
||||
.setPkg("test-package")
|
||||
.build()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLifetimeExtendsCurrentHUN() {
|
||||
// GIVEN there is a HUN, mEntry
|
||||
setCurrentHUN(mEntry);
|
||||
addHUN(mEntry);
|
||||
|
||||
// THEN only the current HUN, mEntry, should be lifetimeExtended
|
||||
assertTrue(mNotifLifetimeExtender.shouldExtendLifetime(mEntry, /* cancellationReason */ 0));
|
||||
assertFalse(mNotifLifetimeExtender.shouldExtendLifetime(
|
||||
new NotificationEntryBuilder().build(), /* cancellationReason */ 0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLifetimeExtensionEndsOnNewHUN() {
|
||||
// GIVEN there was a HUN that was lifetime extended
|
||||
setCurrentHUN(mEntry);
|
||||
assertTrue(mNotifLifetimeExtender.shouldExtendLifetime(
|
||||
mEntry, /* cancellation reason */ 0));
|
||||
|
||||
// WHEN there's a new HUN
|
||||
NotificationEntry newHUN = new NotificationEntryBuilder().build();
|
||||
setCurrentHUN(newHUN);
|
||||
|
||||
// THEN the old entry's lifetime extension should be cancelled
|
||||
verify(mEndLifetimeExtension).onEndLifetimeExtension(mNotifLifetimeExtender, mEntry);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLifetimeExtensionEndsOnNoHUNs() {
|
||||
// GIVEN there was a HUN that was lifetime extended
|
||||
setCurrentHUN(mEntry);
|
||||
assertTrue(mNotifLifetimeExtender.shouldExtendLifetime(
|
||||
mEntry, /* cancellation reason */ 0));
|
||||
|
||||
// WHEN there's no longer a HUN
|
||||
setCurrentHUN(null);
|
||||
|
||||
// THEN the old entry's lifetime extension should be cancelled
|
||||
verify(mEndLifetimeExtension).onEndLifetimeExtension(mNotifLifetimeExtender, mEntry);
|
||||
new NotificationEntryBuilder()
|
||||
.setPkg("test-package")
|
||||
.build(), /* cancellationReason */ 0));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -208,7 +230,7 @@ public class HeadsUpCoordinatorTest extends SysuiTestCase {
|
||||
@Test
|
||||
public void testOnEntryRemovedRemovesHeadsUpNotification() {
|
||||
// GIVEN the current HUN is mEntry
|
||||
setCurrentHUN(mEntry);
|
||||
addHUN(mEntry);
|
||||
|
||||
// WHEN mEntry is removed from the notification collection
|
||||
mCollectionListener.onEntryRemoved(mEntry, /* cancellation reason */ 0);
|
||||
@@ -218,12 +240,9 @@ public class HeadsUpCoordinatorTest extends SysuiTestCase {
|
||||
verify(mHeadsUpManager).removeNotification(mEntry.getKey(), false);
|
||||
}
|
||||
|
||||
private void setCurrentHUN(NotificationEntry entry) {
|
||||
private void addHUN(NotificationEntry entry) {
|
||||
mHuns.add(entry);
|
||||
when(mHeadsUpManager.getTopEntry()).thenReturn(entry);
|
||||
when(mHeadsUpManager.isAlerting(any())).thenReturn(false);
|
||||
if (entry != null) {
|
||||
when(mHeadsUpManager.isAlerting(entry.getKey())).thenReturn(true);
|
||||
}
|
||||
mOnHeadsUpChangedListener.onHeadsUpStateChanged(entry, entry != null);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user