Loading packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinatorTest.java +22 −21 Original line number Diff line number Diff line Loading @@ -22,9 +22,10 @@ import static com.google.common.truth.Truth.assertThat; import static junit.framework.Assert.assertFalse; import static kotlinx.coroutines.flow.StateFlowKt.MutableStateFlow; import static org.junit.Assume.assumeFalse; import static org.junit.Assert.assertTrue; import static org.junit.Assume.assumeFalse; import static org.junit.Assume.assumeTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; Loading @@ -36,8 +37,6 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static kotlinx.coroutines.flow.StateFlowKt.MutableStateFlow; import android.platform.test.annotations.EnableFlags; import android.platform.test.flag.junit.FlagsParameterization; import android.testing.TestableLooper; Loading Loading @@ -74,13 +73,16 @@ import com.android.systemui.statusbar.notification.collection.NotificationEntryB import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifStabilityManager; import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.Pluggable; import com.android.systemui.statusbar.notification.collection.provider.VisualStabilityProvider; import com.android.systemui.statusbar.notification.data.repository.HeadsUpRepository; import com.android.systemui.statusbar.notification.domain.interactor.SeenNotificationsInteractor; import com.android.systemui.statusbar.notification.headsup.HeadsUpManager; import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.util.concurrency.FakeExecutor; import com.android.systemui.util.kotlin.JavaAdapter; import com.android.systemui.util.time.FakeSystemClock; import kotlinx.coroutines.flow.MutableStateFlow; import kotlinx.coroutines.test.TestScope; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; Loading @@ -90,15 +92,12 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.mockito.verification.VerificationMode; import java.util.List; import java.util.Set; import kotlinx.coroutines.flow.MutableStateFlow; import kotlinx.coroutines.test.TestScope; import platform.test.runner.parameterized.ParameterizedAndroidJunit4; import platform.test.runner.parameterized.Parameters; import java.util.List; import java.util.Set; @SmallTest @RunWith(ParameterizedAndroidJunit4.class) @TestableLooper.RunWithLooper Loading @@ -118,7 +117,7 @@ public class VisualStabilityCoordinatorTest extends SysuiTestCase { @Mock private StatusBarStateController mStatusBarStateController; @Mock private Pluggable.PluggableListener<NotifStabilityManager> mInvalidateListener; @Mock private SeenNotificationsInteractor mSeenNotificationsInteractor; @Mock private HeadsUpManager mHeadsUpManager; @Mock private HeadsUpRepository mHeadsUpRepository; @Mock private VisibilityLocationProvider mVisibilityLocationProvider; @Mock private VisualStabilityProvider mVisualStabilityProvider; @Mock private VisualStabilityCoordinatorLogger mLogger; Loading Loading @@ -159,7 +158,7 @@ public class VisualStabilityCoordinatorTest extends SysuiTestCase { mFakeBackgroundExecutor, mFakeMainExecutor, mDumpManager, mHeadsUpManager, mHeadsUpRepository, mShadeAnimationInteractor, mJavaAdapter, mSeenNotificationsInteractor, Loading @@ -172,6 +171,8 @@ public class VisualStabilityCoordinatorTest extends SysuiTestCase { mKosmos.getKeyguardTransitionInteractor(), mKeyguardStateController, mLogger); when(mHeadsUpRepository.isTrackingHeadsUp()).thenReturn(MutableStateFlow(false)); mCoordinator.attach(mNotifPipeline); mTestScope.getTestScheduler().runCurrent(); Loading @@ -194,7 +195,7 @@ public class VisualStabilityCoordinatorTest extends SysuiTestCase { .setSummary(mEntry) .build(); when(mHeadsUpManager.isHeadsUpEntry(mEntry.getKey())).thenReturn(false); when(mHeadsUpRepository.isHeadsUpEntry(mEntry.getKey())).thenReturn(false); // Whenever we invalidate, the pipeline runs again, so we invalidate the state doAnswer(i -> { Loading Loading @@ -461,7 +462,7 @@ public class VisualStabilityCoordinatorTest extends SysuiTestCase { setSleepy(false); // WHEN a notification is alerting and visible when(mHeadsUpManager.isHeadsUpEntry(mEntry.getKey())).thenReturn(true); when(mHeadsUpRepository.isHeadsUpEntry(mEntry.getKey())).thenReturn(true); when(mVisibilityLocationProvider.isInVisibleLocation(any(NotificationEntry.class))) .thenReturn(true); Loading @@ -477,7 +478,7 @@ public class VisualStabilityCoordinatorTest extends SysuiTestCase { setSleepy(false); // WHEN a notification is alerting but not visible when(mHeadsUpManager.isHeadsUpEntry(mEntry.getKey())).thenReturn(true); when(mHeadsUpRepository.isHeadsUpEntry(mEntry.getKey())).thenReturn(true); when(mVisibilityLocationProvider.isInVisibleLocation(any(NotificationEntry.class))) .thenReturn(false); Loading Loading @@ -701,7 +702,7 @@ public class VisualStabilityCoordinatorTest extends SysuiTestCase { assertFalse(mNotifStabilityManager.isSectionChangeAllowed(mEntry)); // GIVEN mEntry is a HUN when(mHeadsUpManager.isHeadsUpEntry(mEntry.getKey())).thenReturn(true); when(mHeadsUpRepository.isHeadsUpEntry(mEntry.getKey())).thenReturn(true); // THEN group + section changes are allowed assertTrue(mNotifStabilityManager.isGroupChangeAllowed(mEntry)); Loading Loading @@ -768,7 +769,7 @@ public class VisualStabilityCoordinatorTest extends SysuiTestCase { // GIVEN - there is a group heads-up. String headsUpGroupKey = "heads_up_group_key"; mCoordinator.setHeadsUpGroupKeys(Set.of(headsUpGroupKey)); when(mHeadsUpManager.isHeadsUpEntry(headsUpGroupKey)).thenReturn(true); when(mHeadsUpRepository.isHeadsUpEntry(headsUpGroupKey)).thenReturn(true); // GIVEN - HUN Group Summary final NotificationEntry nonHeadsUpGroupSummary = mock(NotificationEntry.class); Loading @@ -793,7 +794,7 @@ public class VisualStabilityCoordinatorTest extends SysuiTestCase { // GIVEN - there is a group heads-up. final String headsUpGroupKey = "heads_up_group_key"; mCoordinator.setHeadsUpGroupKeys(Set.of(headsUpGroupKey)); when(mHeadsUpManager.isHeadsUpEntry(headsUpGroupKey)).thenReturn(true); when(mHeadsUpRepository.isHeadsUpEntry(headsUpGroupKey)).thenReturn(true); // GIVEN - HUN Group final NotificationEntry headsUpGroupSummary = mock(NotificationEntry.class); Loading Loading @@ -825,7 +826,7 @@ public class VisualStabilityCoordinatorTest extends SysuiTestCase { // GIVEN - there is a group heads-up. final String headsUpGroupKey = "heads_up_group_key"; mCoordinator.setHeadsUpGroupKeys(Set.of(headsUpGroupKey)); when(mHeadsUpManager.isHeadsUpEntry(headsUpGroupKey)).thenReturn(true); when(mHeadsUpRepository.isHeadsUpEntry(headsUpGroupKey)).thenReturn(true); // GIVEN - HUN Group final NotificationEntry headsUpGroupSummary = mock(NotificationEntry.class); Loading Loading @@ -858,7 +859,7 @@ public class VisualStabilityCoordinatorTest extends SysuiTestCase { // GIVEN - there is a group heads-up. String headsUpGroupKey = "heads_up_group_key"; mCoordinator.setHeadsUpGroupKeys(Set.of(headsUpGroupKey)); when(mHeadsUpManager.isHeadsUpEntry(headsUpGroupKey)).thenReturn(true); when(mHeadsUpRepository.isHeadsUpEntry(headsUpGroupKey)).thenReturn(true); // GIVEN - non HUN parent Group Summary final NotificationEntry groupSummary = mock(NotificationEntry.class); Loading Loading @@ -891,7 +892,7 @@ public class VisualStabilityCoordinatorTest extends SysuiTestCase { // GIVEN - there is a group heads-up. final String headsUpGroupKey = "heads_up_group_key"; mCoordinator.setHeadsUpGroupKeys(Set.of(headsUpGroupKey)); when(mHeadsUpManager.isHeadsUpEntry(headsUpGroupKey)).thenReturn(true); when(mHeadsUpRepository.isHeadsUpEntry(headsUpGroupKey)).thenReturn(true); // GIVEN - HUN Group Summary final NotificationEntry headsUpGroupSummary = mock(NotificationEntry.class); Loading packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java +18 −1 Original line number Diff line number Diff line Loading @@ -101,6 +101,7 @@ import com.android.systemui.wmshell.BubblesTestActivity; import kotlin.coroutines.CoroutineContext; import kotlinx.coroutines.flow.StateFlowKt; import kotlinx.coroutines.test.TestScope; import org.mockito.ArgumentCaptor; Loading Loading @@ -166,11 +167,21 @@ public class NotificationTestHelper { this(context, dependency, testLooper, new FakeFeatureFlagsClassic()); } public NotificationTestHelper( Context context, TestableDependency dependency, @Nullable TestableLooper testLooper, @NonNull FakeFeatureFlagsClassic featureFlags) { this(context, dependency, testLooper, featureFlags, mockHeadsUpManager()); } public NotificationTestHelper( Context context, TestableDependency dependency, @Nullable TestableLooper testLooper, @NonNull FakeFeatureFlagsClassic featureFlags, @NonNull HeadsUpManager headsUpManager) { mContext = context; mFeatureFlags = Objects.requireNonNull(featureFlags); dependency.injectTestDependency(FeatureFlagsClassic.class, mFeatureFlags); Loading @@ -182,7 +193,7 @@ public class NotificationTestHelper { mKeyguardBypassController = mock(KeyguardBypassController.class); mGroupMembershipManager = mock(GroupMembershipManager.class); mGroupExpansionManager = mock(GroupExpansionManager.class); mHeadsUpManager = mock(HeadsUpManager.class); mHeadsUpManager = headsUpManager; mIconManager = new IconManager( mock(CommonNotifCollection.class), mock(LauncherApps.class), Loading Loading @@ -689,6 +700,12 @@ public class NotificationTestHelper { .build(); } private static HeadsUpManager mockHeadsUpManager() { HeadsUpManager mock = mock(HeadsUpManager.class); when(mock.isTrackingHeadsUp()).thenReturn(StateFlowKt.MutableStateFlow(false)); return mock; } private static class MockSmartReplyInflater implements SmartReplyStateInflater { @Override public InflatedSmartReplyState inflateSmartReplyState(NotificationEntry entry) { Loading packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java +3 −2 Original line number Diff line number Diff line Loading @@ -1788,7 +1788,8 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump // height - which means user is swiping down. Otherwise shade QS will either not show at all // with HUN movement or it will blink when touching HUN initially boolean qsShouldExpandWithHeadsUp = !mSplitShadeEnabled || (!mHeadsUpManager.isTrackingHeadsUp() || expandedHeight > mHeadsUpStartHeight); || (!mHeadsUpManager.isTrackingHeadsUp().getValue() || expandedHeight > mHeadsUpStartHeight); if (goingBetweenClosedShadeAndExpandedQs && qsShouldExpandWithHeadsUp) { float qsExpansionFraction; if (mSplitShadeEnabled) { Loading Loading @@ -2048,7 +2049,7 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump // motion has the expected speed. We also only want this on non-lockscreen for now. if (mSplitShadeEnabled && mBarState == SHADE) { boolean transitionFromHeadsUp = (mHeadsUpManager != null && mHeadsUpManager.isTrackingHeadsUp()) || mExpandingFromHeadsUp; && mHeadsUpManager.isTrackingHeadsUp().getValue()) || mExpandingFromHeadsUp; // heads-up starting height is too close to mSplitShadeFullTransitionDistance and // when dragging HUN transition is already 90% complete. It makes shade become // immediately visible when starting to drag. We want to set distance so that Loading packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinator.java +25 −9 Original line number Diff line number Diff line Loading @@ -45,8 +45,8 @@ import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeRenderListListener; import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifStabilityManager; import com.android.systemui.statusbar.notification.collection.provider.VisualStabilityProvider; import com.android.systemui.statusbar.notification.data.repository.HeadsUpRepository; import com.android.systemui.statusbar.notification.domain.interactor.SeenNotificationsInteractor; import com.android.systemui.statusbar.notification.headsup.HeadsUpManager; import com.android.systemui.statusbar.notification.shared.NotificationMinimalism; import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.util.concurrency.DelayableExecutor; Loading @@ -72,7 +72,7 @@ import javax.inject.Inject; public class VisualStabilityCoordinator implements Coordinator, Dumpable { private final DelayableExecutor mDelayableExecutor; private final DelayableExecutor mMainExecutor; private final HeadsUpManager mHeadsUpManager; private final HeadsUpRepository mHeadsUpRepository; private final SeenNotificationsInteractor mSeenNotificationsInteractor; private final ShadeAnimationInteractor mShadeAnimationInteractor; private final StatusBarStateController mStatusBarStateController; Loading @@ -94,6 +94,7 @@ public class VisualStabilityCoordinator implements Coordinator, Dumpable { private boolean mNotifPanelLaunchingActivity; private boolean mCommunalShowing = false; private boolean mLockscreenShowing = false; private boolean mTrackingHeadsUp = false; private boolean mLockscreenInGoneTransition = false; private Set<String> mHeadsUpGroupKeys = new HashSet<>(); Loading @@ -117,7 +118,7 @@ public class VisualStabilityCoordinator implements Coordinator, Dumpable { @Background DelayableExecutor delayableExecutor, @Main DelayableExecutor mainExecutor, DumpManager dumpManager, HeadsUpManager headsUpManager, HeadsUpRepository headsUpRepository, ShadeAnimationInteractor shadeAnimationInteractor, JavaAdapter javaAdapter, SeenNotificationsInteractor seenNotificationsInteractor, Loading @@ -130,7 +131,7 @@ public class VisualStabilityCoordinator implements Coordinator, Dumpable { KeyguardTransitionInteractor keyguardTransitionInteractor, KeyguardStateController keyguardStateController, VisualStabilityCoordinatorLogger logger) { mHeadsUpManager = headsUpManager; mHeadsUpRepository = headsUpRepository; mShadeAnimationInteractor = shadeAnimationInteractor; mJavaAdapter = javaAdapter; mSeenNotificationsInteractor = seenNotificationsInteractor; Loading Loading @@ -177,6 +178,8 @@ public class VisualStabilityCoordinator implements Coordinator, Dumpable { mJavaAdapter.alwaysCollectFlow(mKeyguardTransitionInteractor.transitionValue( KeyguardState.LOCKSCREEN), this::onLockscreenKeyguardStateTransitionValueChanged); mJavaAdapter.alwaysCollectFlow(mHeadsUpRepository.isTrackingHeadsUp(), this::onTrackingHeadsUpModeChanged); } if (Flags.checkLockscreenGoneTransition()) { Loading Loading @@ -239,7 +242,7 @@ public class VisualStabilityCoordinator implements Coordinator, Dumpable { boolean isTopUnseen = NotificationMinimalism.isEnabled() && (mSeenNotificationsInteractor.isTopUnseenNotification(entry) || mSeenNotificationsInteractor.isTopOngoingNotification(entry)); if (isTopUnseen || mHeadsUpManager.isHeadsUpEntry(entry.getKey())) { if (isTopUnseen || mHeadsUpRepository.isHeadsUpEntry(entry.getKey())) { return !mVisibilityLocationProvider.isInVisibleLocation(entry); } return false; Loading Loading @@ -275,7 +278,7 @@ public class VisualStabilityCoordinator implements Coordinator, Dumpable { return false; } return mHeadsUpManager.isHeadsUpEntry(summary.getKey()); return mHeadsUpRepository.isHeadsUpEntry(summary.getKey()); } /** * When reordering is enabled, non-heads-up groups can be pruned. Loading Loading @@ -415,7 +418,7 @@ public class VisualStabilityCoordinator implements Coordinator, Dumpable { if (summary == null) continue; final String summaryKey = summary.getKey(); if (mHeadsUpManager.isHeadsUpEntry(summaryKey)) { if (mHeadsUpRepository.isHeadsUpEntry(summaryKey)) { currentHeadsUpKeys.add(summaryKey); } } Loading Loading @@ -475,11 +478,19 @@ public class VisualStabilityCoordinator implements Coordinator, Dumpable { private boolean isReorderingAllowed() { final boolean sleepyAndDozed = mFullyDozed && mSleepy; final boolean stackShowing = mPanelExpanded || (SceneContainerFlag.isEnabled() && mLockscreenShowing); final boolean stackShowing = isStackShowing(); return (sleepyAndDozed || !stackShowing || mCommunalShowing) && !mPulsing; } /** @return true when the notification stack is visible to the user */ private boolean isStackShowing() { if (SceneContainerFlag.isEnabled()) { return mPanelExpanded || mLockscreenShowing || mTrackingHeadsUp; } else { return mPanelExpanded; } } /** * Allows this notification entry to be re-ordered in the notification list temporarily until * the timeout has passed. Loading Loading @@ -610,6 +621,11 @@ public class VisualStabilityCoordinator implements Coordinator, Dumpable { updateAllowedStates("lockscreenShowing", isShowing); } private void onTrackingHeadsUpModeChanged(boolean isTrackingHeadsUp) { mTrackingHeadsUp = isTrackingHeadsUp; updateAllowedStates("trackingHeadsUp", isTrackingHeadsUp); } private void onLockscreenInGoneTransitionChanged(boolean inGoneTransition) { if (!Flags.checkLockscreenGoneTransition()) { return; Loading packages/SystemUI/src/com/android/systemui/statusbar/notification/data/repository/HeadsUpRepository.kt +10 −0 Original line number Diff line number Diff line Loading @@ -40,6 +40,16 @@ interface HeadsUpRepository { /** Set of currently active top-level heads up rows to be displayed. */ val activeHeadsUpRows: Flow<Set<HeadsUpRowRepository>> /** Whether the user is swiping on a heads up row */ val isTrackingHeadsUp: Flow<Boolean> /** @return true if the actively managed heads up notifications contain an entry for this key */ fun isHeadsUpEntry(key: String): Boolean /** * set whether a HUN is currently animation out, to keep its view container visible during the * animation */ fun setHeadsUpAnimatingAway(animatingAway: Boolean) /** Snooze the currently pinned HUN. */ Loading Loading
packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinatorTest.java +22 −21 Original line number Diff line number Diff line Loading @@ -22,9 +22,10 @@ import static com.google.common.truth.Truth.assertThat; import static junit.framework.Assert.assertFalse; import static kotlinx.coroutines.flow.StateFlowKt.MutableStateFlow; import static org.junit.Assume.assumeFalse; import static org.junit.Assert.assertTrue; import static org.junit.Assume.assumeFalse; import static org.junit.Assume.assumeTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; Loading @@ -36,8 +37,6 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static kotlinx.coroutines.flow.StateFlowKt.MutableStateFlow; import android.platform.test.annotations.EnableFlags; import android.platform.test.flag.junit.FlagsParameterization; import android.testing.TestableLooper; Loading Loading @@ -74,13 +73,16 @@ import com.android.systemui.statusbar.notification.collection.NotificationEntryB import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifStabilityManager; import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.Pluggable; import com.android.systemui.statusbar.notification.collection.provider.VisualStabilityProvider; import com.android.systemui.statusbar.notification.data.repository.HeadsUpRepository; import com.android.systemui.statusbar.notification.domain.interactor.SeenNotificationsInteractor; import com.android.systemui.statusbar.notification.headsup.HeadsUpManager; import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.util.concurrency.FakeExecutor; import com.android.systemui.util.kotlin.JavaAdapter; import com.android.systemui.util.time.FakeSystemClock; import kotlinx.coroutines.flow.MutableStateFlow; import kotlinx.coroutines.test.TestScope; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; Loading @@ -90,15 +92,12 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.mockito.verification.VerificationMode; import java.util.List; import java.util.Set; import kotlinx.coroutines.flow.MutableStateFlow; import kotlinx.coroutines.test.TestScope; import platform.test.runner.parameterized.ParameterizedAndroidJunit4; import platform.test.runner.parameterized.Parameters; import java.util.List; import java.util.Set; @SmallTest @RunWith(ParameterizedAndroidJunit4.class) @TestableLooper.RunWithLooper Loading @@ -118,7 +117,7 @@ public class VisualStabilityCoordinatorTest extends SysuiTestCase { @Mock private StatusBarStateController mStatusBarStateController; @Mock private Pluggable.PluggableListener<NotifStabilityManager> mInvalidateListener; @Mock private SeenNotificationsInteractor mSeenNotificationsInteractor; @Mock private HeadsUpManager mHeadsUpManager; @Mock private HeadsUpRepository mHeadsUpRepository; @Mock private VisibilityLocationProvider mVisibilityLocationProvider; @Mock private VisualStabilityProvider mVisualStabilityProvider; @Mock private VisualStabilityCoordinatorLogger mLogger; Loading Loading @@ -159,7 +158,7 @@ public class VisualStabilityCoordinatorTest extends SysuiTestCase { mFakeBackgroundExecutor, mFakeMainExecutor, mDumpManager, mHeadsUpManager, mHeadsUpRepository, mShadeAnimationInteractor, mJavaAdapter, mSeenNotificationsInteractor, Loading @@ -172,6 +171,8 @@ public class VisualStabilityCoordinatorTest extends SysuiTestCase { mKosmos.getKeyguardTransitionInteractor(), mKeyguardStateController, mLogger); when(mHeadsUpRepository.isTrackingHeadsUp()).thenReturn(MutableStateFlow(false)); mCoordinator.attach(mNotifPipeline); mTestScope.getTestScheduler().runCurrent(); Loading @@ -194,7 +195,7 @@ public class VisualStabilityCoordinatorTest extends SysuiTestCase { .setSummary(mEntry) .build(); when(mHeadsUpManager.isHeadsUpEntry(mEntry.getKey())).thenReturn(false); when(mHeadsUpRepository.isHeadsUpEntry(mEntry.getKey())).thenReturn(false); // Whenever we invalidate, the pipeline runs again, so we invalidate the state doAnswer(i -> { Loading Loading @@ -461,7 +462,7 @@ public class VisualStabilityCoordinatorTest extends SysuiTestCase { setSleepy(false); // WHEN a notification is alerting and visible when(mHeadsUpManager.isHeadsUpEntry(mEntry.getKey())).thenReturn(true); when(mHeadsUpRepository.isHeadsUpEntry(mEntry.getKey())).thenReturn(true); when(mVisibilityLocationProvider.isInVisibleLocation(any(NotificationEntry.class))) .thenReturn(true); Loading @@ -477,7 +478,7 @@ public class VisualStabilityCoordinatorTest extends SysuiTestCase { setSleepy(false); // WHEN a notification is alerting but not visible when(mHeadsUpManager.isHeadsUpEntry(mEntry.getKey())).thenReturn(true); when(mHeadsUpRepository.isHeadsUpEntry(mEntry.getKey())).thenReturn(true); when(mVisibilityLocationProvider.isInVisibleLocation(any(NotificationEntry.class))) .thenReturn(false); Loading Loading @@ -701,7 +702,7 @@ public class VisualStabilityCoordinatorTest extends SysuiTestCase { assertFalse(mNotifStabilityManager.isSectionChangeAllowed(mEntry)); // GIVEN mEntry is a HUN when(mHeadsUpManager.isHeadsUpEntry(mEntry.getKey())).thenReturn(true); when(mHeadsUpRepository.isHeadsUpEntry(mEntry.getKey())).thenReturn(true); // THEN group + section changes are allowed assertTrue(mNotifStabilityManager.isGroupChangeAllowed(mEntry)); Loading Loading @@ -768,7 +769,7 @@ public class VisualStabilityCoordinatorTest extends SysuiTestCase { // GIVEN - there is a group heads-up. String headsUpGroupKey = "heads_up_group_key"; mCoordinator.setHeadsUpGroupKeys(Set.of(headsUpGroupKey)); when(mHeadsUpManager.isHeadsUpEntry(headsUpGroupKey)).thenReturn(true); when(mHeadsUpRepository.isHeadsUpEntry(headsUpGroupKey)).thenReturn(true); // GIVEN - HUN Group Summary final NotificationEntry nonHeadsUpGroupSummary = mock(NotificationEntry.class); Loading @@ -793,7 +794,7 @@ public class VisualStabilityCoordinatorTest extends SysuiTestCase { // GIVEN - there is a group heads-up. final String headsUpGroupKey = "heads_up_group_key"; mCoordinator.setHeadsUpGroupKeys(Set.of(headsUpGroupKey)); when(mHeadsUpManager.isHeadsUpEntry(headsUpGroupKey)).thenReturn(true); when(mHeadsUpRepository.isHeadsUpEntry(headsUpGroupKey)).thenReturn(true); // GIVEN - HUN Group final NotificationEntry headsUpGroupSummary = mock(NotificationEntry.class); Loading Loading @@ -825,7 +826,7 @@ public class VisualStabilityCoordinatorTest extends SysuiTestCase { // GIVEN - there is a group heads-up. final String headsUpGroupKey = "heads_up_group_key"; mCoordinator.setHeadsUpGroupKeys(Set.of(headsUpGroupKey)); when(mHeadsUpManager.isHeadsUpEntry(headsUpGroupKey)).thenReturn(true); when(mHeadsUpRepository.isHeadsUpEntry(headsUpGroupKey)).thenReturn(true); // GIVEN - HUN Group final NotificationEntry headsUpGroupSummary = mock(NotificationEntry.class); Loading Loading @@ -858,7 +859,7 @@ public class VisualStabilityCoordinatorTest extends SysuiTestCase { // GIVEN - there is a group heads-up. String headsUpGroupKey = "heads_up_group_key"; mCoordinator.setHeadsUpGroupKeys(Set.of(headsUpGroupKey)); when(mHeadsUpManager.isHeadsUpEntry(headsUpGroupKey)).thenReturn(true); when(mHeadsUpRepository.isHeadsUpEntry(headsUpGroupKey)).thenReturn(true); // GIVEN - non HUN parent Group Summary final NotificationEntry groupSummary = mock(NotificationEntry.class); Loading Loading @@ -891,7 +892,7 @@ public class VisualStabilityCoordinatorTest extends SysuiTestCase { // GIVEN - there is a group heads-up. final String headsUpGroupKey = "heads_up_group_key"; mCoordinator.setHeadsUpGroupKeys(Set.of(headsUpGroupKey)); when(mHeadsUpManager.isHeadsUpEntry(headsUpGroupKey)).thenReturn(true); when(mHeadsUpRepository.isHeadsUpEntry(headsUpGroupKey)).thenReturn(true); // GIVEN - HUN Group Summary final NotificationEntry headsUpGroupSummary = mock(NotificationEntry.class); Loading
packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java +18 −1 Original line number Diff line number Diff line Loading @@ -101,6 +101,7 @@ import com.android.systemui.wmshell.BubblesTestActivity; import kotlin.coroutines.CoroutineContext; import kotlinx.coroutines.flow.StateFlowKt; import kotlinx.coroutines.test.TestScope; import org.mockito.ArgumentCaptor; Loading Loading @@ -166,11 +167,21 @@ public class NotificationTestHelper { this(context, dependency, testLooper, new FakeFeatureFlagsClassic()); } public NotificationTestHelper( Context context, TestableDependency dependency, @Nullable TestableLooper testLooper, @NonNull FakeFeatureFlagsClassic featureFlags) { this(context, dependency, testLooper, featureFlags, mockHeadsUpManager()); } public NotificationTestHelper( Context context, TestableDependency dependency, @Nullable TestableLooper testLooper, @NonNull FakeFeatureFlagsClassic featureFlags, @NonNull HeadsUpManager headsUpManager) { mContext = context; mFeatureFlags = Objects.requireNonNull(featureFlags); dependency.injectTestDependency(FeatureFlagsClassic.class, mFeatureFlags); Loading @@ -182,7 +193,7 @@ public class NotificationTestHelper { mKeyguardBypassController = mock(KeyguardBypassController.class); mGroupMembershipManager = mock(GroupMembershipManager.class); mGroupExpansionManager = mock(GroupExpansionManager.class); mHeadsUpManager = mock(HeadsUpManager.class); mHeadsUpManager = headsUpManager; mIconManager = new IconManager( mock(CommonNotifCollection.class), mock(LauncherApps.class), Loading Loading @@ -689,6 +700,12 @@ public class NotificationTestHelper { .build(); } private static HeadsUpManager mockHeadsUpManager() { HeadsUpManager mock = mock(HeadsUpManager.class); when(mock.isTrackingHeadsUp()).thenReturn(StateFlowKt.MutableStateFlow(false)); return mock; } private static class MockSmartReplyInflater implements SmartReplyStateInflater { @Override public InflatedSmartReplyState inflateSmartReplyState(NotificationEntry entry) { Loading
packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java +3 −2 Original line number Diff line number Diff line Loading @@ -1788,7 +1788,8 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump // height - which means user is swiping down. Otherwise shade QS will either not show at all // with HUN movement or it will blink when touching HUN initially boolean qsShouldExpandWithHeadsUp = !mSplitShadeEnabled || (!mHeadsUpManager.isTrackingHeadsUp() || expandedHeight > mHeadsUpStartHeight); || (!mHeadsUpManager.isTrackingHeadsUp().getValue() || expandedHeight > mHeadsUpStartHeight); if (goingBetweenClosedShadeAndExpandedQs && qsShouldExpandWithHeadsUp) { float qsExpansionFraction; if (mSplitShadeEnabled) { Loading Loading @@ -2048,7 +2049,7 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump // motion has the expected speed. We also only want this on non-lockscreen for now. if (mSplitShadeEnabled && mBarState == SHADE) { boolean transitionFromHeadsUp = (mHeadsUpManager != null && mHeadsUpManager.isTrackingHeadsUp()) || mExpandingFromHeadsUp; && mHeadsUpManager.isTrackingHeadsUp().getValue()) || mExpandingFromHeadsUp; // heads-up starting height is too close to mSplitShadeFullTransitionDistance and // when dragging HUN transition is already 90% complete. It makes shade become // immediately visible when starting to drag. We want to set distance so that Loading
packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinator.java +25 −9 Original line number Diff line number Diff line Loading @@ -45,8 +45,8 @@ import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeRenderListListener; import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifStabilityManager; import com.android.systemui.statusbar.notification.collection.provider.VisualStabilityProvider; import com.android.systemui.statusbar.notification.data.repository.HeadsUpRepository; import com.android.systemui.statusbar.notification.domain.interactor.SeenNotificationsInteractor; import com.android.systemui.statusbar.notification.headsup.HeadsUpManager; import com.android.systemui.statusbar.notification.shared.NotificationMinimalism; import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.util.concurrency.DelayableExecutor; Loading @@ -72,7 +72,7 @@ import javax.inject.Inject; public class VisualStabilityCoordinator implements Coordinator, Dumpable { private final DelayableExecutor mDelayableExecutor; private final DelayableExecutor mMainExecutor; private final HeadsUpManager mHeadsUpManager; private final HeadsUpRepository mHeadsUpRepository; private final SeenNotificationsInteractor mSeenNotificationsInteractor; private final ShadeAnimationInteractor mShadeAnimationInteractor; private final StatusBarStateController mStatusBarStateController; Loading @@ -94,6 +94,7 @@ public class VisualStabilityCoordinator implements Coordinator, Dumpable { private boolean mNotifPanelLaunchingActivity; private boolean mCommunalShowing = false; private boolean mLockscreenShowing = false; private boolean mTrackingHeadsUp = false; private boolean mLockscreenInGoneTransition = false; private Set<String> mHeadsUpGroupKeys = new HashSet<>(); Loading @@ -117,7 +118,7 @@ public class VisualStabilityCoordinator implements Coordinator, Dumpable { @Background DelayableExecutor delayableExecutor, @Main DelayableExecutor mainExecutor, DumpManager dumpManager, HeadsUpManager headsUpManager, HeadsUpRepository headsUpRepository, ShadeAnimationInteractor shadeAnimationInteractor, JavaAdapter javaAdapter, SeenNotificationsInteractor seenNotificationsInteractor, Loading @@ -130,7 +131,7 @@ public class VisualStabilityCoordinator implements Coordinator, Dumpable { KeyguardTransitionInteractor keyguardTransitionInteractor, KeyguardStateController keyguardStateController, VisualStabilityCoordinatorLogger logger) { mHeadsUpManager = headsUpManager; mHeadsUpRepository = headsUpRepository; mShadeAnimationInteractor = shadeAnimationInteractor; mJavaAdapter = javaAdapter; mSeenNotificationsInteractor = seenNotificationsInteractor; Loading Loading @@ -177,6 +178,8 @@ public class VisualStabilityCoordinator implements Coordinator, Dumpable { mJavaAdapter.alwaysCollectFlow(mKeyguardTransitionInteractor.transitionValue( KeyguardState.LOCKSCREEN), this::onLockscreenKeyguardStateTransitionValueChanged); mJavaAdapter.alwaysCollectFlow(mHeadsUpRepository.isTrackingHeadsUp(), this::onTrackingHeadsUpModeChanged); } if (Flags.checkLockscreenGoneTransition()) { Loading Loading @@ -239,7 +242,7 @@ public class VisualStabilityCoordinator implements Coordinator, Dumpable { boolean isTopUnseen = NotificationMinimalism.isEnabled() && (mSeenNotificationsInteractor.isTopUnseenNotification(entry) || mSeenNotificationsInteractor.isTopOngoingNotification(entry)); if (isTopUnseen || mHeadsUpManager.isHeadsUpEntry(entry.getKey())) { if (isTopUnseen || mHeadsUpRepository.isHeadsUpEntry(entry.getKey())) { return !mVisibilityLocationProvider.isInVisibleLocation(entry); } return false; Loading Loading @@ -275,7 +278,7 @@ public class VisualStabilityCoordinator implements Coordinator, Dumpable { return false; } return mHeadsUpManager.isHeadsUpEntry(summary.getKey()); return mHeadsUpRepository.isHeadsUpEntry(summary.getKey()); } /** * When reordering is enabled, non-heads-up groups can be pruned. Loading Loading @@ -415,7 +418,7 @@ public class VisualStabilityCoordinator implements Coordinator, Dumpable { if (summary == null) continue; final String summaryKey = summary.getKey(); if (mHeadsUpManager.isHeadsUpEntry(summaryKey)) { if (mHeadsUpRepository.isHeadsUpEntry(summaryKey)) { currentHeadsUpKeys.add(summaryKey); } } Loading Loading @@ -475,11 +478,19 @@ public class VisualStabilityCoordinator implements Coordinator, Dumpable { private boolean isReorderingAllowed() { final boolean sleepyAndDozed = mFullyDozed && mSleepy; final boolean stackShowing = mPanelExpanded || (SceneContainerFlag.isEnabled() && mLockscreenShowing); final boolean stackShowing = isStackShowing(); return (sleepyAndDozed || !stackShowing || mCommunalShowing) && !mPulsing; } /** @return true when the notification stack is visible to the user */ private boolean isStackShowing() { if (SceneContainerFlag.isEnabled()) { return mPanelExpanded || mLockscreenShowing || mTrackingHeadsUp; } else { return mPanelExpanded; } } /** * Allows this notification entry to be re-ordered in the notification list temporarily until * the timeout has passed. Loading Loading @@ -610,6 +621,11 @@ public class VisualStabilityCoordinator implements Coordinator, Dumpable { updateAllowedStates("lockscreenShowing", isShowing); } private void onTrackingHeadsUpModeChanged(boolean isTrackingHeadsUp) { mTrackingHeadsUp = isTrackingHeadsUp; updateAllowedStates("trackingHeadsUp", isTrackingHeadsUp); } private void onLockscreenInGoneTransitionChanged(boolean inGoneTransition) { if (!Flags.checkLockscreenGoneTransition()) { return; Loading
packages/SystemUI/src/com/android/systemui/statusbar/notification/data/repository/HeadsUpRepository.kt +10 −0 Original line number Diff line number Diff line Loading @@ -40,6 +40,16 @@ interface HeadsUpRepository { /** Set of currently active top-level heads up rows to be displayed. */ val activeHeadsUpRows: Flow<Set<HeadsUpRowRepository>> /** Whether the user is swiping on a heads up row */ val isTrackingHeadsUp: Flow<Boolean> /** @return true if the actively managed heads up notifications contain an entry for this key */ fun isHeadsUpEntry(key: String): Boolean /** * set whether a HUN is currently animation out, to keep its view container visible during the * animation */ fun setHeadsUpAnimatingAway(animatingAway: Boolean) /** Snooze the currently pinned HUN. */ Loading