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

Commit c1095d06 authored by William Xiao's avatar William Xiao Committed by Android (Google) Code Review
Browse files

Merge "Fix dragging down notification shade handling over Glanceable Hub." into main

parents 0e0c6ed9 6376fc1c
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -146,6 +146,14 @@ class ShadeTouchHandlerTest : SysuiTestCase() {
        verify(mShadeViewController, never()).handleExternalTouch(any())
    }

    @Test
    fun testCancelMotionEvent_popsTouchSession() {
        swipe(Direction.DOWN)
        val event = MotionEvent.obtain(0, 0, MotionEvent.ACTION_CANCEL, 0f, 0f, 0)
        mInputListenerCaptor.lastValue.onInputEvent(event)
        verify(mTouchSession).pop()
    }

    /**
     * Simulates a swipe in the given direction and returns true if the touch was intercepted by the
     * touch handler's gesture listener.
+2 −1
Original line number Diff line number Diff line
@@ -79,7 +79,8 @@ public class ShadeTouchHandler implements TouchHandler {
                if (mCapture != null && mCapture) {
                    sendTouchEvent((MotionEvent) ev);
                }
                if (((MotionEvent) ev).getAction() == MotionEvent.ACTION_UP) {
                if (((MotionEvent) ev).getAction() == MotionEvent.ACTION_UP
                        || ((MotionEvent) ev).getAction() == MotionEvent.ACTION_CANCEL) {
                    session.pop();
                }
            }
+7 −2
Original line number Diff line number Diff line
@@ -128,8 +128,13 @@ public class TouchMonitor {
                    completer.set(predecessor);
                }

                if (mActiveTouchSessions.isEmpty() && mStopMonitoringPending) {
                if (mActiveTouchSessions.isEmpty()) {
                    if (mStopMonitoringPending) {
                        stopMonitoring(false);
                    } else {
                        // restart monitoring to reset any destructive state on the input session
                        startMonitoring();
                    }
                }
            });

+33 −9
Original line number Diff line number Diff line
@@ -56,13 +56,12 @@ import com.android.systemui.scene.shared.flag.SceneContainerFlag
import com.android.systemui.scene.shared.model.SceneDataSourceDelegator
import com.android.systemui.shade.domain.interactor.ShadeInteractor
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController
import com.android.systemui.util.kotlin.BooleanFlowOperators.allOf
import com.android.systemui.util.kotlin.BooleanFlowOperators.anyOf
import com.android.systemui.util.kotlin.BooleanFlowOperators.not
import com.android.systemui.util.kotlin.collectFlow
import java.util.function.Consumer
import javax.inject.Inject
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.launch

/**
@@ -165,7 +164,14 @@ constructor(
     *
     * Based on [ShadeInteractor.isAnyFullyExpanded] and [ShadeInteractor.isUserInteracting].
     */
    private var shadeShowing = false
    private var shadeShowingAndConsumingTouches = false

    /**
     * True if the shade ever fully expands and the user isn't interacting with it (aka finger on
     * screen dragging). In this case, the shade should handle all touch events until it has fully
     * collapsed.
     */
    private var userNotInteractiveAtShadeFullyExpanded = false

    /**
     * True if the device is dreaming, in which case we shouldn't do anything for top/bottom swipes
@@ -317,9 +323,25 @@ constructor(
        )
        collectFlow(
            containerView,
            allOf(shadeInteractor.isAnyFullyExpanded, not(shadeInteractor.isUserInteracting)),
            {
                shadeShowing = it
            combine(
                shadeInteractor.isAnyFullyExpanded,
                shadeInteractor.isUserInteracting,
                shadeInteractor.isShadeFullyCollapsed,
                ::Triple
            ),
            { (isFullyExpanded, isUserInteracting, isShadeFullyCollapsed) ->
                val expandedAndNotInteractive = isFullyExpanded && !isUserInteracting

                // If we ever are fully expanded and not interacting, capture this state as we
                // should not handle touches until we fully collapse again
                userNotInteractiveAtShadeFullyExpanded =
                    !isShadeFullyCollapsed &&
                        (userNotInteractiveAtShadeFullyExpanded || expandedAndNotInteractive)

                // If the shade reaches full expansion without interaction, then we should allow it
                // to consume touches rather than handling it here until it disappears.
                shadeShowingAndConsumingTouches =
                    userNotInteractiveAtShadeFullyExpanded || expandedAndNotInteractive
                updateTouchHandlingState()
            }
        )
@@ -337,7 +359,8 @@ constructor(
     * Also clears gesture exclusion zones when the hub is occluded or gone.
     */
    private fun updateTouchHandlingState() {
        val shouldInterceptGestures = hubShowing && !(shadeShowing || anyBouncerShowing)
        val shouldInterceptGestures =
            hubShowing && !(shadeShowingAndConsumingTouches || anyBouncerShowing)
        if (shouldInterceptGestures) {
            lifecycleRegistry.currentState = Lifecycle.State.RESUMED
        } else {
@@ -395,11 +418,12 @@ constructor(
    private fun handleTouchEventOnCommunalView(view: View, ev: MotionEvent): Boolean {
        val isDown = ev.actionMasked == MotionEvent.ACTION_DOWN
        val isUp = ev.actionMasked == MotionEvent.ACTION_UP
        val isMove = ev.actionMasked == MotionEvent.ACTION_MOVE
        val isCancel = ev.actionMasked == MotionEvent.ACTION_CANCEL

        val hubOccluded = anyBouncerShowing || shadeShowing
        val hubOccluded = anyBouncerShowing || shadeShowingAndConsumingTouches

        if (isDown && !hubOccluded) {
        if ((isDown || isMove) && !hubOccluded) {
            isTrackingHubTouch = true
        }

+29 −0
Original line number Diff line number Diff line
@@ -710,6 +710,35 @@ public class TouchMonitorTest extends SysuiTestCase {
        environment.verifyLifecycleObserversUnregistered();
    }

    @Test
    public void testLastSessionPop_createsNewInputSession() {
        final TouchHandler touchHandler = createTouchHandler();

        final TouchHandler.TouchSession.Callback callback =
                Mockito.mock(TouchHandler.TouchSession.Callback.class);

        final Environment environment = new Environment(Stream.of(touchHandler)
                .collect(Collectors.toCollection(HashSet::new)), mKosmos);

        final InputEvent initialEvent = Mockito.mock(InputEvent.class);
        environment.publishInputEvent(initialEvent);

        final TouchHandler.TouchSession session = captureSession(touchHandler);
        session.registerCallback(callback);

        // Clear invocations on input session and factory.
        clearInvocations(environment.mInputFactory);
        clearInvocations(environment.mInputSession);

        // Pop only active touch session.
        session.pop();
        environment.executeAll();

        // Verify that input session disposed and new session requested from factory.
        verify(environment.mInputSession).dispose();
        verify(environment.mInputFactory).create(any(), any(), any(), anyBoolean());
    }

    private GestureDetector.OnGestureListener registerGestureListener(TouchHandler handler) {
        final GestureDetector.OnGestureListener gestureListener = Mockito.mock(
                GestureDetector.OnGestureListener.class);
Loading