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

Commit 546b4dbf authored by Alejandro Nijamkin's avatar Alejandro Nijamkin
Browse files

[multi-shade] Fixes issue where NSWV was still visible after unlock.

For reasons that are not yet understood, the NotificationShadeWindowView
remaines visible after unlocking the device.

The solution here simply removes the bouncer-showing logic from our
MultiShadeMotionEventInteractor but keeps the logic that checks the
direction of drag. If the user drags up the screen, our system does not
intercept the touch, allowing the legacy code to show the bouncer in its
own, correct way - which gets rid of the NSWV visibility bug. If the
user drags down the screen, we intercept touch and show the shade(s).

Bug: 274159734
Flag: DUAL_SHADE
Test: unit tests updated
Test: manually verified that, after unlocking the device, touch goes
through and I can click app icons on the launcher. Also made sure that
dragging up on the lock screen brings up the bouncer and I can unlock
the device from it.

Change-Id: I9f0d02f403007946b6911a5057fac9ffa316a9c7
parent 58cd6126
Loading
Loading
Loading
Loading
+29 −66
Original line number Diff line number Diff line
@@ -22,7 +22,6 @@ import android.view.ViewConfiguration
import com.android.systemui.classifier.Classifier
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerInteractor
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.multishade.shared.math.isZero
import com.android.systemui.multishade.shared.model.ProxiedInputModel
@@ -48,7 +47,6 @@ constructor(
    @Application private val applicationScope: CoroutineScope,
    private val multiShadeInteractor: MultiShadeInteractor,
    keyguardTransitionInteractor: KeyguardTransitionInteractor,
    private val bouncerInteractor: PrimaryBouncerInteractor,
    private val falsingManager: FalsingManager,
) {

@@ -98,7 +96,7 @@ constructor(
                        currentY = event.y,
                        pointerId = event.getPointerId(0),
                        isDraggingHorizontally = false,
                        draggedVertically = Dragged.NONE,
                        isDraggingShade = false,
                    )

                false
@@ -108,38 +106,28 @@ constructor(
                    val pointerIndex = event.findPointerIndex(it.pointerId)
                    val currentX = event.getX(pointerIndex)
                    val currentY = event.getY(pointerIndex)
                    if (!it.isDraggingHorizontally && it.draggedVertically == Dragged.NONE) {
                    if (!it.isDraggingHorizontally && !it.isDraggingShade) {
                        val xDistanceTravelled = currentX - it.initialX
                        val yDistanceTravelled = currentY - it.initialY
                        val touchSlop = ViewConfiguration.get(applicationContext).scaledTouchSlop
                        interactionState =
                            when {
                                abs(yDistanceTravelled) > touchSlop ->
                                    it.copy(
                                        draggedVertically =
                                            if (yDistanceTravelled > 0) {
                                                Dragged.SHADE
                                            } else {
                                                Dragged.BOUNCER
                                            }
                                    )
                                yDistanceTravelled > touchSlop -> it.copy(isDraggingShade = true)
                                abs(xDistanceTravelled) > touchSlop ->
                                    it.copy(
                                        isDraggingHorizontally = true,
                                    )
                                    it.copy(isDraggingHorizontally = true)
                                else -> interactionState
                            }
                    }
                }

                // We want to intercept the rest of the gesture if we're dragging.
                interactionState.isDraggingVertically()
                // We want to intercept the rest of the gesture if we're dragging the shade.
                isDraggingShade()
            }
            MotionEvent.ACTION_UP,
            MotionEvent.ACTION_CANCEL ->
                // Make sure that we intercept the up or cancel if we're dragging, to handle drag
                // end and cancel.
                interactionState.isDraggingVertically()
                // Make sure that we intercept the up or cancel if we're dragging the shade, to
                // handle drag end or cancel.
                isDraggingShade()
            else -> false
        }
    }
@@ -156,17 +144,12 @@ constructor(
        return when (event.actionMasked) {
            MotionEvent.ACTION_MOVE -> {
                interactionState?.let {
                    if (it.draggedVertically != Dragged.NONE) {
                    if (it.isDraggingShade) {
                        val pointerIndex = event.findPointerIndex(it.pointerId)
                        val previousY = it.currentY
                        val currentY = event.getY(pointerIndex)
                        interactionState =
                            it.copy(
                                currentY = currentY,
                            )
                        interactionState = it.copy(currentY = currentY)

                        when (it.draggedVertically) {
                            Dragged.SHADE -> {
                        val yDragAmountPx = currentY - previousY

                        if (yDragAmountPx != 0f) {
@@ -178,13 +161,6 @@ constructor(
                            )
                        }
                        true
                            }
                            Dragged.BOUNCER -> {
                                bouncerInteractor.show(isScrimmed = true)
                                false
                            }
                            else -> false
                        }
                    } else {
                        false
                    }
@@ -192,9 +168,10 @@ constructor(
                    ?: false
            }
            MotionEvent.ACTION_UP -> {
                if (interactionState?.draggedVertically == Dragged.SHADE) {
                    // We finished dragging. Record that so the multi-shade framework can issue a
                    // fling, if the velocity reached in the drag was high enough, for example.
                if (isDraggingShade()) {
                    // We finished dragging the shade. Record that so the multi-shade framework can
                    // issue a fling, if the velocity reached in the drag was high enough, for
                    // example.
                    multiShadeInteractor.sendProxiedInput(ProxiedInputModel.OnDragEnd)

                    if (falsingManager.isFalseTouch(Classifier.SHADE_DRAG)) {
@@ -206,7 +183,7 @@ constructor(
                true
            }
            MotionEvent.ACTION_CANCEL -> {
                if (interactionState?.draggedVertically == Dragged.SHADE) {
                if (isDraggingShade()) {
                    // Our drag gesture was canceled by the system. This happens primarily in one of
                    // two occasions: (a) the parent view has decided to intercept the gesture
                    // itself and/or route it to a different child view or (b) the pointer has
@@ -219,10 +196,6 @@ constructor(
                    if (falsingManager.isFalseTouch(Classifier.SHADE_DRAG)) {
                        multiShadeInteractor.collapseAll()
                    }
                } else if (interactionState?.draggedVertically == Dragged.BOUNCER) {
                    if (falsingManager.isFalseTouch(Classifier.BOUNCER_UNLOCK)) {
                        bouncerInteractor.hide()
                    }
                }

                interactionState = null
@@ -239,21 +212,11 @@ constructor(
        val pointerId: Int,
        /** Whether the current gesture is dragging horizontally. */
        val isDraggingHorizontally: Boolean,
        /** The UI component that is being dragged vertically, if any. */
        val draggedVertically: Dragged,
        /** Whether the current gesture is dragging the shade vertically. */
        val isDraggingShade: Boolean,
    )

    /** Enumerates the UI components that can be dragged by the user. */
    private enum class Dragged {
        /** The bouncer is being dragged by the user. */
        BOUNCER,
        /** A shade is being dragged by the user. */
        SHADE,
        /** No UI component is being dragged by the user. */
        NONE,
    }

    private fun InteractionState?.isDraggingVertically(): Boolean {
        return this?.draggedVertically != Dragged.NONE
    private fun isDraggingShade(): Boolean {
        return interactionState?.isDraggingShade ?: false
    }
}
+2 −6
Original line number Diff line number Diff line
@@ -388,7 +388,6 @@ public final class NotificationPanelViewController implements Dumpable {
    private KeyguardBottomAreaView mKeyguardBottomArea;
    private boolean mExpanding;
    private boolean mSplitShadeEnabled;
    private final boolean mMultiShadeEnabled;
    /** The bottom padding reserved for elements of the keyguard measuring notifications. */
    private float mKeyguardNotificationBottomPadding;
    /**
@@ -853,7 +852,6 @@ public final class NotificationPanelViewController implements Dumpable {
        mFeatureFlags = featureFlags;
        mAnimateBack = mFeatureFlags.isEnabled(Flags.WM_SHADE_ANIMATE_BACK_GESTURE);
        mTrackpadGestureBack = mFeatureFlags.isEnabled(Flags.TRACKPAD_GESTURE_FEATURES);
        mMultiShadeEnabled = mFeatureFlags.isEnabled(Flags.DUAL_SHADE);
        mFalsingCollector = falsingCollector;
        mPowerManager = powerManager;
        mWakeUpCoordinator = coordinator;
@@ -4021,10 +4019,8 @@ public final class NotificationPanelViewController implements Dumpable {
     *   {@link #updateVisibility()}? That would allow us to make this method private.
     */
    public void updatePanelExpansionAndVisibility() {
        if (!mMultiShadeEnabled) {
        mShadeExpansionStateManager.onPanelExpansionChanged(
                mExpandedFraction, isExpanded(), mTracking, mExpansionDragDownAmountPx);
        }

        updateVisibility();
    }
+6 −20
Original line number Diff line number Diff line
@@ -24,7 +24,6 @@ import com.android.systemui.classifier.FalsingManagerFake
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerInteractor
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.keyguard.shared.model.TransitionStep
@@ -43,18 +42,12 @@ import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
import org.mockito.Mock
import org.mockito.Mockito.never
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations

@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
@RunWith(JUnit4::class)
class MultiShadeMotionEventInteractorTest : SysuiTestCase() {

    @Mock private lateinit var bouncerInteractor: PrimaryBouncerInteractor

    private lateinit var underTest: MultiShadeMotionEventInteractor

    private lateinit var testScope: TestScope
@@ -67,8 +60,6 @@ class MultiShadeMotionEventInteractorTest : SysuiTestCase() {

    @Before
    fun setUp() {
        MockitoAnnotations.initMocks(this)

        testScope = TestScope()
        motionEvents = mutableSetOf()

@@ -95,7 +86,6 @@ class MultiShadeMotionEventInteractorTest : SysuiTestCase() {
                    KeyguardTransitionInteractor(
                        repository = keyguardTransitionRepository,
                    ),
                bouncerInteractor = bouncerInteractor,
                falsingManager = falsingManager,
            )
    }
@@ -400,7 +390,7 @@ class MultiShadeMotionEventInteractorTest : SysuiTestCase() {
        }

    @Test
    fun dragBouncerAboveTouchSlopAndUp_showsBouncer() =
    fun dragUp_withUp_doesNotShowShade() =
        testScope.runTest {
            val leftShadeProxiedInput by collectLastValue(interactor.proxiedInput(ShadeId.LEFT))
            val rightShadeProxiedInput by collectLastValue(interactor.proxiedInput(ShadeId.RIGHT))
@@ -423,24 +413,22 @@ class MultiShadeMotionEventInteractorTest : SysuiTestCase() {
                    x = 100f, // left shade
                    y = yDragAmountPx,
                )
            assertThat(underTest.shouldIntercept(moveEvent)).isTrue()
            assertThat(underTest.shouldIntercept(moveEvent)).isFalse()
            underTest.onTouchEvent(moveEvent, viewWidthPx = 1000)
            verify(bouncerInteractor).show(isScrimmed = true)
            assertThat(leftShadeProxiedInput).isNull()
            assertThat(rightShadeProxiedInput).isNull()
            assertThat(singleShadeProxiedInput).isNull()

            val upEvent = motionEvent(MotionEvent.ACTION_UP)
            assertThat(underTest.shouldIntercept(upEvent)).isTrue()
            assertThat(underTest.shouldIntercept(upEvent)).isFalse()
            underTest.onTouchEvent(upEvent, viewWidthPx = 1000)
            verify(bouncerInteractor, never()).hide()
            assertThat(leftShadeProxiedInput).isNull()
            assertThat(rightShadeProxiedInput).isNull()
            assertThat(singleShadeProxiedInput).isNull()
        }

    @Test
    fun dragBouncerAboveTouchSlopAndCancel_falseTouch_showsThenHidesBouncer() =
    fun dragUp_withCancel_falseTouch_showsThenHidesBouncer() =
        testScope.runTest {
            val leftShadeProxiedInput by collectLastValue(interactor.proxiedInput(ShadeId.LEFT))
            val rightShadeProxiedInput by collectLastValue(interactor.proxiedInput(ShadeId.RIGHT))
@@ -463,18 +451,16 @@ class MultiShadeMotionEventInteractorTest : SysuiTestCase() {
                    x = 900f, // right shade
                    y = yDragAmountPx,
                )
            assertThat(underTest.shouldIntercept(moveEvent)).isTrue()
            assertThat(underTest.shouldIntercept(moveEvent)).isFalse()
            underTest.onTouchEvent(moveEvent, viewWidthPx = 1000)
            verify(bouncerInteractor).show(isScrimmed = true)
            assertThat(leftShadeProxiedInput).isNull()
            assertThat(rightShadeProxiedInput).isNull()
            assertThat(singleShadeProxiedInput).isNull()

            falsingManager.setIsFalseTouch(true)
            val cancelEvent = motionEvent(MotionEvent.ACTION_CANCEL)
            assertThat(underTest.shouldIntercept(cancelEvent)).isTrue()
            assertThat(underTest.shouldIntercept(cancelEvent)).isFalse()
            underTest.onTouchEvent(cancelEvent, viewWidthPx = 1000)
            verify(bouncerInteractor).hide()
            assertThat(leftShadeProxiedInput).isNull()
            assertThat(rightShadeProxiedInput).isNull()
            assertThat(singleShadeProxiedInput).isNull()
+0 −1
Original line number Diff line number Diff line
@@ -177,7 +177,6 @@ class NotificationShadeWindowViewControllerTest : SysuiTestCase() {
                            KeyguardTransitionInteractor(
                                repository = FakeKeyguardTransitionRepository(),
                            ),
                        bouncerInteractor = com.android.systemui.util.mockito.mock(),
                        falsingManager = FalsingManagerFake(),
                    )
                },
+0 −1
Original line number Diff line number Diff line
@@ -189,7 +189,6 @@ class NotificationShadeWindowViewTest : SysuiTestCase() {
                            KeyguardTransitionInteractor(
                                repository = FakeKeyguardTransitionRepository(),
                            ),
                        bouncerInteractor = mock(),
                        falsingManager = FalsingManagerFake(),
                    )
                },