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
This commit is contained in:
Bryce Lee
2023-03-23 00:16:52 +00:00
parent aa8c33a112
commit 52329d28ab
8 changed files with 148 additions and 37 deletions

View File

@@ -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> 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;

View File

@@ -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<TouchSessionImpl> mActiveTouchSessions = new HashSet<>();
private final Collection<DreamTouchHandler> 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<DreamTouchHandler> handlers) {
mHandlers = handlers;
mInputSessionFactory = inputSessionFactory;
mExecutor = executor;
mLifecycle = lifecycle;
mDisplayHelper = displayHelper;
}
/**

View File

@@ -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) {
}
/**

View File

@@ -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);

View File

@@ -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();
}
}

View File

@@ -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();

View File

@@ -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<DreamTouchHandler> 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<LifecycleObserver> 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<DreamTouchHandler.TouchSession> 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)));

View File

@@ -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);