From 52329d28abeadb4dbcb59726af8d906a952b1439 Mon Sep 17 00:00:00 2001 From: Bryce Lee Date: Thu, 23 Mar 2023 00:16:52 +0000 Subject: [PATCH] Correct display dimensions considered. This changelist makes sure the full screen size is considered when accounting for the dream overlay. Previously, insets would be subtracted from the overall dimensions. Test: atest DreamOverlayTouchMonitorTest#testReportedDisplayBounds Fixes: 267565290 Change-Id: I48c072491efc62c49385ae5f4684d99585a05895 --- .../touch/BouncerSwipeTouchHandler.java | 26 ++++----- .../touch/DreamOverlayTouchMonitor.java | 29 ++++++++-- .../dreams/touch/DreamTouchHandler.java | 8 ++- .../systemui/touch/TouchInsetManager.java | 5 +- .../systemui/util/display/DisplayHelper.java | 53 +++++++++++++++++++ .../touch/BouncerSwipeTouchHandlerTest.java | 13 ++--- .../touch/DreamOverlayTouchMonitorTest.java | 44 +++++++++++++-- .../systemui/touch/TouchInsetManagerTest.java | 7 ++- 8 files changed, 148 insertions(+), 37 deletions(-) create mode 100644 packages/SystemUI/src/com/android/systemui/util/display/DisplayHelper.java diff --git a/packages/SystemUI/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandler.java b/packages/SystemUI/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandler.java index a7b3bbcbc37b6..2ea7bce664526 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandler.java +++ b/packages/SystemUI/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandler.java @@ -25,7 +25,6 @@ import android.animation.AnimatorListenerAdapter; import android.animation.ValueAnimator; import android.graphics.Rect; import android.graphics.Region; -import android.util.DisplayMetrics; import android.util.Log; import android.view.GestureDetector; import android.view.InputEvent; @@ -89,8 +88,6 @@ public class BouncerSwipeTouchHandler implements DreamTouchHandler { private final FlingAnimationUtils mFlingAnimationUtils; private final FlingAnimationUtils mFlingAnimationUtilsClosing; - private final DisplayMetrics mDisplayMetrics; - private Boolean mCapture; private Boolean mExpanded; @@ -161,7 +158,7 @@ public class BouncerSwipeTouchHandler implements DreamTouchHandler { // (0). final float dragDownAmount = e2.getY() - e1.getY(); final float screenTravelPercentage = Math.abs(e1.getY() - e2.getY()) - / mCentralSurfaces.get().getDisplayHeight(); + / mTouchSession.getBounds().height(); setPanelExpansion(mBouncerInitiallyShowing ? screenTravelPercentage : 1 - screenTravelPercentage, dragDownAmount); return true; @@ -202,7 +199,6 @@ public class BouncerSwipeTouchHandler implements DreamTouchHandler { @Inject public BouncerSwipeTouchHandler( - DisplayMetrics displayMetrics, ScrimManager scrimManager, Optional centralSurfaces, NotificationShadeWindowController notificationShadeWindowController, @@ -214,7 +210,6 @@ public class BouncerSwipeTouchHandler implements DreamTouchHandler { FlingAnimationUtils flingAnimationUtilsClosing, @Named(SWIPE_TO_BOUNCER_START_REGION) float swipeRegionPercentage, UiEventLogger uiEventLogger) { - mDisplayMetrics = displayMetrics; mCentralSurfaces = centralSurfaces; mScrimManager = scrimManager; mNotificationShadeWindowController = notificationShadeWindowController; @@ -227,19 +222,20 @@ public class BouncerSwipeTouchHandler implements DreamTouchHandler { } @Override - public void getTouchInitiationRegion(Region region) { + public void getTouchInitiationRegion(Rect bounds, Region region) { + final int width = bounds.width(); + final int height = bounds.height(); + if (mCentralSurfaces.map(CentralSurfaces::isBouncerShowing).orElse(false)) { - region.op(new Rect(0, 0, mDisplayMetrics.widthPixels, + region.op(new Rect(0, 0, width, Math.round( - mDisplayMetrics.heightPixels * mBouncerZoneScreenPercentage)), + height * mBouncerZoneScreenPercentage)), Region.Op.UNION); } else { region.op(new Rect(0, - Math.round( - mDisplayMetrics.heightPixels - * (1 - mBouncerZoneScreenPercentage)), - mDisplayMetrics.widthPixels, - mDisplayMetrics.heightPixels), + Math.round(height * (1 - mBouncerZoneScreenPercentage)), + width, + height), Region.Op.UNION); } } @@ -356,7 +352,7 @@ public class BouncerSwipeTouchHandler implements DreamTouchHandler { } // The animation utils deal in pixel units, rather than expansion height. - final float viewHeight = mCentralSurfaces.get().getDisplayHeight(); + final float viewHeight = mTouchSession.getBounds().height(); final float currentHeight = viewHeight * mCurrentExpansion; final float targetHeight = viewHeight * expansion; final float expansionHeight = targetHeight - currentHeight; diff --git a/packages/SystemUI/src/com/android/systemui/dreams/touch/DreamOverlayTouchMonitor.java b/packages/SystemUI/src/com/android/systemui/dreams/touch/DreamOverlayTouchMonitor.java index b8b459e1c68cb..43e4c62b60d68 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/touch/DreamOverlayTouchMonitor.java +++ b/packages/SystemUI/src/com/android/systemui/dreams/touch/DreamOverlayTouchMonitor.java @@ -16,6 +16,9 @@ package com.android.systemui.dreams.touch; +import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; + +import android.graphics.Rect; import android.graphics.Region; import android.view.GestureDetector; import android.view.InputEvent; @@ -31,6 +34,7 @@ import androidx.lifecycle.LifecycleOwner; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.dreams.touch.dagger.InputSessionComponent; import com.android.systemui.shared.system.InputChannelCompat; +import com.android.systemui.util.display.DisplayHelper; import com.google.common.util.concurrent.ListenableFuture; @@ -69,7 +73,8 @@ public class DreamOverlayTouchMonitor { } final TouchSessionImpl touchSession = - new TouchSessionImpl(this, touchSessionImpl); + new TouchSessionImpl(this, touchSessionImpl.getBounds(), + touchSessionImpl); mActiveTouchSessions.add(touchSession); completer.set(touchSession); }); @@ -120,10 +125,13 @@ public class DreamOverlayTouchMonitor { private final TouchSessionImpl mPredecessor; private final DreamOverlayTouchMonitor mTouchMonitor; + private final Rect mBounds; - TouchSessionImpl(DreamOverlayTouchMonitor touchMonitor, TouchSessionImpl predecessor) { + TouchSessionImpl(DreamOverlayTouchMonitor touchMonitor, Rect bounds, + TouchSessionImpl predecessor) { mPredecessor = predecessor; mTouchMonitor = touchMonitor; + mBounds = bounds; } @Override @@ -185,6 +193,11 @@ public class DreamOverlayTouchMonitor { private void onRemoved() { mCallbacks.forEach(callback -> callback.onRemoved()); } + + @Override + public Rect getBounds() { + return mBounds; + } } /** @@ -242,6 +255,7 @@ public class DreamOverlayTouchMonitor { private final HashSet mActiveTouchSessions = new HashSet<>(); private final Collection mHandlers; + private final DisplayHelper mDisplayHelper; private InputChannelCompat.InputEventListener mInputEventListener = new InputChannelCompat.InputEventListener() { @@ -253,8 +267,11 @@ public class DreamOverlayTouchMonitor { new HashMap<>(); for (DreamTouchHandler handler : mHandlers) { + final Rect maxBounds = mDisplayHelper.getMaxBounds(ev.getDisplayId(), + TYPE_APPLICATION_OVERLAY); + final Region initiationRegion = Region.obtain(); - handler.getTouchInitiationRegion(initiationRegion); + handler.getTouchInitiationRegion(maxBounds, initiationRegion); if (!initiationRegion.isEmpty()) { // Initiation regions require a motion event to determine pointer location @@ -272,8 +289,8 @@ public class DreamOverlayTouchMonitor { } } - final TouchSessionImpl sessionStack = - new TouchSessionImpl(DreamOverlayTouchMonitor.this, null); + final TouchSessionImpl sessionStack = new TouchSessionImpl( + DreamOverlayTouchMonitor.this, maxBounds, null); mActiveTouchSessions.add(sessionStack); sessionMap.put(handler, sessionStack); } @@ -389,11 +406,13 @@ public class DreamOverlayTouchMonitor { @Main Executor executor, Lifecycle lifecycle, InputSessionComponent.Factory inputSessionFactory, + DisplayHelper displayHelper, Set handlers) { mHandlers = handlers; mInputSessionFactory = inputSessionFactory; mExecutor = executor; mLifecycle = lifecycle; + mDisplayHelper = displayHelper; } /** diff --git a/packages/SystemUI/src/com/android/systemui/dreams/touch/DreamTouchHandler.java b/packages/SystemUI/src/com/android/systemui/dreams/touch/DreamTouchHandler.java index 8288fcfb54811..b37010cfc07bf 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/touch/DreamTouchHandler.java +++ b/packages/SystemUI/src/com/android/systemui/dreams/touch/DreamTouchHandler.java @@ -16,6 +16,7 @@ package com.android.systemui.dreams.touch; +import android.graphics.Rect; import android.graphics.Region; import android.view.GestureDetector; @@ -77,6 +78,11 @@ public interface DreamTouchHandler { * Returns the number of currently active sessions. */ int getActiveSessionCount(); + + /** + * Returns the bounds of the display the touch region. + */ + Rect getBounds(); } /** @@ -84,7 +90,7 @@ public interface DreamTouchHandler { * indicating the entire screen should be considered. * @param region A {@link Region} that is passed in to the target entry touch region. */ - default void getTouchInitiationRegion(Region region) { + default void getTouchInitiationRegion(Rect bounds, Region region) { } /** diff --git a/packages/SystemUI/src/com/android/systemui/touch/TouchInsetManager.java b/packages/SystemUI/src/com/android/systemui/touch/TouchInsetManager.java index 166ac9e737f3b..f09b2f76e38c4 100644 --- a/packages/SystemUI/src/com/android/systemui/touch/TouchInsetManager.java +++ b/packages/SystemUI/src/com/android/systemui/touch/TouchInsetManager.java @@ -21,6 +21,7 @@ import android.graphics.Region; import android.util.Log; import android.view.AttachedSurfaceControl; import android.view.View; +import android.view.ViewGroup; import androidx.concurrent.futures.CallbackToFutureAdapter; @@ -118,7 +119,9 @@ public class TouchInsetManager { affectedSurfaces.put(surface, Region.obtain()); } final Rect boundaries = new Rect(); - view.getBoundsOnScreen(boundaries); + view.getDrawingRect(boundaries); + ((ViewGroup) view.getRootView()) + .offsetDescendantRectToMyCoords(view, boundaries); affectedSurfaces.get(surface).op(boundaries, Region.Op.UNION); }); mManager.setTouchRegions(this, affectedSurfaces); diff --git a/packages/SystemUI/src/com/android/systemui/util/display/DisplayHelper.java b/packages/SystemUI/src/com/android/systemui/util/display/DisplayHelper.java new file mode 100644 index 0000000000000..8acd6535e751e --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/util/display/DisplayHelper.java @@ -0,0 +1,53 @@ +/* + * 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.util.display; + +import android.content.Context; +import android.graphics.Rect; +import android.hardware.display.DisplayManager; +import android.view.Display; +import android.view.WindowManager; + +import javax.inject.Inject; + +/** + * Utility class for working with displays. + */ +public class DisplayHelper { + private final Context mContext; + private final DisplayManager mDisplayManager; + + /** + * Default constructor. + */ + @Inject + public DisplayHelper(Context context, DisplayManager displayManager) { + mContext = context; + mDisplayManager = displayManager; + } + + + /** + * Returns the maximum display bounds for the given window context type. + */ + public Rect getMaxBounds(int displayId, int windowContextType) { + final Display display = mDisplayManager.getDisplay(displayId); + WindowManager windowManager = mContext.createDisplayContext(display) + .createWindowContext(windowContextType, null) + .getSystemService(WindowManager.class); + return windowManager.getMaximumWindowMetrics().getBounds(); + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandlerTest.java index d6dbd730368e2..1a89076741ef3 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandlerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandlerTest.java @@ -31,7 +31,6 @@ import android.animation.ValueAnimator; import android.graphics.Rect; import android.graphics.Region; import android.testing.AndroidTestingRunner; -import android.util.DisplayMetrics; import android.view.GestureDetector; import android.view.GestureDetector.OnGestureListener; import android.view.MotionEvent; @@ -101,20 +100,16 @@ public class BouncerSwipeTouchHandlerTest extends SysuiTestCase { @Mock UiEventLogger mUiEventLogger; - final DisplayMetrics mDisplayMetrics = new DisplayMetrics(); - 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 Rect SCREEN_BOUNDS = new Rect(0, 0, 1024, 100); + @Before public void setup() { - mDisplayMetrics.widthPixels = SCREEN_WIDTH_PX; - mDisplayMetrics.heightPixels = SCREEN_HEIGHT_PX; - MockitoAnnotations.initMocks(this); mTouchHandler = new BouncerSwipeTouchHandler( - mDisplayMetrics, mScrimManager, Optional.of(mCentralSurfaces), mNotificationShadeWindowController, @@ -127,10 +122,10 @@ public class BouncerSwipeTouchHandlerTest extends SysuiTestCase { when(mScrimManager.getCurrentController()).thenReturn(mScrimController); when(mCentralSurfaces.isBouncerShowing()).thenReturn(false); - when(mCentralSurfaces.getDisplayHeight()).thenReturn((float) SCREEN_HEIGHT_PX); when(mValueAnimatorCreator.create(anyFloat(), anyFloat())).thenReturn(mValueAnimator); when(mVelocityTrackerFactory.obtain()).thenReturn(mVelocityTracker); when(mFlingAnimationUtils.getMinVelocityPxPerSecond()).thenReturn(Float.MAX_VALUE); + when(mTouchSession.getBounds()).thenReturn(SCREEN_BOUNDS); } /** @@ -139,7 +134,7 @@ public class BouncerSwipeTouchHandlerTest extends SysuiTestCase { @Test public void testSessionStart() { final Region region = Region.obtain(); - mTouchHandler.getTouchInitiationRegion(region); + mTouchHandler.getTouchInitiationRegion(SCREEN_BOUNDS, region); final Rect bounds = region.getBounds(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/DreamOverlayTouchMonitorTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/DreamOverlayTouchMonitorTest.java index 178b9cc727269..7f6e2ba1c0f98 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/DreamOverlayTouchMonitorTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/DreamOverlayTouchMonitorTest.java @@ -20,6 +20,7 @@ import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.never; @@ -44,6 +45,7 @@ import com.android.systemui.SysuiTestCase; import com.android.systemui.dreams.touch.dagger.InputSessionComponent; import com.android.systemui.shared.system.InputChannelCompat; import com.android.systemui.util.concurrency.FakeExecutor; +import com.android.systemui.util.display.DisplayHelper; import com.android.systemui.util.time.FakeSystemClock; import com.google.common.util.concurrent.ListenableFuture; @@ -79,7 +81,9 @@ public class DreamOverlayTouchMonitorTest extends SysuiTestCase { private final DefaultLifecycleObserver mLifecycleObserver; private final InputChannelCompat.InputEventListener mEventListener; private final GestureDetector.OnGestureListener mGestureListener; + private final DisplayHelper mDisplayHelper; private final FakeExecutor mExecutor = new FakeExecutor(new FakeSystemClock()); + private final Rect mDisplayBounds = Mockito.mock(Rect.class); Environment(Set handlers) { mLifecycle = Mockito.mock(Lifecycle.class); @@ -93,7 +97,11 @@ public class DreamOverlayTouchMonitorTest extends SysuiTestCase { .thenReturn(inputComponent); when(inputComponent.getInputSession()).thenReturn(mInputSession); - mMonitor = new DreamOverlayTouchMonitor(mExecutor, mLifecycle, mInputFactory, handlers); + mDisplayHelper = Mockito.mock(DisplayHelper.class); + when(mDisplayHelper.getMaxBounds(anyInt(), anyInt())) + .thenReturn(mDisplayBounds); + mMonitor = new DreamOverlayTouchMonitor(mExecutor, mLifecycle, mInputFactory, + mDisplayHelper, handlers); mMonitor.init(); final ArgumentCaptor lifecycleObserverCaptor = @@ -117,6 +125,10 @@ public class DreamOverlayTouchMonitorTest extends SysuiTestCase { mGestureListener = gestureListenerCaptor.getValue(); } + public Rect getDisplayBounds() { + return mDisplayBounds; + } + void executeAll() { mExecutor.runAllReady(); } @@ -139,16 +151,38 @@ public class DreamOverlayTouchMonitorTest extends SysuiTestCase { } } + @Test + public void testReportedDisplayBounds() { + final DreamTouchHandler touchHandler = Mockito.mock(DreamTouchHandler.class); + final Environment environment = new Environment(Stream.of(touchHandler) + .collect(Collectors.toCollection(HashSet::new))); + + final MotionEvent initialEvent = Mockito.mock(MotionEvent.class); + when(initialEvent.getX()).thenReturn(0.0f); + when(initialEvent.getY()).thenReturn(0.0f); + environment.publishInputEvent(initialEvent); + + // Verify display bounds passed into TouchHandler#getTouchInitiationRegion + verify(touchHandler).getTouchInitiationRegion(eq(environment.getDisplayBounds()), any()); + final ArgumentCaptor touchSessionArgumentCaptor = + ArgumentCaptor.forClass(DreamTouchHandler.TouchSession.class); + verify(touchHandler).onSessionStart(touchSessionArgumentCaptor.capture()); + + // Verify that display bounds provided from TouchSession#getBounds + assertThat(touchSessionArgumentCaptor.getValue().getBounds()) + .isEqualTo(environment.getDisplayBounds()); + } + @Test public void testEntryTouchZone() { final DreamTouchHandler touchHandler = Mockito.mock(DreamTouchHandler.class); final Rect touchArea = new Rect(4, 4, 8 , 8); doAnswer(invocation -> { - final Region region = (Region) invocation.getArguments()[0]; + final Region region = (Region) invocation.getArguments()[1]; region.set(touchArea); return null; - }).when(touchHandler).getTouchInitiationRegion(any()); + }).when(touchHandler).getTouchInitiationRegion(any(), any()); final Environment environment = new Environment(Stream.of(touchHandler) .collect(Collectors.toCollection(HashSet::new))); @@ -174,10 +208,10 @@ public class DreamOverlayTouchMonitorTest extends SysuiTestCase { final DreamTouchHandler unzonedTouchHandler = Mockito.mock(DreamTouchHandler.class); doAnswer(invocation -> { - final Region region = (Region) invocation.getArguments()[0]; + final Region region = (Region) invocation.getArguments()[1]; region.set(touchArea); return null; - }).when(touchHandler).getTouchInitiationRegion(any()); + }).when(touchHandler).getTouchInitiationRegion(any(), any()); final Environment environment = new Environment(Stream.of(touchHandler, unzonedTouchHandler) .collect(Collectors.toCollection(HashSet::new))); diff --git a/packages/SystemUI/tests/src/com/android/systemui/touch/TouchInsetManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/touch/TouchInsetManagerTest.java index a7072225baa74..667099718788f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/touch/TouchInsetManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/touch/TouchInsetManagerTest.java @@ -28,6 +28,7 @@ import android.graphics.Region; import android.testing.AndroidTestingRunner; import android.view.AttachedSurfaceControl; import android.view.View; +import android.view.ViewGroup; import androidx.test.filters.SmallTest; @@ -49,6 +50,9 @@ public class TouchInsetManagerTest extends SysuiTestCase { @Mock private AttachedSurfaceControl mAttachedSurfaceControl; + @Mock + private ViewGroup mRootView; + private FakeExecutor mFakeExecutor = new FakeExecutor(new FakeSystemClock()); @Before @@ -228,10 +232,11 @@ public class TouchInsetManagerTest extends SysuiTestCase { private View createView(Rect bounds) { final Rect rect = new Rect(bounds); final View view = Mockito.mock(View.class); + when(view.getRootView()).thenReturn(mRootView); doAnswer(invocation -> { ((Rect) invocation.getArgument(0)).set(rect); return null; - }).when(view).getBoundsOnScreen(any()); + }).when(view).getDrawingRect(any()); when(view.isAttachedToWindow()).thenReturn(true); when(view.getRootSurfaceControl()).thenReturn(mAttachedSurfaceControl);