Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit cc70765f authored by Steve Elliott's avatar Steve Elliott
Browse files

Update EmptyShadeView during GONE->AOD transition

Internal changes to keyguard have caused our call to
NSSLC#updateShowEmptyShadeView to happen *before* keyguard states have
been updated for the GONE->AOD transition. This is due to an implicit
assumption that by the time our unrelated call to
updateShowEmptyShadeView occurs, the transition state is already set.

This is fixed by explcitly listening for the GONE->AOD transition and
calling updateShowEmptyShadeView when it starts and ends.

Fixes: 286209517
Test: atest NotificationStackScrollLayoutControllerTest

Change-Id: Ie81ea7f95fa42294fb32cffd305f840ca9c1c9e3
parent e1c1711e
Loading
Loading
Loading
Loading
+3 −1
Original line number Diff line number Diff line
@@ -16,7 +16,9 @@
package com.android.systemui.keyguard.shared.model

/** This information will flow from the [KeyguardTransitionRepository] to control the UI layer */
data class TransitionStep(
data class TransitionStep
@JvmOverloads
constructor(
    val from: KeyguardState = KeyguardState.OFF,
    val to: KeyguardState = KeyguardState.OFF,
    val value: Float = 0f, // constrained [0.0, 1.0]
+24 −2
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@ import static com.android.systemui.statusbar.notification.stack.NotificationStac
import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.ROWS_HIGH_PRIORITY;
import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.SelectedRows;
import static com.android.systemui.statusbar.phone.NotificationIconAreaController.HIGH_PRIORITY;
import static com.android.systemui.util.kotlin.JavaAdapterKt.collectFlow;

import android.content.res.Configuration;
import android.content.res.Resources;
@@ -63,7 +64,10 @@ import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.Flags;
import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository;
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor;
import com.android.systemui.keyguard.shared.model.KeyguardState;
import com.android.systemui.keyguard.shared.model.TransitionStep;
import com.android.systemui.media.controls.ui.KeyguardMediaController;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.FalsingManager;
@@ -189,6 +193,7 @@ public class NotificationStackScrollLayoutController {
    private final GroupExpansionManager mGroupExpansionManager;
    private final NotifPipelineFlags mNotifPipelineFlags;
    private final SeenNotificationsProvider mSeenNotificationsProvider;
    private final KeyguardTransitionRepository mKeyguardTransitionRepo;

    private NotificationStackScrollLayout mView;
    private NotificationSwipeHelper mSwipeHelper;
@@ -197,6 +202,8 @@ public class NotificationStackScrollLayoutController {
    private int mBarState;
    private boolean mIsBouncerShowingFromCentralSurfaces;
    private HeadsUpAppearanceController mHeadsUpAppearanceController;
    private boolean mIsInTransitionToAod = false;

    private final FeatureFlags mFeatureFlags;
    private final NotificationTargetsHelper mNotificationTargetsHelper;
    private final SecureSettings mSecureSettings;
@@ -633,6 +640,7 @@ public class NotificationStackScrollLayoutController {
            KeyguardBypassController keyguardBypassController,
            KeyguardInteractor keyguardInteractor,
            PrimaryBouncerInteractor primaryBouncerInteractor,
            KeyguardTransitionRepository keyguardTransitionRepo,
            ZenModeController zenModeController,
            NotificationLockscreenUserManager lockscreenUserManager,
            Optional<NotificationListViewModel> nsslViewModel,
@@ -665,6 +673,7 @@ public class NotificationStackScrollLayoutController {
            NotificationDismissibilityProvider dismissibilityProvider,
            ActivityStarter activityStarter) {
        mView = view;
        mKeyguardTransitionRepo = keyguardTransitionRepo;
        mStackStateLogger = stackLogger;
        mLogger = logger;
        mAllowLongPress = allowLongPress;
@@ -819,6 +828,9 @@ public class NotificationStackScrollLayoutController {
        mViewModel.ifPresent(
                vm -> NotificationListViewBinder
                        .bind(mView, vm, mFalsingManager, mFeatureFlags, mNotifIconAreaController));

        collectFlow(mView, mKeyguardTransitionRepo.getTransitions(),
                this::onKeyguardTransitionChanged);
    }

    private boolean isInVisibleLocation(NotificationEntry entry) {
@@ -1241,10 +1253,10 @@ public class NotificationStackScrollLayoutController {

        final boolean shouldShow = getVisibleNotificationCount() == 0
                && !mView.isQsFullScreen()
                // Hide empty shade view when in transition to Keyguard.
                // Hide empty shade view when in transition to AOD.
                // That avoids "No Notifications" to blink when transitioning to AOD.
                // For more details, see: b/228790482
                && !isInTransitionToKeyguard()
                && !mIsInTransitionToAod
                // Don't show any notification content if the bouncer is showing. See b/267060171.
                && !isBouncerShowing();

@@ -1643,6 +1655,16 @@ public class NotificationStackScrollLayoutController {
        return shelf == null ? 0 : shelf.getIntrinsicHeight();
    }

    @VisibleForTesting
    void onKeyguardTransitionChanged(TransitionStep transitionStep) {
        boolean isTransitionToAod = transitionStep.getFrom().equals(KeyguardState.GONE)
                && transitionStep.getTo().equals(KeyguardState.AOD);
        if (mIsInTransitionToAod != isTransitionToAod) {
            mIsInTransitionToAod = isTransitionToAod;
            updateShowEmptyShadeView();
        }
    }

    /**
     * Enum for UiEvent logged from this class
     */
+35 −3
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@ import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.mock;
@@ -32,10 +33,14 @@ import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import static kotlinx.coroutines.flow.FlowKt.emptyFlow;

import android.content.res.Resources;
import android.metrics.LogMaker;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.view.View;
import android.view.ViewTreeObserver;

import androidx.test.filters.SmallTest;

@@ -49,8 +54,12 @@ import com.android.systemui.classifier.FalsingCollectorFake;
import com.android.systemui.classifier.FalsingManagerFake;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.flags.FakeFeatureFlags;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.Flags;
import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository;
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor;
import com.android.systemui.keyguard.shared.model.KeyguardState;
import com.android.systemui.keyguard.shared.model.TransitionStep;
import com.android.systemui.media.controls.ui.KeyguardMediaController;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
@@ -105,6 +114,7 @@ import java.util.Optional;
 * Tests for {@link NotificationStackScrollLayoutController}.
 */
@SmallTest
@TestableLooper.RunWithLooper(setAsMainLooper = true)
@RunWith(AndroidTestingRunner.class)
public class NotificationStackScrollLayoutControllerTest extends SysuiTestCase {

@@ -151,6 +161,7 @@ public class NotificationStackScrollLayoutControllerTest extends SysuiTestCase {
    @Mock private SecureSettings mSecureSettings;
    @Mock private NotificationIconAreaController mIconAreaController;
    @Mock private ActivityStarter mActivityStarter;
    @Mock private KeyguardTransitionRepository mKeyguardTransitionRepo;

    @Captor
    private ArgumentCaptor<StatusBarStateController.StateListener> mStateListenerArgumentCaptor;
@@ -162,11 +173,13 @@ public class NotificationStackScrollLayoutControllerTest extends SysuiTestCase {

    @Before
    public void setUp() {
        allowTestableLooperAsMainThread();
        MockitoAnnotations.initMocks(this);

        mFeatureFlags.set(Flags.USE_REPOS_FOR_BOUNCER_SHOWING, false);

        when(mNotificationSwipeHelperBuilder.build()).thenReturn(mNotificationSwipeHelper);
        when(mKeyguardTransitionRepo.getTransitions()).thenReturn(emptyFlow());
    }

    @Test
@@ -572,17 +585,33 @@ public class NotificationStackScrollLayoutControllerTest extends SysuiTestCase {
                .setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
    }

    @Test
    public void updateEmptyShadeView_onKeyguardTransitionToAod_hidesView() {
        initController(/* viewIsAttached= */ true);
        mController.onKeyguardTransitionChanged(
                new TransitionStep(
                        /* from= */ KeyguardState.GONE,
                        /* to= */ KeyguardState.AOD));
        verify(mNotificationStackScrollLayout).updateEmptyShadeView(eq(false), anyBoolean());
    }

    private LogMaker logMatcher(int category, int type) {
        return argThat(new LogMatcher(category, type));
    }

    private void setupShowEmptyShadeViewState(boolean toShow) {
        if (toShow) {
            when(mSysuiStatusBarStateController.getCurrentOrUpcomingState()).thenReturn(SHADE);
            mController.onKeyguardTransitionChanged(
                    new TransitionStep(
                            /* from= */ KeyguardState.LOCKSCREEN,
                            /* to= */ KeyguardState.GONE));
            mController.setQsFullScreen(false);
            mController.getView().removeAllViews();
        } else {
            when(mSysuiStatusBarStateController.getCurrentOrUpcomingState()).thenReturn(KEYGUARD);
            mController.onKeyguardTransitionChanged(
                    new TransitionStep(
                            /* from= */ KeyguardState.GONE,
                            /* to= */ KeyguardState.AOD));
            mController.setQsFullScreen(true);
            mController.getView().addContainerView(mock(ExpandableNotificationRow.class));
        }
@@ -590,7 +619,9 @@ public class NotificationStackScrollLayoutControllerTest extends SysuiTestCase {

    private void initController(boolean viewIsAttached) {
        when(mNotificationStackScrollLayout.isAttachedToWindow()).thenReturn(viewIsAttached);

        ViewTreeObserver viewTreeObserver = mock(ViewTreeObserver.class);
        when(mNotificationStackScrollLayout.getViewTreeObserver())
                .thenReturn(viewTreeObserver);
        mController = new NotificationStackScrollLayoutController(
                mNotificationStackScrollLayout,
                true,
@@ -608,6 +639,7 @@ public class NotificationStackScrollLayoutControllerTest extends SysuiTestCase {
                mKeyguardBypassController,
                mKeyguardInteractor,
                mPrimaryBouncerInteractor,
                mKeyguardTransitionRepo,
                mZenModeController,
                mNotificationLockscreenUserManager,
                Optional.<NotificationListViewModel>empty(),