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

Commit f8d2ed89 authored by Prince Donkor's avatar Prince Donkor Committed by Android (Google) Code Review
Browse files

Merge "Added exclusions and calculated a default bouncer region" into main

parents 56f4c536 1b924ffc
Loading
Loading
Loading
Loading
+83 −3
Original line number Diff line number Diff line
@@ -63,7 +63,6 @@ import org.mockito.MockitoAnnotations;

import java.util.Collections;
import java.util.Optional;

@SmallTest
@RunWith(AndroidJUnit4.class)
public class BouncerSwipeTouchHandlerTest extends SysuiTestCase {
@@ -119,6 +118,7 @@ public class BouncerSwipeTouchHandlerTest extends SysuiTestCase {
    private static final float TOUCH_REGION = .3f;
    private static final int SCREEN_WIDTH_PX = 1024;
    private static final int SCREEN_HEIGHT_PX = 100;
    private static final float MIN_BOUNCER_HEIGHT = .05f;

    private static final Rect SCREEN_BOUNDS = new Rect(0, 0, 1024, 100);
    private static final UserInfo CURRENT_USER_INFO = new UserInfo(
@@ -142,6 +142,7 @@ public class BouncerSwipeTouchHandlerTest extends SysuiTestCase {
                mFlingAnimationUtils,
                mFlingAnimationUtilsClosing,
                TOUCH_REGION,
                MIN_BOUNCER_HEIGHT,
                mUiEventLogger);

        when(mScrimManager.getCurrentController()).thenReturn(mScrimController);
@@ -160,9 +161,9 @@ public class BouncerSwipeTouchHandlerTest extends SysuiTestCase {
     */
    @Test
    public void testSessionStart() {
        mTouchHandler.getTouchInitiationRegion(SCREEN_BOUNDS, mRegion);
        mTouchHandler.getTouchInitiationRegion(SCREEN_BOUNDS, mRegion, null);

        verify(mRegion).op(mRectCaptor.capture(), eq(Region.Op.UNION));
        verify(mRegion).union(mRectCaptor.capture());
        final Rect bounds = mRectCaptor.getValue();

        final Rect expected = new Rect();
@@ -194,6 +195,85 @@ public class BouncerSwipeTouchHandlerTest extends SysuiTestCase {
        UP,
    }

    @Test
    public void testSwipeUp_whenBouncerInitiallyShowing_reduceHeightWithExclusionRects() {
        mTouchHandler.getTouchInitiationRegion(SCREEN_BOUNDS, mRegion,
                new Rect(0, 0, SCREEN_WIDTH_PX, SCREEN_HEIGHT_PX));
        verify(mRegion).union(mRectCaptor.capture());
        final Rect bounds = mRectCaptor.getValue();

        final Rect expected = new Rect();
        final float minBouncerHeight =
                SCREEN_HEIGHT_PX * MIN_BOUNCER_HEIGHT;
        final int minAllowableBottom = SCREEN_HEIGHT_PX - Math.round(minBouncerHeight);

        expected.set(0, minAllowableBottom , SCREEN_WIDTH_PX, SCREEN_HEIGHT_PX);

        assertThat(bounds).isEqualTo(expected);

        onSessionStartHelper(mTouchHandler, mTouchSession, mNotificationShadeWindowController);
    }

    @Test
    public void testSwipeUp_exclusionRectAtTop_doesNotIntersectGestureArea() {
        mTouchHandler.getTouchInitiationRegion(SCREEN_BOUNDS, mRegion,
                new Rect(0, 0, SCREEN_WIDTH_PX, SCREEN_HEIGHT_PX / 4));
        verify(mRegion).union(mRectCaptor.capture());
        final Rect bounds = mRectCaptor.getValue();

        final Rect expected = new Rect();
        final int gestureAreaTop = SCREEN_HEIGHT_PX - Math.round(SCREEN_HEIGHT_PX * TOUCH_REGION);
        expected.set(0, gestureAreaTop, SCREEN_WIDTH_PX, SCREEN_HEIGHT_PX);

        assertThat(bounds).isEqualTo(expected);
        onSessionStartHelper(mTouchHandler, mTouchSession, mNotificationShadeWindowController);
    }

    @Test
    public void testSwipeUp_exclusionRectBetweenNormalAndMinimumSwipeArea() {
        final int normalSwipeAreaTop = SCREEN_HEIGHT_PX
                - Math.round(SCREEN_HEIGHT_PX * TOUCH_REGION);
        final int minimumSwipeAreaTop = SCREEN_HEIGHT_PX
                - Math.round(SCREEN_HEIGHT_PX * MIN_BOUNCER_HEIGHT);

        Rect exclusionRect = new Rect(0, 0, SCREEN_WIDTH_PX,
                (normalSwipeAreaTop + minimumSwipeAreaTop) / 2);

        mTouchHandler.getTouchInitiationRegion(SCREEN_BOUNDS, mRegion, exclusionRect);

        verify(mRegion).union(mRectCaptor.capture());

        final Rect bounds = mRectCaptor.getValue();
        final Rect expected = new Rect();

        final int expectedSwipeAreaBottom = exclusionRect.bottom;
        expected.set(0, expectedSwipeAreaBottom, SCREEN_WIDTH_PX, SCREEN_HEIGHT_PX);

        assertThat(bounds).isEqualTo(expected);

        onSessionStartHelper(mTouchHandler, mTouchSession, mNotificationShadeWindowController);
    }

    private static void onSessionStartHelper(BouncerSwipeTouchHandler touchHandler,
            DreamTouchHandler.TouchSession touchSession,
            NotificationShadeWindowController notificationShadeWindowController) {
        touchHandler.onSessionStart(touchSession);
        verify(notificationShadeWindowController).setForcePluginOpen(eq(true), any());
        ArgumentCaptor<InputChannelCompat.InputEventListener> eventListenerCaptor =
                ArgumentCaptor.forClass(InputChannelCompat.InputEventListener.class);
        ArgumentCaptor<GestureDetector.OnGestureListener> gestureListenerCaptor =
                ArgumentCaptor.forClass(GestureDetector.OnGestureListener.class);
        verify(touchSession).registerGestureListener(gestureListenerCaptor.capture());
        verify(touchSession).registerInputListener(eventListenerCaptor.capture());

        // A touch within range at the bottom of the screen should trigger listening
        assertThat(gestureListenerCaptor.getValue()
                .onScroll(Mockito.mock(MotionEvent.class),
                        Mockito.mock(MotionEvent.class),
                        1,
                        2)).isTrue();
    }

    /**
     * Makes sure swiping up when bouncer initially showing doesn't change the expansion amount.
     */
+4 −0
Original line number Diff line number Diff line
@@ -1867,6 +1867,10 @@
        .2
    </item>

    <item name="dream_overlay_bouncer_min_region_screen_percentage" format="float" type="dimen">
        .05
    </item>

    <!-- The padding applied to the dream overlay container -->
    <dimen name="dream_overlay_container_padding_start">0dp</dimen>
    <dimen name="dream_overlay_container_padding_end">0dp</dimen>
+20 −13
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ package com.android.systemui.dreams.touch;
import static com.android.systemui.dreams.touch.dagger.BouncerSwipeModule.SWIPE_TO_BOUNCER_FLING_ANIMATION_UTILS_CLOSING;
import static com.android.systemui.dreams.touch.dagger.BouncerSwipeModule.SWIPE_TO_BOUNCER_FLING_ANIMATION_UTILS_OPENING;
import static com.android.systemui.dreams.touch.dagger.BouncerSwipeModule.SWIPE_TO_BOUNCER_START_REGION;
import static com.android.systemui.dreams.touch.dagger.BouncerSwipeModule.MIN_BOUNCER_ZONE_SCREEN_PERCENTAGE;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -81,6 +82,7 @@ public class BouncerSwipeTouchHandler implements DreamTouchHandler {
    private final LockPatternUtils mLockPatternUtils;
    private final UserTracker mUserTracker;
    private final float mBouncerZoneScreenPercentage;
    private final float mMinBouncerZoneScreenPercentage;

    private final ScrimManager mScrimManager;
    private ScrimController mCurrentScrimController;
@@ -222,6 +224,7 @@ public class BouncerSwipeTouchHandler implements DreamTouchHandler {
            @Named(SWIPE_TO_BOUNCER_FLING_ANIMATION_UTILS_CLOSING)
                    FlingAnimationUtils flingAnimationUtilsClosing,
            @Named(SWIPE_TO_BOUNCER_START_REGION) float swipeRegionPercentage,
            @Named(MIN_BOUNCER_ZONE_SCREEN_PERCENTAGE) float minRegionPercentage,
            UiEventLogger uiEventLogger) {
        mCentralSurfaces = centralSurfaces;
        mScrimManager = scrimManager;
@@ -229,6 +232,7 @@ public class BouncerSwipeTouchHandler implements DreamTouchHandler {
        mLockPatternUtils = lockPatternUtils;
        mUserTracker = userTracker;
        mBouncerZoneScreenPercentage = swipeRegionPercentage;
        mMinBouncerZoneScreenPercentage = minRegionPercentage;
        mFlingAnimationUtils = flingAnimationUtils;
        mFlingAnimationUtilsClosing = flingAnimationUtilsClosing;
        mValueAnimatorCreator = valueAnimatorCreator;
@@ -237,24 +241,27 @@ public class BouncerSwipeTouchHandler implements DreamTouchHandler {
    }

    @Override
    public void getTouchInitiationRegion(Rect bounds, Region region) {
    public void getTouchInitiationRegion(Rect bounds, Region region, Rect exclusionRect) {
        final int width = bounds.width();
        final int height = bounds.height();
        final float minBouncerHeight = height * mMinBouncerZoneScreenPercentage;
        final int minAllowableBottom = Math.round(height * (1 - mMinBouncerZoneScreenPercentage));

        if (mCentralSurfaces.map(CentralSurfaces::isBouncerShowing).orElse(false)) {
            region.op(new Rect(0, 0, width,
                            Math.round(
                                    height * mBouncerZoneScreenPercentage)),
                    Region.Op.UNION);
        } else {
            region.op(new Rect(0,
                            Math.round(height * (1 - mBouncerZoneScreenPercentage)),
                            width,
                            height),
                    Region.Op.UNION);
        final boolean isBouncerShowing =
                mCentralSurfaces.map(CentralSurfaces::isBouncerShowing).orElse(false);
        final Rect normalRegion = isBouncerShowing
                ? new Rect(0, 0, width, Math.round(height * mBouncerZoneScreenPercentage))
                : new Rect(0, Math.round(height * (1 - mBouncerZoneScreenPercentage)),
                        width, height);

        if (!isBouncerShowing && exclusionRect != null) {
            int lowestBottom = Math.min(Math.max(0, exclusionRect.bottom), minAllowableBottom);
            normalRegion.top = Math.max(normalRegion.top, lowestBottom);
        }
        region.union(normalRegion);
    }


    @Override
    public void onSessionStart(TouchSession session) {
        mVelocityTracker = mVelocityTrackerFactory.obtain();
+1 −1
Original line number Diff line number Diff line
@@ -87,7 +87,7 @@ public class CommunalTouchHandler implements DreamTouchHandler {
    }

    @Override
    public void getTouchInitiationRegion(Rect bounds, Region region) {
    public void getTouchInitiationRegion(Rect bounds, Region region, Rect exclusionRect) {
        final Rect outBounds = new Rect(bounds);
        outBounds.inset(outBounds.width() - mInitiationWidth, 0, 0, 0);
        region.op(outBounds, Region.Op.UNION);
+73 −11
Original line number Diff line number Diff line
@@ -18,9 +18,15 @@ package com.android.systemui.dreams.touch;

import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;

import static com.android.systemui.shared.Flags.bouncerAreaExclusion;

import android.graphics.Rect;
import android.graphics.Region;
import android.os.RemoteException;
import android.util.Log;
import android.view.GestureDetector;
import android.view.ISystemGestureExclusionListener;
import android.view.IWindowManager;
import android.view.InputEvent;
import android.view.MotionEvent;

@@ -31,6 +37,8 @@ import androidx.lifecycle.Lifecycle;
import androidx.lifecycle.LifecycleObserver;
import androidx.lifecycle.LifecycleOwner;

import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.DisplayId;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dreams.touch.dagger.InputSessionComponent;
import com.android.systemui.shared.system.InputChannelCompat;
@@ -58,8 +66,23 @@ import javax.inject.Inject;
public class DreamOverlayTouchMonitor {
    // This executor is used to protect {@code mActiveTouchSessions} from being modified
    // concurrently. Any operation that adds or removes values should use this executor.
    private final Executor mExecutor;
    public String TAG = "DreamOverlayTouchMonitor";
    private final Executor mMainExecutor;
    private final Executor mBackgroundExecutor;
    private final Lifecycle mLifecycle;
    private Rect mExclusionRect = null;

    private ISystemGestureExclusionListener mGestureExclusionListener =
            new ISystemGestureExclusionListener.Stub() {
                @Override
                public void onSystemGestureExclusionChanged(int displayId,
                        Region systemGestureExclusion,
                        Region systemGestureExclusionUnrestricted) {
                    mExclusionRect = systemGestureExclusion.getBounds();
                }
            };



    /**
     * Adds a new {@link TouchSessionImpl} to participate in receiving future touches and gestures.
@@ -67,7 +90,7 @@ public class DreamOverlayTouchMonitor {
    private ListenableFuture<DreamTouchHandler.TouchSession> push(
            TouchSessionImpl touchSessionImpl) {
        return CallbackToFutureAdapter.getFuture(completer -> {
            mExecutor.execute(() -> {
            mMainExecutor.execute(() -> {
                if (!mActiveTouchSessions.remove(touchSessionImpl)) {
                    completer.set(null);
                    return;
@@ -90,7 +113,7 @@ public class DreamOverlayTouchMonitor {
    private ListenableFuture<DreamTouchHandler.TouchSession> pop(
            TouchSessionImpl touchSessionImpl) {
        return CallbackToFutureAdapter.getFuture(completer -> {
            mExecutor.execute(() -> {
            mMainExecutor.execute(() -> {
                if (mActiveTouchSessions.remove(touchSessionImpl)) {
                    touchSessionImpl.onRemoved();

@@ -240,6 +263,17 @@ public class DreamOverlayTouchMonitor {
     */
    private void startMonitoring() {
        stopMonitoring(true);
        if (bouncerAreaExclusion()) {
            mBackgroundExecutor.execute(() -> {
                try {
                    mWindowManagerService.registerSystemGestureExclusionListener(
                            mGestureExclusionListener, mDisplayId);
                } catch (RemoteException e) {
                    // Handle the exception
                    Log.e(TAG, "Failed to register gesture exclusion listener", e);
                }
            });
        }
        mCurrentInputSession = mInputSessionFactory.create(
                "dreamOverlay",
                mInputEventListener,
@@ -252,6 +286,18 @@ public class DreamOverlayTouchMonitor {
     * Destroys any active {@link InputSession}.
     */
    private void stopMonitoring(boolean force) {
        mExclusionRect = null;
        if (bouncerAreaExclusion()) {
            mBackgroundExecutor.execute(() -> {
                try {
                    mWindowManagerService.unregisterSystemGestureExclusionListener(
                            mGestureExclusionListener, mDisplayId);
                } catch (RemoteException e) {
                    // Handle the exception
                    Log.e(TAG, "unregisterSystemGestureExclusionListener: failed", e);
                }
            });
        }
        if (mCurrentInputSession == null) {
            return;
        }
@@ -263,7 +309,7 @@ public class DreamOverlayTouchMonitor {

        // When we stop monitoring touches, we must ensure that all active touch sessions and
        // descendants informed of the removal so any cleanup for active tracking can proceed.
        mExecutor.execute(() -> mActiveTouchSessions.forEach(touchSession -> {
        mMainExecutor.execute(() -> mActiveTouchSessions.forEach(touchSession -> {
            while (touchSession != null) {
                touchSession.onRemoved();
                touchSession = touchSession.getPredecessor();
@@ -297,9 +343,13 @@ public class DreamOverlayTouchMonitor {
                            }
                            final Rect maxBounds = mDisplayHelper.getMaxBounds(ev.getDisplayId(),
                                    TYPE_APPLICATION_OVERLAY);

                            final Region initiationRegion = Region.obtain();
                    handler.getTouchInitiationRegion(maxBounds, initiationRegion);
                            Rect exclusionRect = null;
                            if (bouncerAreaExclusion()) {
                                exclusionRect = getCurrentExclusionRect();
                            }
                            handler.getTouchInitiationRegion(
                                            maxBounds, initiationRegion, exclusionRect);

                    if (!initiationRegion.isEmpty()) {
                        // Initiation regions require a motion event to determine pointer location
@@ -335,6 +385,9 @@ public class DreamOverlayTouchMonitor {
                    .flatMap(Collection::stream)
                    .forEach(inputEventListener -> inputEventListener.onInputEvent(ev));
        }
                    private Rect getCurrentExclusionRect() {
                        return mExclusionRect;
                    }
    };

    /**
@@ -416,6 +469,9 @@ public class DreamOverlayTouchMonitor {

    private InputSessionComponent.Factory mInputSessionFactory;
    private InputSession mCurrentInputSession;
    private final int mDisplayId;
    private final IWindowManager mWindowManagerService;


    /**
     * Designated constructor for {@link DreamOverlayTouchMonitor}
@@ -432,15 +488,21 @@ public class DreamOverlayTouchMonitor {
    @Inject
    public DreamOverlayTouchMonitor(
            @Main Executor executor,
            @Background Executor backgroundExecutor,
            Lifecycle lifecycle,
            InputSessionComponent.Factory inputSessionFactory,
            DisplayHelper displayHelper,
            Set<DreamTouchHandler> handlers) {
            Set<DreamTouchHandler> handlers,
            IWindowManager windowManagerService,
            @DisplayId int displayId) {
        mDisplayId = displayId;
        mHandlers = handlers;
        mInputSessionFactory = inputSessionFactory;
        mExecutor = executor;
        mMainExecutor = executor;
        mBackgroundExecutor = backgroundExecutor;
        mLifecycle = lifecycle;
        mDisplayHelper = displayHelper;
        mWindowManagerService = windowManagerService;
    }

    /**
Loading