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

Commit 69f5eb75 authored by cocod's avatar cocod
Browse files

Prevent landscape bouncer from showing when opened from hub

As we enable rotation for hub, opening bouncer in landscape will show
it in a landscape layout before screen rotates to portrait.

This happens when KeyguardBouncerViewBinder#isShowing becomes true,
it starts the appear animation for bouncer elements right away. It
can happen earlier than hub -> bouncer transition start and screen
is still in landspe. The fix is to delay the animation and start it
after orientation changes to portrait. This can prevent a small
landscpe layout of bouncer from showing at the beginning.

Bug: b/392708288
Test: atest GlanceableHubToPrimaryBouncerTransitionViewModelTest
Test: atest KeyguardSecurityContainerControllerTest
Test: atest KeyguardSecurityContainerTest
Test: manually on foldable
Flag: com.android.systemui.glanceable_hub_v2
Change-Id: I7984dd312484e756abae3e34a96271b24c6ec0d5
parent a3d6fdb9
Loading
Loading
Loading
Loading
+33 −0
Original line number Diff line number Diff line
@@ -25,6 +25,8 @@ import android.view.Gravity
import android.view.LayoutInflater
import android.view.MotionEvent
import android.view.View
import android.view.ViewTreeObserver
import android.view.ViewTreeObserver.OnPreDrawListener
import android.view.WindowInsetsController
import android.widget.FrameLayout
import androidx.test.ext.junit.runners.AndroidJUnit4
@@ -717,6 +719,37 @@ class KeyguardSecurityContainerControllerTest : SysuiTestCase() {
        verify(inputViewController).onStartingToHide()
    }

    @Test
    fun startAppearAnimation_ifDelayed() {
        val argumentCaptor = ArgumentCaptor.forClass(OnPreDrawListener::class.java)
        whenever(view.isAppearAnimationDelayed).thenReturn(true)
        val viewTreeObserver: ViewTreeObserver = mock()
        whenever(view.viewTreeObserver).thenReturn(viewTreeObserver)

        underTest.startAppearAnimationIfDelayed()

        verify(view).alpha = 1f
        verify(viewTreeObserver).addOnPreDrawListener(argumentCaptor.capture())
        argumentCaptor.value.onPreDraw()

        verify(view).startAppearAnimation(any(SecurityMode::class.java))
        verify(view).setIsAppearAnimationDelayed(false)
    }

    @Test
    fun appearAnimation_willNotStart_ifNotDelayed() {
        whenever(view.isAppearAnimationDelayed).thenReturn(false)
        val viewTreeObserver: ViewTreeObserver = mock()
        whenever(view.viewTreeObserver).thenReturn(viewTreeObserver)

        underTest.startAppearAnimationIfDelayed()

        verify(view, never()).alpha
        verify(viewTreeObserver, never()).addOnPreDrawListener(any())

        verify(view, never()).startAppearAnimation(any(SecurityMode::class.java))
    }

    @Test
    fun gravityReappliedOnConfigurationChange() {
        // Set initial gravity
+8 −0
Original line number Diff line number Diff line
@@ -452,6 +452,14 @@ public class KeyguardSecurityContainerTest extends SysuiTestCase {
        verify(keyguardPasswordView).setDisappearAnimationListener(any());
    }

    @Test
    public void setupForDelayedAppear() {
        mKeyguardSecurityContainer.setupForDelayedAppear();
        assertThat(mKeyguardSecurityContainer.getTranslationY()).isEqualTo(0f);
        assertThat(mKeyguardSecurityContainer.getAlpha()).isEqualTo(0f);
        assertThat(mKeyguardSecurityContainer.isAppearAnimationDelayed()).isTrue();
    }

    private BackEvent createBackEvent(float touchX, float progress) {
        return new BackEvent(0, 0, progress, BackEvent.EDGE_LEFT);
    }
+96 −1
Original line number Diff line number Diff line
@@ -16,28 +16,46 @@

package com.android.systemui.keyguard.ui.viewmodel

import android.content.res.mainResources
import android.platform.test.annotations.DisableFlags
import android.platform.test.annotations.EnableFlags
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.Flags.FLAG_GLANCEABLE_HUB_BLURRED_BACKGROUND
import com.android.systemui.Flags.FLAG_GLANCEABLE_HUB_V2
import com.android.systemui.SysuiTestCase
import com.android.systemui.communal.domain.interactor.communalInteractor
import com.android.systemui.communal.domain.interactor.communalSceneInteractor
import com.android.systemui.communal.domain.interactor.setCommunalV2ConfigEnabled
import com.android.systemui.communal.shared.model.CommunalScenes
import com.android.systemui.flags.DisableSceneContainer
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.TransitionStep
import com.android.systemui.keyguard.ui.transitions.blurConfig
import com.android.systemui.kosmos.collectLastValue
import com.android.systemui.kosmos.collectValues
import com.android.systemui.kosmos.runCurrent
import com.android.systemui.kosmos.runTest
import com.android.systemui.statusbar.policy.keyguardStateController
import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.kotlin.whenever

@SmallTest
@RunWith(AndroidJUnit4::class)
class GlanceableHubToPrimaryBouncerTransitionViewModelTest : SysuiTestCase() {
    private val kosmos = testKosmos()
    private val kosmos =
        testKosmos().apply { mainResources = mContext.orCreateTestableResources.resources }
    private val underTest by lazy { kosmos.glanceableHubToPrimaryBouncerTransitionViewModel }

    @Before
    fun setUp() {
        with(kosmos) { setCommunalV2ConfigEnabled(true) }
    }

    @Test
    @DisableSceneContainer
    @DisableFlags(FLAG_GLANCEABLE_HUB_BLURRED_BACKGROUND)
@@ -84,4 +102,81 @@ class GlanceableHubToPrimaryBouncerTransitionViewModelTest : SysuiTestCase() {
                },
            )
        }

    @Test
    @DisableSceneContainer
    @DisableFlags(FLAG_GLANCEABLE_HUB_V2)
    fun willDelayBouncerAppearAnimation_flagDisabled_isFalse() =
        kosmos.runTest {
            // keyguard rotation is not allowed on device.
            whenever(keyguardStateController.isKeyguardScreenRotationAllowed()).thenReturn(false)

            val isIdleOnCommunal by collectLastValue(communalInteractor.isIdleOnCommunal)
            communalSceneInteractor.changeScene(CommunalScenes.Communal, "test")
            runCurrent()
            // Device is idle on communal.
            assertThat(isIdleOnCommunal).isTrue()

            // in landscape
            assertThat(underTest.willDelayAppearAnimation(isLandscape = true)).isFalse()
            // in portrait
            assertThat(underTest.willDelayAppearAnimation(isLandscape = false)).isFalse()
        }

    @Test
    @DisableSceneContainer
    @EnableFlags(FLAG_GLANCEABLE_HUB_V2)
    fun willDelayBouncerAppearAnimation_keyguardRotationAllowed_isFalse() =
        kosmos.runTest {
            // Keyguard rotation is allowed on device.
            whenever(keyguardStateController.isKeyguardScreenRotationAllowed()).thenReturn(true)

            val isIdleOnCommunal by collectLastValue(communalInteractor.isIdleOnCommunal)
            communalSceneInteractor.changeScene(CommunalScenes.Communal, "test")
            runCurrent()
            // Device is idle on communal.
            assertThat(isIdleOnCommunal).isTrue()

            // in landscape
            assertThat(underTest.willDelayAppearAnimation(isLandscape = true)).isFalse()
            // in portrait
            assertThat(underTest.willDelayAppearAnimation(isLandscape = false)).isFalse()
        }

    @Test
    @DisableSceneContainer
    @EnableFlags(FLAG_GLANCEABLE_HUB_V2)
    fun willDelayBouncerAppearAnimation_isNotIdleOnCommunal_isFalse() =
        kosmos.runTest {
            whenever(keyguardStateController.isKeyguardScreenRotationAllowed()).thenReturn(false)

            val isIdleOnCommunal by collectLastValue(communalInteractor.isIdleOnCommunal)
            communalSceneInteractor.changeScene(CommunalScenes.Blank, "test")
            runCurrent()
            // Device is not on communal.
            assertThat(isIdleOnCommunal).isFalse()

            // in landscape
            assertThat(underTest.willDelayAppearAnimation(isLandscape = true)).isFalse()
            // in portrait
            assertThat(underTest.willDelayAppearAnimation(isLandscape = false)).isFalse()
        }

    @Test
    @DisableSceneContainer
    @EnableFlags(FLAG_GLANCEABLE_HUB_V2)
    fun willDelayBouncerAppearAnimation_isIdleOnCommunalAndKeyguardRotationIsNotAllowed() =
        kosmos.runTest {
            whenever(keyguardStateController.isKeyguardScreenRotationAllowed()).thenReturn(false)
            val isIdleOnCommunal by collectLastValue(communalInteractor.isIdleOnCommunal)
            communalSceneInteractor.changeScene(CommunalScenes.Communal, "test")
            runCurrent()
            // Device is idle on communal.
            assertThat(isIdleOnCommunal).isTrue()

            // Will delay in landscape
            assertThat(underTest.willDelayAppearAnimation(isLandscape = true)).isTrue()
            // Won't delay in portrait
            assertThat(underTest.willDelayAppearAnimation(isLandscape = false)).isFalse()
        }
}
+19 −0
Original line number Diff line number Diff line
@@ -172,6 +172,7 @@ public class KeyguardSecurityContainer extends ConstraintLayout {
    private boolean mIsDragging;
    private float mStartTouchY = -1;
    private boolean mDisappearAnimRunning;
    private boolean mIsAppearAnimationDelayed;
    private SwipeListener mSwipeListener;
    private ViewMode mViewMode = new DefaultViewMode();
    private boolean mIsInteractable;
@@ -583,6 +584,10 @@ public class KeyguardSecurityContainer extends ConstraintLayout {
        return false;
    }

    boolean isAppearAnimationDelayed() {
        return mIsAppearAnimationDelayed;
    }

    void addMotionEventListener(Gefingerpoken listener) {
        mMotionEventListeners.add(listener);
    }
@@ -624,6 +629,19 @@ public class KeyguardSecurityContainer extends ConstraintLayout {
        mViewMode.startAppearAnimation(securityMode);
    }

    /**
     * Set view translationY and alpha as we delay bouncer animation.
     */
    public void setupForDelayedAppear() {
        setTranslationY(0f);
        setAlpha(0f);
        setIsAppearAnimationDelayed(true);
    }

    public void setIsAppearAnimationDelayed(boolean isDelayed) {
        mIsAppearAnimationDelayed = isDelayed;
    }

    private void beginJankInstrument(int cuj) {
        KeyguardInputView securityView = mSecurityViewFlipper.getSecurityView();
        if (securityView == null) return;
@@ -812,6 +830,7 @@ public class KeyguardSecurityContainer extends ConstraintLayout {
    public void reset() {
        mViewMode.reset();
        mDisappearAnimRunning = false;
        mIsAppearAnimationDelayed = false;
    }

    /**
+24 −0
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package com.android.keyguard;

import static android.app.StatusBarManager.SESSION_KEYGUARD;
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
import static android.content.res.Configuration.ORIENTATION_PORTRAIT;

import static com.android.keyguard.KeyguardSecurityContainer.BOUNCER_DISMISSIBLE_KEYGUARD;
import static com.android.keyguard.KeyguardSecurityContainer.BOUNCER_DISMISS_BIOMETRIC;
@@ -385,6 +386,10 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
                        boolean useSplitBouncer = orientation == ORIENTATION_LANDSCAPE;
                        mSecurityViewFlipperController.updateConstraints(useSplitBouncer);
                    }
                    if (orientation == ORIENTATION_PORTRAIT) {
                        // If there is any delayed bouncer appear animation it can start now
                        startAppearAnimationIfDelayed();
                    }
                }

                @Override
@@ -845,6 +850,16 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
        }
    }

    /** Start appear animation which was previously delayed from opening bouncer in landscape. */
    public void startAppearAnimationIfDelayed() {
        if (!mView.isAppearAnimationDelayed()) {
            return;
        }
        setAlpha(1f);
        appear();
        mView.setIsAppearAnimationDelayed(false);
    }

    /** Called when the bouncer changes visibility. */
    public void onBouncerVisibilityChanged(boolean isVisible) {
        if (!isVisible) {
@@ -1301,4 +1316,13 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
        setAlpha(MathUtils.constrain(1 - scaledFraction, 0f, 1f));
        mView.setTranslationY(scaledFraction * mTranslationY);
    }

    /** Set up view for delayed appear animation. */
    public void setupForDelayedAppear() {
        mView.setupForDelayedAppear();
    }

    public boolean isLandscapeOrientation() {
        return mLastOrientation == Configuration.ORIENTATION_LANDSCAPE;
    }
}
Loading