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

Commit a430a9c5 authored by Bryce Lee's avatar Bryce Lee Committed by Android (Google) Code Review
Browse files

Merge changes from topic "267565290-udc" into udc-dev

* changes:
  Allow swiping down notification shade over dream.
  Allow in-progress touch sessions to continue outside resume.
  Suppress transient bars over dreams.
parents 1e380aea fb8b8e2e
Loading
Loading
Loading
Loading
+20 −3
Original line number Diff line number Diff line
@@ -101,6 +101,10 @@ public class DreamOverlayTouchMonitor {

                    completer.set(predecessor);
                }

                if (mActiveTouchSessions.isEmpty() && mStopMonitoringPending) {
                    stopMonitoring(false);
                }
            });

            return "DreamOverlayTouchMonitor::pop";
@@ -214,7 +218,12 @@ public class DreamOverlayTouchMonitor {

        @Override
        public void onPause(@NonNull LifecycleOwner owner) {
            stopMonitoring();
            stopMonitoring(false);
        }

        @Override
        public void onDestroy(LifecycleOwner owner) {
            stopMonitoring(true);
        }
    };

@@ -222,7 +231,7 @@ public class DreamOverlayTouchMonitor {
     * When invoked, instantiates a new {@link InputSession} to monitor touch events.
     */
    private void startMonitoring() {
        stopMonitoring();
        stopMonitoring(true);
        mCurrentInputSession = mInputSessionFactory.create(
                "dreamOverlay",
                mInputEventListener,
@@ -234,11 +243,16 @@ public class DreamOverlayTouchMonitor {
    /**
     * Destroys any active {@link InputSession}.
     */
    private void stopMonitoring() {
    private void stopMonitoring(boolean force) {
        if (mCurrentInputSession == null) {
            return;
        }

        if (!mActiveTouchSessions.isEmpty() && !force) {
            mStopMonitoringPending = true;
            return;
        }

        // 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 -> {
@@ -250,6 +264,7 @@ public class DreamOverlayTouchMonitor {

        mCurrentInputSession.dispose();
        mCurrentInputSession = null;
        mStopMonitoringPending = false;
    }


@@ -257,6 +272,8 @@ public class DreamOverlayTouchMonitor {
    private final Collection<DreamTouchHandler> mHandlers;
    private final DisplayHelper mDisplayHelper;

    private boolean mStopMonitoringPending;

    private InputChannelCompat.InputEventListener mInputEventListener =
            new InputChannelCompat.InputEventListener() {
        @Override
+92 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2023 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.systemui.dreams.touch;

import static com.android.systemui.dreams.touch.dagger.ShadeModule.NOTIFICATION_SHADE_GESTURE_INITIATION_HEIGHT;

import android.graphics.Rect;
import android.graphics.Region;
import android.view.GestureDetector;
import android.view.MotionEvent;

import com.android.systemui.shade.NotificationPanelViewController;
import com.android.systemui.statusbar.phone.CentralSurfaces;

import java.util.Optional;

import javax.inject.Inject;
import javax.inject.Named;

/**
 * {@link ShadeTouchHandler} is responsible for handling swipe down gestures over dream
 * to bring down the shade.
 */
public class ShadeTouchHandler implements DreamTouchHandler {
    private final Optional<CentralSurfaces> mSurfaces;
    private final int mInitiationHeight;

    @Inject
    ShadeTouchHandler(Optional<CentralSurfaces> centralSurfaces,
            @Named(NOTIFICATION_SHADE_GESTURE_INITIATION_HEIGHT) int initiationHeight) {
        mSurfaces = centralSurfaces;
        mInitiationHeight = initiationHeight;
    }

    @Override
    public void onSessionStart(TouchSession session) {
        if (mSurfaces.map(CentralSurfaces::isBouncerShowing).orElse(false)) {
            session.pop();
            return;
        }

        session.registerInputListener(ev -> {
            final NotificationPanelViewController viewController =
                    mSurfaces.map(CentralSurfaces::getNotificationPanelViewController).orElse(null);

            if (viewController != null) {
                viewController.handleExternalTouch((MotionEvent) ev);
            }

            if (ev instanceof MotionEvent) {
                if (((MotionEvent) ev).getAction() == MotionEvent.ACTION_UP) {
                    session.pop();
                }
            }
        });

        session.registerGestureListener(new GestureDetector.SimpleOnGestureListener() {
            @Override
            public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,
                    float distanceY) {
                return true;
            }

            @Override
            public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
                    float velocityY) {
                return true;
            }
        });
    }

    @Override
    public void getTouchInitiationRegion(Rect bounds, Region region) {
        final Rect outBounds = new Rect(bounds);
        outBounds.inset(0, 0, 0, outBounds.height() - mInitiationHeight);
        region.op(outBounds, Region.Op.UNION);
    }
}
+1 −0
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@ import dagger.Module;
 */
@Module(includes = {
            BouncerSwipeModule.class,
            ShadeModule.class,
        }, subcomponents = {
            InputSessionComponent.class,
})
+62 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2023 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.systemui.dreams.touch.dagger;

import android.content.res.Resources;

import com.android.systemui.R;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dreams.touch.DreamTouchHandler;
import com.android.systemui.dreams.touch.ShadeTouchHandler;

import dagger.Module;
import dagger.Provides;
import dagger.multibindings.IntoSet;

import javax.inject.Named;

/**
 * Dependencies for swipe down to notification over dream.
 */
@Module
public class ShadeModule {
    /**
     * The height, defined in pixels, of the gesture initiation region at the top of the screen for
     * swiping down notifications.
     */
    public static final String NOTIFICATION_SHADE_GESTURE_INITIATION_HEIGHT =
            "notification_shade_gesture_initiation_height";

    /**
     * Provides {@link ShadeTouchHandler} to handle notification swipe down over dream.
     */
    @Provides
    @IntoSet
    public static DreamTouchHandler providesNotificationShadeTouchHandler(
            ShadeTouchHandler touchHandler) {
        return touchHandler;
    }

    /**
     * Provides the height of the gesture area for notification swipe down.
     */
    @Provides
    @Named(NOTIFICATION_SHADE_GESTURE_INITIATION_HEIGHT)
    public static int providesNotificationShadeGestureRegionHeight(@Main Resources resources) {
        return resources.getDimensionPixelSize(R.dimen.dream_overlay_status_bar_height);
    }
}
+61 −2
Original line number Diff line number Diff line
@@ -399,7 +399,21 @@ public class DreamOverlayTouchMonitorTest extends SysuiTestCase {
    }

    @Test
    public void testPause() {
    public void testPauseWithNoActiveSessions() {
        final DreamTouchHandler touchHandler = Mockito.mock(DreamTouchHandler.class);

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

        environment.updateLifecycle(observerOwnerPair -> {
            observerOwnerPair.first.onPause(observerOwnerPair.second);
        });

        environment.verifyInputSessionDispose();
    }

    @Test
    public void testDeferredPauseWithActiveSessions() {
        final DreamTouchHandler touchHandler = Mockito.mock(DreamTouchHandler.class);

        final Environment environment = new Environment(Stream.of(touchHandler)
@@ -417,13 +431,58 @@ public class DreamOverlayTouchMonitorTest extends SysuiTestCase {
        environment.publishInputEvent(event);
        verify(eventListener).onInputEvent(eq(event));

        final ArgumentCaptor<DreamTouchHandler.TouchSession> touchSessionArgumentCaptor =
                ArgumentCaptor.forClass(DreamTouchHandler.TouchSession.class);

        verify(touchHandler).onSessionStart(touchSessionArgumentCaptor.capture());

        environment.updateLifecycle(observerOwnerPair -> {
            observerOwnerPair.first.onPause(observerOwnerPair.second);
        });

        verify(environment.mInputSession, never()).dispose();

        // End session
        touchSessionArgumentCaptor.getValue().pop();
        environment.executeAll();

        // Check to make sure the input session is now disposed.
        environment.verifyInputSessionDispose();
    }

    @Test
    public void testDestroyWithActiveSessions() {
        final DreamTouchHandler touchHandler = Mockito.mock(DreamTouchHandler.class);

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

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

        // Ensure session started
        final InputChannelCompat.InputEventListener eventListener =
                registerInputEventListener(touchHandler);

        // First event will be missed since we register after the execution loop,
        final InputEvent event = Mockito.mock(InputEvent.class);
        environment.publishInputEvent(event);
        verify(eventListener).onInputEvent(eq(event));

        final ArgumentCaptor<DreamTouchHandler.TouchSession> touchSessionArgumentCaptor =
                ArgumentCaptor.forClass(DreamTouchHandler.TouchSession.class);

        verify(touchHandler).onSessionStart(touchSessionArgumentCaptor.capture());

        environment.updateLifecycle(observerOwnerPair -> {
            observerOwnerPair.first.onDestroy(observerOwnerPair.second);
        });

        // Check to make sure the input session is now disposed.
        environment.verifyInputSessionDispose();
    }


    @Test
    public void testPilfering() {
        final DreamTouchHandler touchHandler1 = Mockito.mock(DreamTouchHandler.class);
@@ -476,7 +535,7 @@ public class DreamOverlayTouchMonitorTest extends SysuiTestCase {
        environment.executeAll();

        environment.updateLifecycle(observerOwnerPair -> {
            observerOwnerPair.first.onPause(observerOwnerPair.second);
            observerOwnerPair.first.onDestroy(observerOwnerPair.second);
        });

        environment.executeAll();
Loading