From 52a3bb48ca3d684b188f4e6eb9eb1b626649cdd6 Mon Sep 17 00:00:00 2001 From: Bill Lin Date: Wed, 17 Mar 2021 20:11:17 +0800 Subject: [PATCH] Integrate DisplayLayout for One handed mode 1) Handle rotation 2) Initialize DisplayLayout in dagger and update when onDisplayAdded() & onDisplayRemoved() 3) Refact OneHandedTouchHandler 4) Refact OneHandedBackgroundPanelOrganizer 5) Refact OneHandedDisplayAreaOrganizer Test: atest WMShellUnitTests Bug:182899148 Bug:182633327 Bug:183172404 Bug:183489178 Bug:183559944 Bug:183065937 Bug:183005910 Bug:183063280 Bug:183162084 Bug:181423645 Bug:177497107 Change-Id: Ie7a4fa97df5f6a3963a55bd507d36e026e971bab --- .../OneHandedBackgroundPanelOrganizer.java | 36 +++-- .../shell/onehanded/OneHandedController.java | 112 +++++++++----- .../OneHandedDisplayAreaOrganizer.java | 86 +++++------ .../onehanded/OneHandedGestureHandler.java | 120 +++++++-------- ...OneHandedBackgroundPanelOrganizerTest.java | 26 ++-- .../onehanded/OneHandedControllerTest.java | 80 +++++++++- .../OneHandedDisplayAreaOrganizerTest.java | 145 ++++++++++++++---- .../OneHandedGestureHandlerTest.java | 57 ++++--- .../OneHandedTutorialHandlerTest.java | 1 - .../systemui/wmshell/WMShellBaseModule.java | 13 +- 10 files changed, 445 insertions(+), 231 deletions(-) diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedBackgroundPanelOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedBackgroundPanelOrganizer.java index d90cc47692866..c7dbe880859d1 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedBackgroundPanelOrganizer.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedBackgroundPanelOrganizer.java @@ -23,7 +23,6 @@ import android.graphics.Rect; import android.util.Log; import android.view.SurfaceControl; import android.view.SurfaceSession; -import android.view.WindowManager; import android.window.DisplayAreaAppearedInfo; import android.window.DisplayAreaInfo; import android.window.DisplayAreaOrganizer; @@ -34,8 +33,9 @@ import androidx.annotation.VisibleForTesting; import com.android.internal.annotations.GuardedBy; import com.android.wm.shell.R; -import com.android.wm.shell.common.DisplayController; +import com.android.wm.shell.common.DisplayLayout; +import java.io.PrintWriter; import java.util.List; import java.util.concurrent.Executor; @@ -52,12 +52,15 @@ public class OneHandedBackgroundPanelOrganizer extends DisplayAreaOrganizer private final SurfaceSession mSurfaceSession = new SurfaceSession(); private final float[] mColor; private final float mAlpha; - private final Rect mRect; private final Executor mMainExecutor; - private final Rect mDisplaySize; private final OneHandedSurfaceTransactionHelper.SurfaceControlTransactionFactory mSurfaceControlTransactionFactory; + /** + * The background to distinguish the boundary of translated windows and empty region when + * one handed mode triggered. + */ + private Rect mBkgBounds; @VisibleForTesting @GuardedBy("mLock") boolean mIsShowing; @@ -82,15 +85,19 @@ public class OneHandedBackgroundPanelOrganizer extends DisplayAreaOrganizer mMainExecutor.execute(() -> removeBackgroundPanelLayer()); } - public OneHandedBackgroundPanelOrganizer(Context context, WindowManager windowManager, - DisplayController displayController, Executor executor) { + public OneHandedBackgroundPanelOrganizer(Context context, DisplayLayout displayLayout, + Executor executor) { super(executor); - mDisplaySize = windowManager.getCurrentWindowMetrics().getBounds(); final Resources res = context.getResources(); final float defaultRGB = res.getFloat(R.dimen.config_one_handed_background_rgb); mColor = new float[]{defaultRGB, defaultRGB, defaultRGB}; mAlpha = res.getFloat(R.dimen.config_one_handed_background_alpha); - mRect = new Rect(0, 0, mDisplaySize.width(), mDisplaySize.height()); + // Ensure the mBkgBounds is portrait, due to OHM only support on portrait + if (displayLayout.height() > displayLayout.width()) { + mBkgBounds = new Rect(0, 0, displayLayout.width(), displayLayout.height()); + } else { + mBkgBounds = new Rect(0, 0, displayLayout.height(), displayLayout.width()); + } mMainExecutor = executor; mSurfaceControlTransactionFactory = SurfaceControl.Transaction::new; } @@ -144,6 +151,7 @@ public class OneHandedBackgroundPanelOrganizer extends DisplayAreaOrganizer if (mBackgroundSurface == null) { mBackgroundSurface = new SurfaceControl.Builder(mSurfaceSession) .setParent(mParentLeash) + .setBufferSize(mBkgBounds.width(), mBkgBounds.height()) .setColorLayer() .setFormat(PixelFormat.RGBA_8888) .setOpaque(false) @@ -188,11 +196,19 @@ public class OneHandedBackgroundPanelOrganizer extends DisplayAreaOrganizer SurfaceControl.Transaction transaction = mSurfaceControlTransactionFactory.getTransaction(); - transaction.remove(mBackgroundSurface); - transaction.apply(); + transaction.remove(mBackgroundSurface).apply(); transaction.close(); mBackgroundSurface = null; mIsShowing = false; } } + + void dump(@NonNull PrintWriter pw) { + final String innerPrefix = " "; + pw.println(TAG + "states: "); + pw.print(innerPrefix + "mIsShowing="); + pw.println(mIsShowing); + pw.print(innerPrefix + "mBkgBounds="); + pw.println(mBkgBounds); + } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java index 25968ebd817d3..7965a80deead2 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java @@ -17,10 +17,10 @@ package com.android.wm.shell.onehanded; import static android.os.UserHandle.USER_CURRENT; +import static android.view.Display.DEFAULT_DISPLAY; import static com.android.wm.shell.common.ExecutorUtils.executeRemoteCallWithTaskPermission; -import android.Manifest; import android.annotation.BinderThread; import android.content.ComponentName; import android.content.Context; @@ -28,13 +28,13 @@ import android.content.om.IOverlayManager; import android.content.om.OverlayInfo; import android.content.res.Configuration; import android.database.ContentObserver; -import android.graphics.Rect; import android.os.Handler; import android.os.RemoteException; import android.os.ServiceManager; import android.os.SystemProperties; import android.provider.Settings; import android.util.Slog; +import android.view.Surface; import android.view.ViewConfiguration; import android.view.WindowManager; import android.view.accessibility.AccessibilityManager; @@ -47,7 +47,7 @@ import com.android.internal.logging.UiEventLogger; import com.android.wm.shell.R; import com.android.wm.shell.common.DisplayChangeController; import com.android.wm.shell.common.DisplayController; -import com.android.wm.shell.common.ExecutorUtils; +import com.android.wm.shell.common.DisplayLayout; import com.android.wm.shell.common.RemoteCallable; import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.common.TaskStackListenerCallback; @@ -76,9 +76,10 @@ public class OneHandedController implements RemoteCallable private boolean mLockedDisabled; private float mOffSetFraction; - private final Context mContext; + private Context mContext; + + private final AccessibilityManager mAccessibilityManager; private final DisplayController mDisplayController; - private final OneHandedGestureHandler mGestureHandler; private final OneHandedSettingsUtil mOneHandedSettingsUtil; private final OneHandedTimeoutHandler mTimeoutHandler; private final OneHandedTouchHandler mTouchHandler; @@ -89,10 +90,9 @@ public class OneHandedController implements RemoteCallable private final ShellExecutor mMainExecutor; private final Handler mMainHandler; private final OneHandedImpl mImpl = new OneHandedImpl(); - private final WindowManager mWindowManager; private OneHandedDisplayAreaOrganizer mDisplayAreaOrganizer; - private final AccessibilityManager mAccessibilityManager; + private OneHandedGestureHandler mGestureHandler; private OneHandedBackgroundPanelOrganizer mBackgroundPanelOrganizer; /** @@ -100,8 +100,29 @@ public class OneHandedController implements RemoteCallable */ private final DisplayChangeController.OnDisplayChangingListener mRotationController = (display, fromRotation, toRotation, wct) -> { - if (mDisplayAreaOrganizer != null) { - mDisplayAreaOrganizer.onRotateDisplay(fromRotation, toRotation, wct); + if (!isInitialized()) { + return; + } + mDisplayAreaOrganizer.onRotateDisplay(mContext, toRotation, wct); + mGestureHandler.onRotateDisplay(mDisplayAreaOrganizer.getDisplayLayout()); + }; + + private final DisplayController.OnDisplaysChangedListener mDisplaysChangedListener = + new DisplayController.OnDisplaysChangedListener() { + @Override + public void onDisplayConfigurationChanged(int displayId, Configuration newConfig) { + if (displayId != DEFAULT_DISPLAY || !isInitialized()) { + return; + } + updateDisplayLayout(displayId); + } + + @Override + public void onDisplayAdded(int displayId) { + if (displayId != DEFAULT_DISPLAY || !isInitialized()) { + return; + } + updateDisplayLayout(displayId); } }; @@ -115,8 +136,7 @@ public class OneHandedController implements RemoteCallable new AccessibilityManager.AccessibilityStateChangeListener() { @Override public void onAccessibilityStateChanged(boolean enabled) { - if (mOneHandedSettingsUtil == null) { - Slog.w(TAG, "mOneHandedSettingsUtil may not instantiate yet"); + if (!isInitialized()) { return; } if (enabled) { @@ -147,6 +167,14 @@ public class OneHandedController implements RemoteCallable } }; + private boolean isInitialized() { + if (mDisplayAreaOrganizer == null || mDisplayController == null + || mGestureHandler == null || mOneHandedSettingsUtil == null) { + Slog.w(TAG, "Components may not initialized yet!"); + return false; + } + return true; + } /** * Creates {@link OneHandedController}, returns {@code null} if the feature is not supported. @@ -154,8 +182,8 @@ public class OneHandedController implements RemoteCallable @Nullable public static OneHandedController create( Context context, WindowManager windowManager, DisplayController displayController, - TaskStackListenerImpl taskStackListener, UiEventLogger uiEventLogger, - ShellExecutor mainExecutor, Handler mainHandler) { + DisplayLayout displayLayout, TaskStackListenerImpl taskStackListener, + UiEventLogger uiEventLogger, ShellExecutor mainExecutor, Handler mainHandler) { if (!SystemProperties.getBoolean(SUPPORT_ONE_HANDED_MODE, false)) { Slog.w(TAG, "Device doesn't support OneHanded feature"); return null; @@ -169,19 +197,17 @@ public class OneHandedController implements RemoteCallable OneHandedTouchHandler touchHandler = new OneHandedTouchHandler(timeoutHandler, mainExecutor); OneHandedGestureHandler gestureHandler = new OneHandedGestureHandler( - context, windowManager, displayController, ViewConfiguration.get(context), - mainExecutor); + context, displayLayout, ViewConfiguration.get(context), mainExecutor); OneHandedBackgroundPanelOrganizer oneHandedBackgroundPanelOrganizer = - new OneHandedBackgroundPanelOrganizer(context, windowManager, displayController, - mainExecutor); + new OneHandedBackgroundPanelOrganizer(context, displayLayout, mainExecutor); OneHandedDisplayAreaOrganizer organizer = new OneHandedDisplayAreaOrganizer( - context, windowManager, animationController, tutorialHandler, + context, displayLayout, animationController, tutorialHandler, oneHandedBackgroundPanelOrganizer, mainExecutor); OneHandedSettingsUtil settingsUtil = new OneHandedSettingsUtil(); OneHandedUiEventLogger oneHandedUiEventsLogger = new OneHandedUiEventLogger(uiEventLogger); IOverlayManager overlayManager = IOverlayManager.Stub.asInterface( ServiceManager.getService(Context.OVERLAY_SERVICE)); - return new OneHandedController(context, windowManager, displayController, + return new OneHandedController(context, displayController, oneHandedBackgroundPanelOrganizer, organizer, touchHandler, tutorialHandler, gestureHandler, settingsUtil, timeoutHandler, oneHandedUiEventsLogger, overlayManager, taskStackListener, mainExecutor, mainHandler); @@ -189,7 +215,6 @@ public class OneHandedController implements RemoteCallable @VisibleForTesting OneHandedController(Context context, - WindowManager windowManager, DisplayController displayController, OneHandedBackgroundPanelOrganizer backgroundPanelOrganizer, OneHandedDisplayAreaOrganizer displayAreaOrganizer, @@ -205,7 +230,6 @@ public class OneHandedController implements RemoteCallable Handler mainHandler) { mContext = context; mOneHandedSettingsUtil = settingsUtil; - mWindowManager = windowManager; mBackgroundPanelOrganizer = backgroundPanelOrganizer; mDisplayAreaOrganizer = displayAreaOrganizer; mDisplayController = displayController; @@ -218,6 +242,7 @@ public class OneHandedController implements RemoteCallable mOneHandedUiEventLogger = uiEventsLogger; mTaskStackListener = taskStackListener; + mDisplayController.addDisplayWindowListener(mDisplaysChangedListener); final float offsetPercentageConfig = context.getResources().getFraction( R.fraction.config_one_handed_offset, 1, 1); final int sysPropPercentageConfig = SystemProperties.getInt( @@ -297,8 +322,14 @@ public class OneHandedController implements RemoteCallable Slog.d(TAG, "Temporary lock disabled"); return; } + final int currentRotation = mDisplayAreaOrganizer.getDisplayLayout().rotation(); + if (currentRotation != Surface.ROTATION_0 && currentRotation != Surface.ROTATION_180) { + Slog.w(TAG, "One handed mode only support portrait mode"); + return; + } if (!mDisplayAreaOrganizer.isInOneHanded()) { - final int yOffSet = Math.round(getDisplaySize().height() * mOffSetFraction); + final int yOffSet = Math.round( + mDisplayAreaOrganizer.getDisplayLayout().height() * mOffSetFraction); mDisplayAreaOrganizer.scheduleOffset(0, yOffSet); mTimeoutHandler.resetTimer(); @@ -371,6 +402,12 @@ public class OneHandedController implements RemoteCallable .getSettingsSwipeToNotificationEnabled(mContext.getContentResolver())); } + private void updateDisplayLayout(int displayId) { + mDisplayAreaOrganizer.setDisplayLayout( + mDisplayController.getDisplayLayout(displayId)); + mGestureHandler.onDisplayChanged(mDisplayAreaOrganizer.getDisplayLayout()); + } + private ContentObserver getObserver(Runnable onChangeRunnable) { return new ContentObserver(mMainHandler) { @Override @@ -454,24 +491,6 @@ public class OneHandedController implements RemoteCallable OneHandedUiEventLogger.EVENT_ONE_HANDED_TRIGGER_TIMEOUT_OUT)); } - /** - * Query the current display real size from {@link WindowManager} - * - * @return {@link WindowManager#getCurrentWindowMetrics()#getBounds()} - */ - private Rect getDisplaySize() { - if (mWindowManager == null) { - Slog.e(TAG, "WindowManager instance is null! Can not get display size!"); - return new Rect(); - } - final Rect displaySize = mWindowManager.getCurrentWindowMetrics().getBounds(); - if (displaySize.width() == 0 || displaySize.height() == 0) { - Slog.e(TAG, "Display size error! width = " + displaySize.width() - + ", height = " + displaySize.height()); - } - return displaySize; - } - @VisibleForTesting boolean isLockedDisabled() { return mLockedDisabled; @@ -483,7 +502,7 @@ public class OneHandedController implements RemoteCallable } mTouchHandler.onOneHandedEnabled(mIsOneHandedEnabled); - mGestureHandler.onOneHandedEnabled(mIsOneHandedEnabled || mIsSwipeToNotificationEnabled); + mGestureHandler.onGestureEnabled(mIsOneHandedEnabled || mIsSwipeToNotificationEnabled); if (!mIsOneHandedEnabled) { mDisplayAreaOrganizer.unregisterOrganizer(); @@ -532,10 +551,15 @@ public class OneHandedController implements RemoteCallable @VisibleForTesting void setLockedDisabled(boolean locked, boolean enabled) { - if (enabled == mIsOneHandedEnabled) { + final boolean isFeatureEnabled = mIsOneHandedEnabled || mIsSwipeToNotificationEnabled; + + if (enabled == isFeatureEnabled) { return; } mLockedDisabled = locked && !enabled; + + // Disabled gesture when keyguard ON + mGestureHandler.onGestureEnabled(!mLockedDisabled && isFeatureEnabled); } private void onConfigChanged(Configuration newConfig) { @@ -556,6 +580,10 @@ public class OneHandedController implements RemoteCallable pw.print(innerPrefix + "mLockedDisabled="); pw.println(mLockedDisabled); + if (mBackgroundPanelOrganizer != null) { + mBackgroundPanelOrganizer.dump(pw); + } + if (mDisplayAreaOrganizer != null) { mDisplayAreaOrganizer.dump(pw); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizer.java index 5eec23106f475..682c9a3f0d62a 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizer.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizer.java @@ -23,9 +23,7 @@ import android.content.Context; import android.graphics.Rect; import android.os.SystemProperties; import android.util.ArrayMap; -import android.util.Slog; import android.view.SurfaceControl; -import android.view.WindowManager; import android.window.DisplayAreaAppearedInfo; import android.window.DisplayAreaInfo; import android.window.DisplayAreaOrganizer; @@ -37,6 +35,7 @@ import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; import com.android.wm.shell.R; +import com.android.wm.shell.common.DisplayLayout; import com.android.wm.shell.common.ShellExecutor; import java.io.PrintWriter; @@ -58,7 +57,8 @@ public class OneHandedDisplayAreaOrganizer extends DisplayAreaOrganizer { private static final String ONE_HANDED_MODE_TRANSLATE_ANIMATION_DURATION = "persist.debug.one_handed_translate_animation_duration"; - private final WindowManager mWindowManager; + private DisplayLayout mDisplayLayout = new DisplayLayout(); + private final Rect mLastVisualDisplayBounds = new Rect(); private final Rect mDefaultDisplayBounds = new Rect(); @@ -108,15 +108,15 @@ public class OneHandedDisplayAreaOrganizer extends DisplayAreaOrganizer { * Constructor of OneHandedDisplayAreaOrganizer */ public OneHandedDisplayAreaOrganizer(Context context, - WindowManager windowManager, + DisplayLayout displayLayout, OneHandedAnimationController animationController, OneHandedTutorialHandler tutorialHandler, OneHandedBackgroundPanelOrganizer oneHandedBackgroundGradientOrganizer, ShellExecutor mainExecutor) { super(mainExecutor); - mWindowManager = windowManager; + mDisplayLayout.set(displayLayout); + updateDisplayBounds(); mAnimationController = animationController; - mLastVisualDisplayBounds.set(getDisplayBounds()); final int animationDurationConfig = context.getResources().getInteger( R.integer.config_one_handed_translate_animation_duration); mEnterExitAnimationDurationMs = @@ -146,7 +146,7 @@ public class OneHandedDisplayAreaOrganizer extends DisplayAreaOrganizer { final DisplayAreaAppearedInfo info = displayAreaInfos.get(i); onDisplayAreaAppeared(info.getDisplayAreaInfo(), info.getLeash()); } - mDefaultDisplayBounds.set(getDisplayBounds()); + updateDisplayBounds(); return displayAreaInfos; } @@ -157,29 +157,21 @@ public class OneHandedDisplayAreaOrganizer extends DisplayAreaOrganizer { } /** - * Handler for display rotation changes by below policy which - * handles 90 degree display rotation changes {@link Surface.Rotation}. + * Handler for display rotation changes by {@link DisplayLayout} * - * @param fromRotation starting rotation of the display. - * @param toRotation target rotation of the display (after rotating). - * @param wct A task transaction {@link WindowContainerTransaction} from - * {@link DisplayChangeController} to populate. + * @param context Any context + * @param toRotation target rotation of the display (after rotating). + * @param wct A task transaction {@link WindowContainerTransaction} from + * {@link DisplayChangeController} to populate. */ - public void onRotateDisplay(int fromRotation, int toRotation, WindowContainerTransaction wct) { - // Stop one handed without animation and reset cropped size immediately - final Rect newBounds = new Rect(getDisplayBounds()); - // This diff rule will only filter the cases portrait <-> landscape - final boolean isOrientationDiff = Math.abs(fromRotation - toRotation) % 2 == 1; - - if (isOrientationDiff) { - // getDisplayBounds() will return window metrics bounds which dose not update to - // corresponding display orientation yet, we have to manual rotate bounds - newBounds.set(0, 0, newBounds.bottom, newBounds.right); - resetWindowsOffset(wct); - mDefaultDisplayBounds.set(newBounds); - mLastVisualDisplayBounds.set(newBounds); - finishOffset(0, TRANSITION_DIRECTION_EXIT); + public void onRotateDisplay(Context context, int toRotation, WindowContainerTransaction wct) { + if (mDisplayLayout.rotation() == toRotation) { + return; } + mDisplayLayout.rotateTo(context.getResources(), toRotation); + resetWindowsOffset(wct); + updateDisplayBounds(); + finishOffset(0, TRANSITION_DIRECTION_EXIT); } /** @@ -191,9 +183,7 @@ public class OneHandedDisplayAreaOrganizer extends DisplayAreaOrganizer { mDefaultDisplayBounds.top + yOffset, mDefaultDisplayBounds.right, mDefaultDisplayBounds.bottom + yOffset); - final Rect fromBounds = getLastVisualDisplayBounds() != null - ? getLastVisualDisplayBounds() - : mDefaultDisplayBounds; + final Rect fromBounds = getLastVisualDisplayBounds(); final int direction = yOffset > 0 ? TRANSITION_DIRECTION_TRIGGER : TRANSITION_DIRECTION_EXIT; @@ -219,7 +209,8 @@ public class OneHandedDisplayAreaOrganizer extends DisplayAreaOrganizer { applyTransaction(wct); } - private void resetWindowsOffset(WindowContainerTransaction wct) { + @VisibleForTesting + void resetWindowsOffset(WindowContainerTransaction wct) { final SurfaceControl.Transaction tx = mSurfaceControlTransactionFactory.getTransaction(); mDisplayAreaTokenMap.forEach( @@ -292,19 +283,19 @@ public class OneHandedDisplayAreaOrganizer extends DisplayAreaOrganizer { return mLastVisualDisplayBounds; } - @Nullable @VisibleForTesting - Rect getDisplayBounds() { - if (mWindowManager == null) { - Slog.e(TAG, "WindowManager instance is null! Can not get display size!"); - return new Rect(); - } - final Rect displayBounds = mWindowManager.getCurrentWindowMetrics().getBounds(); - if (displayBounds.width() == 0 || displayBounds.height() == 0) { - Slog.e(TAG, "Display size error! width = " + displayBounds.width() - + ", height = " + displayBounds.height()); - } - return displayBounds; + @Nullable + Rect getLastDisplayBounds() { + return mLastVisualDisplayBounds; + } + + public DisplayLayout getDisplayLayout() { + return mDisplayLayout; + } + + @VisibleForTesting + void setDisplayLayout(@NonNull DisplayLayout displayLayout) { + mDisplayLayout.set(displayLayout); } @VisibleForTesting @@ -312,6 +303,11 @@ public class OneHandedDisplayAreaOrganizer extends DisplayAreaOrganizer { return mDisplayAreaTokenMap; } + void updateDisplayBounds() { + mDefaultDisplayBounds.set(0, 0, mDisplayLayout.width(), mDisplayLayout.height()); + mLastVisualDisplayBounds.set(mDefaultDisplayBounds); + } + /** * Register transition callback */ @@ -324,13 +320,13 @@ public class OneHandedDisplayAreaOrganizer extends DisplayAreaOrganizer { pw.println(TAG + "states: "); pw.print(innerPrefix + "mIsInOneHanded="); pw.println(mIsInOneHanded); + pw.print(innerPrefix + "mDisplayLayout.rotation()="); + pw.println(mDisplayLayout.rotation()); pw.print(innerPrefix + "mDisplayAreaTokenMap="); pw.println(mDisplayAreaTokenMap); pw.print(innerPrefix + "mDefaultDisplayBounds="); pw.println(mDefaultDisplayBounds); pw.print(innerPrefix + "mLastVisualDisplayBounds="); pw.println(mLastVisualDisplayBounds); - pw.print(innerPrefix + "getDisplayBounds()="); - pw.println(getDisplayBounds()); } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedGestureHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedGestureHandler.java index 778876c76afed..495362a3eef77 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedGestureHandler.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedGestureHandler.java @@ -24,7 +24,6 @@ import android.graphics.PointF; import android.graphics.Rect; import android.hardware.input.InputManager; import android.os.Looper; -import android.util.Log; import android.view.Display; import android.view.InputChannel; import android.view.InputEvent; @@ -33,29 +32,23 @@ import android.view.InputMonitor; import android.view.MotionEvent; import android.view.Surface; import android.view.ViewConfiguration; -import android.view.WindowManager; -import android.window.WindowContainerTransaction; import androidx.annotation.NonNull; import androidx.annotation.VisibleForTesting; import com.android.wm.shell.R; -import com.android.wm.shell.common.DisplayChangeController; -import com.android.wm.shell.common.DisplayController; import com.android.wm.shell.common.DisplayLayout; import com.android.wm.shell.common.ShellExecutor; import java.io.PrintWriter; /** - * The class manage swipe up and down gesture for 3-Button mode navigation, - * others(e.g, 2-button, full gesture mode) are handled by Launcher quick steps. - * TODO(b/160934654) Migrate to Launcher quick steps + * The class manage swipe up and down gesture for 3-Button mode navigation, others(e.g, 2-button, + * full gesture mode) are handled by Launcher quick steps. TODO(b/160934654) Migrate to Launcher + * quick steps */ -public class OneHandedGestureHandler implements OneHandedTransitionCallback, - DisplayChangeController.OnDisplayChangingListener { +public class OneHandedGestureHandler implements OneHandedTransitionCallback { private static final String TAG = "OneHandedGestureHandler"; - private static final boolean DEBUG_GESTURE = false; private static final int ANGLE_MAX = 150; private static final int ANGLE_MIN = 30; @@ -64,14 +57,13 @@ public class OneHandedGestureHandler implements OneHandedTransitionCallback, private final PointF mDownPos = new PointF(); private final PointF mLastPos = new PointF(); private final PointF mStartDragPos = new PointF(); - private final WindowManager mWindowManager; private boolean mPassedSlop; private boolean mAllowGesture; private boolean mIsEnabled; private int mNavGestureHeight; private boolean mIsThreeButtonModeEnabled; - private int mRotation = Surface.ROTATION_0; + private int mRotation; @VisibleForTesting InputMonitor mInputMonitor; @@ -85,37 +77,35 @@ public class OneHandedGestureHandler implements OneHandedTransitionCallback, private boolean mIsStopGesture; /** - * Constructor of OneHandedGestureHandler, we only handle the gesture of - * {@link Display#DEFAULT_DISPLAY} + * Constructor of OneHandedGestureHandler, we only handle the gesture of {@link + * Display#DEFAULT_DISPLAY} * - * @param context {@link Context} - * @param displayController {@link DisplayController} + * @param context Any context + * @param displayLayout Current {@link DisplayLayout} from controller + * @param viewConfig {@link ViewConfiguration} to obtain touch slop + * @param mainExecutor The wm-shell main executor */ - public OneHandedGestureHandler(Context context, WindowManager windowManager, - DisplayController displayController, ViewConfiguration viewConfig, + public OneHandedGestureHandler(Context context, + DisplayLayout displayLayout, + ViewConfiguration viewConfig, ShellExecutor mainExecutor) { - mWindowManager = windowManager; mMainExecutor = mainExecutor; - displayController.addDisplayChangingController(this); - mNavGestureHeight = getNavBarSize(context, - displayController.getDisplayLayout(DEFAULT_DISPLAY)); mDragDistThreshold = context.getResources().getDimensionPixelSize( R.dimen.gestures_onehanded_drag_threshold); + final float slop = viewConfig.getScaledTouchSlop(); mSquaredSlop = slop * slop; - + onDisplayChanged(displayLayout); updateIsEnabled(); } /** - * Notified by {@link OneHandedController}, when user update settings of Enabled or Disabled + * Notifies by {@link OneHandedController}, when swipe down gesture is enabled on 3 button + * navigation bar mode. * - * @param isEnabled is one handed settings enabled or not + * @param isEnabled Either one handed mode or swipe for notification function enabled or not */ - public void onOneHandedEnabled(boolean isEnabled) { - if (DEBUG_GESTURE) { - Log.d(TAG, "onOneHandedEnabled, isEnabled = " + isEnabled); - } + public void onGestureEnabled(boolean isEnabled) { mIsEnabled = isEnabled; updateIsEnabled(); } @@ -126,25 +116,31 @@ public class OneHandedGestureHandler implements OneHandedTransitionCallback, } /** - * Register {@link OneHandedGestureEventCallback} to receive onStart(), onStop() callback + * Registers {@link OneHandedGestureEventCallback} to receive onStart(), onStop() callback */ public void setGestureEventListener(OneHandedGestureEventCallback callback) { mGestureEventCallback = callback; } + /** + * Called when onDisplayAdded() or onDisplayRemoved() callback + * @param displayLayout The latest {@link DisplayLayout} representing current displayId + */ + public void onDisplayChanged(DisplayLayout displayLayout) { + mNavGestureHeight = getNavBarSize(displayLayout); + mGestureRegion.set(0, displayLayout.height() - mNavGestureHeight, displayLayout.width(), + displayLayout.height()); + mRotation = displayLayout.rotation(); + } + private void onMotionEvent(MotionEvent ev) { int action = ev.getActionMasked(); if (action == MotionEvent.ACTION_DOWN) { - mAllowGesture = isWithinTouchRegion(ev.getX(), ev.getY()) - && mRotation == Surface.ROTATION_0; + mAllowGesture = isWithinTouchRegion(ev.getX(), ev.getY()) && isGestureAvailable(); if (mAllowGesture) { mDownPos.set(ev.getX(), ev.getY()); mLastPos.set(mDownPos); } - if (DEBUG_GESTURE) { - Log.d(TAG, "ACTION_DOWN, mDownPos=" + mDownPos + ", mAllowGesture=" - + mAllowGesture); - } } else if (mAllowGesture) { switch (action) { case MotionEvent.ACTION_MOVE: @@ -204,34 +200,17 @@ public class OneHandedGestureHandler implements OneHandedTransitionCallback, } private boolean isWithinTouchRegion(float x, float y) { - if (DEBUG_GESTURE) { - Log.d(TAG, "isWithinTouchRegion(), mGestureRegion=" + mGestureRegion + ", downX=" + x - + ", downY=" + y); - } return mGestureRegion.contains(Math.round(x), Math.round(y)); } - private int getNavBarSize(Context context, @Nullable DisplayLayout displayLayout) { - if (displayLayout != null) { - return displayLayout.navBarFrameHeight(); - } else { - return isRotated() - ? context.getResources().getDimensionPixelSize( - com.android.internal.R.dimen.navigation_bar_height_landscape) - : context.getResources().getDimensionPixelSize( - com.android.internal.R.dimen.navigation_bar_height); - } + private int getNavBarSize(@NonNull DisplayLayout displayLayout) { + return isGestureAvailable() ? displayLayout.navBarFrameHeight() : 0 /* In landscape */; } private void updateIsEnabled() { disposeInputChannel(); - // Either OHM or swipe notification shade can activate in portrait mode only - if (mIsEnabled && mIsThreeButtonModeEnabled && !isRotated()) { - final Rect displaySize = mWindowManager.getCurrentWindowMetrics().getBounds(); - // Register input event receiver to monitor the touch region of NavBar gesture height - mGestureRegion.set(0, displaySize.height() - mNavGestureHeight, displaySize.width(), - displaySize.height()); + if (mIsEnabled && mIsThreeButtonModeEnabled && isGestureAvailable()) { mInputMonitor = InputManager.getInstance().monitorGestureInput( "onehanded-gesture-offset", DEFAULT_DISPLAY); try { @@ -251,10 +230,16 @@ public class OneHandedGestureHandler implements OneHandedTransitionCallback, } } - @Override - public void onRotateDisplay(int displayId, int fromRotation, int toRotation, - WindowContainerTransaction t) { - mRotation = toRotation; + /** + * Handler for display rotation changes by {@link DisplayLayout} + * + * @param displayLayout The rotated displayLayout + */ + public void onRotateDisplay(DisplayLayout displayLayout) { + mRotation = displayLayout.rotation(); + mNavGestureHeight = getNavBarSize(displayLayout); + mGestureRegion.set(0, displayLayout.height() - mNavGestureHeight, displayLayout.width(), + displayLayout.height()); updateIsEnabled(); } @@ -270,8 +255,9 @@ public class OneHandedGestureHandler implements OneHandedTransitionCallback, } } - private boolean isRotated() { - return mRotation == Surface.ROTATION_90 || mRotation == Surface.ROTATION_270; + private boolean isGestureAvailable() { + // Either OHM or swipe notification shade can activate in portrait mode only + return mRotation == Surface.ROTATION_0 || mRotation == Surface.ROTATION_180; } private boolean isValidStartAngle(float deltaX, float deltaY) { @@ -291,14 +277,18 @@ public class OneHandedGestureHandler implements OneHandedTransitionCallback, void dump(@NonNull PrintWriter pw) { final String innerPrefix = " "; pw.println(TAG + "States: "); + pw.print(innerPrefix + "mAllowGesture="); + pw.println(mAllowGesture); pw.print(innerPrefix + "mIsEnabled="); pw.println(mIsEnabled); + pw.print(innerPrefix + "mGestureRegion="); + pw.println(mGestureRegion); pw.print(innerPrefix + "mNavGestureHeight="); pw.println(mNavGestureHeight); pw.print(innerPrefix + "mIsThreeButtonModeEnabled="); pw.println(mIsThreeButtonModeEnabled); - pw.print(innerPrefix + "isLandscape="); - pw.println(isRotated()); + pw.print(innerPrefix + "mRotation="); + pw.println(mRotation); } /** diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedBackgroundPanelOrganizerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedBackgroundPanelOrganizerTest.java index d6bcf0375f32b..3f47c040dd8d4 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedBackgroundPanelOrganizerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedBackgroundPanelOrganizerTest.java @@ -22,6 +22,7 @@ import static android.window.DisplayAreaOrganizer.FEATURE_ONE_HANDED_BACKGROUND_ import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; import android.testing.AndroidTestingRunner; @@ -35,6 +36,7 @@ import android.window.WindowContainerToken; import androidx.test.filters.SmallTest; import com.android.wm.shell.common.DisplayController; +import com.android.wm.shell.common.DisplayLayout; import org.junit.Before; import org.junit.Test; @@ -48,7 +50,8 @@ import org.mockito.MockitoAnnotations; public class OneHandedBackgroundPanelOrganizerTest extends OneHandedTestCase { private DisplayAreaInfo mDisplayAreaInfo; private Display mDisplay; - private OneHandedBackgroundPanelOrganizer mBackgroundPanelOrganizer; + private DisplayLayout mDisplayLayout; + private OneHandedBackgroundPanelOrganizer mSpiedBackgroundPanelOrganizer; private WindowContainerToken mToken; private SurfaceControl mLeash; private TestableLooper mTestableLooper; @@ -65,37 +68,38 @@ public class OneHandedBackgroundPanelOrganizerTest extends OneHandedTestCase { mToken = new WindowContainerToken(mMockRealToken); mLeash = new SurfaceControl(); mDisplay = mContext.getDisplay(); + mDisplayLayout = new DisplayLayout(mContext, mDisplay); when(mMockDisplayController.getDisplay(anyInt())).thenReturn(mDisplay); mDisplayAreaInfo = new DisplayAreaInfo(mToken, DEFAULT_DISPLAY, FEATURE_ONE_HANDED_BACKGROUND_PANEL); - mBackgroundPanelOrganizer = new OneHandedBackgroundPanelOrganizer(mContext, mWindowManager, - mMockDisplayController, Runnable::run); + mSpiedBackgroundPanelOrganizer = spy( + new OneHandedBackgroundPanelOrganizer(mContext, mDisplayLayout, Runnable::run)); } @Test public void testOnDisplayAreaAppeared() { - mBackgroundPanelOrganizer.onDisplayAreaAppeared(mDisplayAreaInfo, mLeash); + mSpiedBackgroundPanelOrganizer.onDisplayAreaAppeared(mDisplayAreaInfo, mLeash); mTestableLooper.processAllMessages(); - assertThat(mBackgroundPanelOrganizer.getBackgroundSurface()).isNotNull(); + assertThat(mSpiedBackgroundPanelOrganizer.getBackgroundSurface()).isNotNull(); } @Test public void testShowBackgroundLayer() { - mBackgroundPanelOrganizer.onDisplayAreaAppeared(mDisplayAreaInfo, mLeash); - mBackgroundPanelOrganizer.showBackgroundPanelLayer(); + mSpiedBackgroundPanelOrganizer.onDisplayAreaAppeared(mDisplayAreaInfo, mLeash); + mSpiedBackgroundPanelOrganizer.showBackgroundPanelLayer(); mTestableLooper.processAllMessages(); - assertThat(mBackgroundPanelOrganizer.mIsShowing).isTrue(); + assertThat(mSpiedBackgroundPanelOrganizer.mIsShowing).isTrue(); } @Test public void testRemoveBackgroundLayer() { - mBackgroundPanelOrganizer.onDisplayAreaAppeared(mDisplayAreaInfo, mLeash); - mBackgroundPanelOrganizer.removeBackgroundPanelLayer(); + mSpiedBackgroundPanelOrganizer.onDisplayAreaAppeared(mDisplayAreaInfo, mLeash); + mSpiedBackgroundPanelOrganizer.removeBackgroundPanelLayer(); mTestableLooper.processAllMessages(); - assertThat(mBackgroundPanelOrganizer.mIsShowing).isFalse(); + assertThat(mSpiedBackgroundPanelOrganizer.mIsShowing).isFalse(); } } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java index bd5fe2bcbdad6..b0fc4c14a6bfc 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java @@ -23,20 +23,24 @@ import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.never; +import static org.mockito.Mockito.reset; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.content.om.IOverlayManager; +import android.graphics.Rect; import android.os.Handler; import android.testing.AndroidTestingRunner; import android.util.ArrayMap; import android.view.Display; +import android.view.Surface; import android.view.SurfaceControl; import androidx.test.filters.SmallTest; import com.android.wm.shell.common.DisplayController; +import com.android.wm.shell.common.DisplayLayout; import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.common.TaskStackListenerImpl; @@ -50,6 +54,7 @@ import org.mockito.MockitoAnnotations; @RunWith(AndroidTestingRunner.class) public class OneHandedControllerTest extends OneHandedTestCase { Display mDisplay; + DisplayLayout mDisplayLayout; OneHandedController mSpiedOneHandedController; OneHandedTimeoutHandler mSpiedTimeoutHandler; @@ -88,6 +93,7 @@ public class OneHandedControllerTest extends OneHandedTestCase { public void setUp() { MockitoAnnotations.initMocks(this); mDisplay = mContext.getDisplay(); + mDisplayLayout = new DisplayLayout(mContext, mDisplay); mSpiedTimeoutHandler = spy(new OneHandedTimeoutHandler(mMockShellMainExecutor)); when(mMockDisplayController.getDisplay(anyInt())).thenReturn(mDisplay); @@ -103,9 +109,12 @@ public class OneHandedControllerTest extends OneHandedTestCase { when(mMockSettingsUitl.getSettingsSwipeToNotificationEnabled(any())).thenReturn( mDefaultSwipeToNotificationEnabled); + when(mMockDisplayAreaOrganizer.getLastDisplayBounds()).thenReturn( + new Rect(0, 0, mDisplayLayout.width(), mDisplayLayout.height())); + when(mMockDisplayAreaOrganizer.getDisplayLayout()).thenReturn(mDisplayLayout); + mSpiedOneHandedController = spy(new OneHandedController( mContext, - mWindowManager, mMockDisplayController, mMockBackgroundOrganizer, mMockDisplayAreaOrganizer, @@ -127,7 +136,7 @@ public class OneHandedControllerTest extends OneHandedTestCase { final OneHandedAnimationController animationController = new OneHandedAnimationController( mContext); OneHandedDisplayAreaOrganizer displayAreaOrganizer = new OneHandedDisplayAreaOrganizer( - mContext, mWindowManager, animationController, mMockTutorialHandler, + mContext, mDisplayLayout, animationController, mMockTutorialHandler, mMockBackgroundOrganizer, mMockShellMainExecutor); assertThat(displayAreaOrganizer.isInOneHanded()).isFalse(); @@ -188,7 +197,7 @@ public class OneHandedControllerTest extends OneHandedTestCase { mSpiedOneHandedController.setOneHandedEnabled(true); verify(mMockTouchHandler, atLeastOnce()).onOneHandedEnabled(anyBoolean()); - verify(mMockGestureHandler, atLeastOnce()).onOneHandedEnabled(anyBoolean()); + verify(mMockGestureHandler, atLeastOnce()).onGestureEnabled(anyBoolean()); } @Test @@ -196,7 +205,7 @@ public class OneHandedControllerTest extends OneHandedTestCase { mSpiedOneHandedController.setSwipeToNotificationEnabled(mDefaultSwipeToNotificationEnabled); verify(mMockTouchHandler, atLeastOnce()).onOneHandedEnabled(anyBoolean()); - verify(mMockGestureHandler, atLeastOnce()).onOneHandedEnabled(anyBoolean()); + verify(mMockGestureHandler, atLeastOnce()).onGestureEnabled(anyBoolean()); } @Test @@ -282,4 +291,67 @@ public class OneHandedControllerTest extends OneHandedTestCase { verify(mMockDisplayAreaOrganizer).scheduleOffset(anyInt(), anyInt()); } + + @Test + public void testRotation90CanNotStartOneHanded() { + final DisplayLayout landscapeDisplayLayout = new DisplayLayout(mDisplayLayout); + landscapeDisplayLayout.rotateTo(mContext.getResources(), Surface.ROTATION_90); + when(mMockDisplayAreaOrganizer.isInOneHanded()).thenReturn(false); + when(mMockDisplayAreaOrganizer.getDisplayLayout()).thenReturn(landscapeDisplayLayout); + mSpiedOneHandedController.setOneHandedEnabled(true); + mSpiedOneHandedController.setLockedDisabled(false /* locked */, false /* enabled */); + mSpiedOneHandedController.startOneHanded(); + + verify(mMockDisplayAreaOrganizer, never()).scheduleOffset(anyInt(), anyInt()); + } + + @Test + public void testRotation180CanStartOneHanded() { + final DisplayLayout testDisplayLayout = new DisplayLayout(mDisplayLayout); + testDisplayLayout.rotateTo(mContext.getResources(), Surface.ROTATION_180); + when(mMockDisplayAreaOrganizer.isInOneHanded()).thenReturn(false); + when(mMockDisplayAreaOrganizer.getDisplayLayout()).thenReturn(testDisplayLayout); + mSpiedOneHandedController.setOneHandedEnabled(true); + mSpiedOneHandedController.setLockedDisabled(false /* locked */, false /* enabled */); + mSpiedOneHandedController.startOneHanded(); + + verify(mMockDisplayAreaOrganizer).scheduleOffset(anyInt(), anyInt()); + } + + @Test + public void testRotation270CanNotStartOneHanded() { + final DisplayLayout testDisplayLayout = new DisplayLayout(mDisplayLayout); + testDisplayLayout.rotateTo(mContext.getResources(), Surface.ROTATION_270); + when(mMockDisplayAreaOrganizer.isInOneHanded()).thenReturn(false); + when(mMockDisplayAreaOrganizer.getDisplayLayout()).thenReturn(testDisplayLayout); + mSpiedOneHandedController.setOneHandedEnabled(true); + mSpiedOneHandedController.setLockedDisabled(false /* locked */, false /* enabled */); + mSpiedOneHandedController.startOneHanded(); + + verify(mMockDisplayAreaOrganizer, never()).scheduleOffset(anyInt(), anyInt()); + } + + @Test + public void testDisabled3ButtonGestureWhenKeyguardOn() { + final boolean isOneHandedEnabled = true; + final boolean isLockWhenKeyguardOn = true; + final boolean isEnabledWhenKeyguardOn = false; + mSpiedOneHandedController.setOneHandedEnabled(isOneHandedEnabled); + mSpiedOneHandedController.setLockedDisabled(isLockWhenKeyguardOn, isEnabledWhenKeyguardOn); + + verify(mMockGestureHandler).onGestureEnabled(isEnabledWhenKeyguardOn); + } + + @Test + public void testEnabled3ButtonGestureWhenKeyguardGoingAway() { + final boolean isOneHandedEnabled = true; + final boolean isLockWhenKeyguardOn = false; + final boolean isEnabledWhenKeyguardOn = false; + mSpiedOneHandedController.setOneHandedEnabled(isOneHandedEnabled); + reset(mMockGestureHandler); + + mSpiedOneHandedController.setLockedDisabled(isLockWhenKeyguardOn, isEnabledWhenKeyguardOn); + + verify(mMockGestureHandler).onGestureEnabled(isOneHandedEnabled); + } } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizerTest.java index f897b09f8b8ba..f654bb59ef0cb 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizerTest.java @@ -19,6 +19,9 @@ package com.android.wm.shell.onehanded; import static android.view.Display.DEFAULT_DISPLAY; import static android.window.DisplayAreaOrganizer.FEATURE_ONE_HANDED; +import static com.android.wm.shell.onehanded.OneHandedAnimationController.TRANSITION_DIRECTION_EXIT; +import static com.android.wm.shell.onehanded.OneHandedAnimationController.TRANSITION_DIRECTION_TRIGGER; + import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.anyFloat; @@ -32,6 +35,7 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.content.res.Configuration; +import android.graphics.Rect; import android.os.Binder; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; @@ -47,6 +51,7 @@ import android.window.WindowContainerTransaction; import androidx.test.filters.SmallTest; import com.android.wm.shell.common.DisplayController; +import com.android.wm.shell.common.DisplayLayout; import com.android.wm.shell.common.ShellExecutor; import org.junit.Before; @@ -67,6 +72,7 @@ public class OneHandedDisplayAreaOrganizerTest extends OneHandedTestCase { DisplayAreaInfo mDisplayAreaInfo; Display mDisplay; + DisplayLayout mDisplayLayout; OneHandedDisplayAreaOrganizer mSpiedDisplayAreaOrganizer; OneHandedTutorialHandler mTutorialHandler; OneHandedAnimationController.OneHandedTransitionAnimator mFakeAnimator; @@ -103,6 +109,7 @@ public class OneHandedDisplayAreaOrganizerTest extends OneHandedTestCase { mToken = new WindowContainerToken(mMockRealToken); mLeash = new SurfaceControl(); mDisplay = mContext.getDisplay(); + mDisplayLayout = new DisplayLayout(mContext, mDisplay); mDisplayAreaInfo = new DisplayAreaInfo(mToken, DEFAULT_DISPLAY, FEATURE_ONE_HANDED); mDisplayAreaInfo.configuration.orientation = Configuration.ORIENTATION_PORTRAIT; when(mMockAnimationController.getAnimator(any(), any(), any(), any())).thenReturn(null); @@ -121,7 +128,7 @@ public class OneHandedDisplayAreaOrganizerTest extends OneHandedTestCase { when(mMockLeash.getHeight()).thenReturn(DISPLAY_HEIGHT); mSpiedDisplayAreaOrganizer = spy(new OneHandedDisplayAreaOrganizer(mContext, - mWindowManager, + mDisplayLayout, mMockAnimationController, mTutorialHandler, mMockBackgroundOrganizer, @@ -168,21 +175,14 @@ public class OneHandedDisplayAreaOrganizerTest extends OneHandedTestCase { any()); } - @Test - public void testRotation_getNewDisplayBounds() { - when(mMockLeash.isValid()).thenReturn(false); - // Rotate 0 -> 90 - mSpiedDisplayAreaOrganizer.onRotateDisplay(Surface.ROTATION_0, Surface.ROTATION_90, - mMockWindowContainerTransaction); - verify(mSpiedDisplayAreaOrganizer).getDisplayBounds(); - } - @Test public void testRotation_portrait_0_to_landscape_90() { when(mMockLeash.isValid()).thenReturn(false); // Rotate 0 -> 90 - mSpiedDisplayAreaOrganizer.onRotateDisplay(Surface.ROTATION_0, Surface.ROTATION_90, + mSpiedDisplayAreaOrganizer.onRotateDisplay(mContext, Surface.ROTATION_90, mMockWindowContainerTransaction); + + verify(mSpiedDisplayAreaOrganizer).resetWindowsOffset(mMockWindowContainerTransaction); verify(mSpiedDisplayAreaOrganizer).finishOffset(anyInt(), anyInt()); } @@ -190,8 +190,10 @@ public class OneHandedDisplayAreaOrganizerTest extends OneHandedTestCase { public void testRotation_portrait_0_to_seascape_270() { when(mMockLeash.isValid()).thenReturn(false); // Rotate 0 -> 270 - mSpiedDisplayAreaOrganizer.onRotateDisplay(Surface.ROTATION_0, Surface.ROTATION_270, + mSpiedDisplayAreaOrganizer.onRotateDisplay(mContext, Surface.ROTATION_270, mMockWindowContainerTransaction); + + verify(mSpiedDisplayAreaOrganizer).resetWindowsOffset(mMockWindowContainerTransaction); verify(mSpiedDisplayAreaOrganizer).finishOffset(anyInt(), anyInt()); } @@ -199,8 +201,12 @@ public class OneHandedDisplayAreaOrganizerTest extends OneHandedTestCase { public void testRotation_portrait_180_to_landscape_90() { when(mMockLeash.isValid()).thenReturn(false); // Rotate 180 -> 90 - mSpiedDisplayAreaOrganizer.onRotateDisplay(Surface.ROTATION_180, Surface.ROTATION_90, + mDisplayLayout.rotateTo(mContext.getResources(), Surface.ROTATION_180); + mSpiedDisplayAreaOrganizer.setDisplayLayout(mDisplayLayout); + mSpiedDisplayAreaOrganizer.onRotateDisplay(mContext, Surface.ROTATION_90, mMockWindowContainerTransaction); + + verify(mSpiedDisplayAreaOrganizer).resetWindowsOffset(mMockWindowContainerTransaction); verify(mSpiedDisplayAreaOrganizer).finishOffset(anyInt(), anyInt()); } @@ -208,8 +214,12 @@ public class OneHandedDisplayAreaOrganizerTest extends OneHandedTestCase { public void testRotation_portrait_180_to_seascape_270() { when(mMockLeash.isValid()).thenReturn(false); // Rotate 180 -> 270 - mSpiedDisplayAreaOrganizer.onRotateDisplay(Surface.ROTATION_180, Surface.ROTATION_270, + mDisplayLayout.rotateTo(mContext.getResources(), Surface.ROTATION_180); + mSpiedDisplayAreaOrganizer.setDisplayLayout(mDisplayLayout); + mSpiedDisplayAreaOrganizer.onRotateDisplay(mContext, Surface.ROTATION_270, mMockWindowContainerTransaction); + + verify(mSpiedDisplayAreaOrganizer).resetWindowsOffset(mMockWindowContainerTransaction); verify(mSpiedDisplayAreaOrganizer).finishOffset(anyInt(), anyInt()); } @@ -217,8 +227,12 @@ public class OneHandedDisplayAreaOrganizerTest extends OneHandedTestCase { public void testRotation_landscape_90_to_portrait_0() { when(mMockLeash.isValid()).thenReturn(false); // Rotate 90 -> 0 - mSpiedDisplayAreaOrganizer.onRotateDisplay(Surface.ROTATION_90, Surface.ROTATION_0, + mDisplayLayout.rotateTo(mContext.getResources(), Surface.ROTATION_90); + mSpiedDisplayAreaOrganizer.setDisplayLayout(mDisplayLayout); + mSpiedDisplayAreaOrganizer.onRotateDisplay(mContext, Surface.ROTATION_0, mMockWindowContainerTransaction); + + verify(mSpiedDisplayAreaOrganizer).resetWindowsOffset(mMockWindowContainerTransaction); verify(mSpiedDisplayAreaOrganizer).finishOffset(anyInt(), anyInt()); } @@ -226,26 +240,38 @@ public class OneHandedDisplayAreaOrganizerTest extends OneHandedTestCase { public void testRotation_landscape_90_to_portrait_180() { when(mMockLeash.isValid()).thenReturn(false); // Rotate 90 -> 180 - mSpiedDisplayAreaOrganizer.onRotateDisplay(Surface.ROTATION_90, Surface.ROTATION_180, + mDisplayLayout.rotateTo(mContext.getResources(), Surface.ROTATION_90); + mSpiedDisplayAreaOrganizer.setDisplayLayout(mDisplayLayout); + mSpiedDisplayAreaOrganizer.onRotateDisplay(mContext, Surface.ROTATION_180, mMockWindowContainerTransaction); + + verify(mSpiedDisplayAreaOrganizer).resetWindowsOffset(mMockWindowContainerTransaction); verify(mSpiedDisplayAreaOrganizer).finishOffset(anyInt(), anyInt()); } @Test - public void testRotation_Seascape_270_to_portrait_0() { + public void testRotation_seascape_270_to_portrait_0() { when(mMockLeash.isValid()).thenReturn(false); // Rotate 270 -> 0 - mSpiedDisplayAreaOrganizer.onRotateDisplay(Surface.ROTATION_270, Surface.ROTATION_0, + mDisplayLayout.rotateTo(mContext.getResources(), Surface.ROTATION_270); + mSpiedDisplayAreaOrganizer.setDisplayLayout(mDisplayLayout); + mSpiedDisplayAreaOrganizer.onRotateDisplay(mContext, Surface.ROTATION_0, mMockWindowContainerTransaction); + + verify(mSpiedDisplayAreaOrganizer).resetWindowsOffset(mMockWindowContainerTransaction); verify(mSpiedDisplayAreaOrganizer).finishOffset(anyInt(), anyInt()); } @Test - public void testRotation_seascape_90_to_portrait_180() { + public void testRotation_seascape_270_to_portrait_180() { when(mMockLeash.isValid()).thenReturn(false); // Rotate 270 -> 180 - mSpiedDisplayAreaOrganizer.onRotateDisplay(Surface.ROTATION_270, Surface.ROTATION_180, + mDisplayLayout.rotateTo(mContext.getResources(), Surface.ROTATION_270); + mSpiedDisplayAreaOrganizer.setDisplayLayout(mDisplayLayout); + mSpiedDisplayAreaOrganizer.onRotateDisplay(mContext, Surface.ROTATION_180, mMockWindowContainerTransaction); + + verify(mSpiedDisplayAreaOrganizer).resetWindowsOffset(mMockWindowContainerTransaction); verify(mSpiedDisplayAreaOrganizer).finishOffset(anyInt(), anyInt()); } @@ -253,7 +279,10 @@ public class OneHandedDisplayAreaOrganizerTest extends OneHandedTestCase { public void testRotation_portrait_0_to_portrait_0() { when(mMockLeash.isValid()).thenReturn(false); // Rotate 0 -> 0 - mSpiedDisplayAreaOrganizer.onRotateDisplay(Surface.ROTATION_0, Surface.ROTATION_0, + mSpiedDisplayAreaOrganizer.onRotateDisplay(mContext, Surface.ROTATION_0, + mMockWindowContainerTransaction); + + verify(mSpiedDisplayAreaOrganizer, never()).resetWindowsOffset( mMockWindowContainerTransaction); verify(mSpiedDisplayAreaOrganizer, never()).finishOffset(anyInt(), anyInt()); } @@ -262,16 +291,23 @@ public class OneHandedDisplayAreaOrganizerTest extends OneHandedTestCase { public void testRotation_portrait_0_to_portrait_180() { when(mMockLeash.isValid()).thenReturn(false); // Rotate 0 -> 180 - mSpiedDisplayAreaOrganizer.onRotateDisplay(Surface.ROTATION_0, Surface.ROTATION_180, + mSpiedDisplayAreaOrganizer.onRotateDisplay(mContext, Surface.ROTATION_180, mMockWindowContainerTransaction); - verify(mSpiedDisplayAreaOrganizer, never()).finishOffset(anyInt(), anyInt()); + + verify(mSpiedDisplayAreaOrganizer).resetWindowsOffset(mMockWindowContainerTransaction); + verify(mSpiedDisplayAreaOrganizer).finishOffset(anyInt(), anyInt()); } @Test public void testRotation_portrait_180_to_portrait_180() { when(mMockLeash.isValid()).thenReturn(false); // Rotate 180 -> 180 - mSpiedDisplayAreaOrganizer.onRotateDisplay(Surface.ROTATION_180, Surface.ROTATION_180, + mDisplayLayout.rotateTo(mContext.getResources(), Surface.ROTATION_180); + mSpiedDisplayAreaOrganizer.setDisplayLayout(mDisplayLayout); + mSpiedDisplayAreaOrganizer.onRotateDisplay(mContext, Surface.ROTATION_180, + mMockWindowContainerTransaction); + + verify(mSpiedDisplayAreaOrganizer, never()).resetWindowsOffset( mMockWindowContainerTransaction); verify(mSpiedDisplayAreaOrganizer, never()).finishOffset(anyInt(), anyInt()); } @@ -280,16 +316,25 @@ public class OneHandedDisplayAreaOrganizerTest extends OneHandedTestCase { public void testRotation_portrait_180_to_portrait_0() { when(mMockLeash.isValid()).thenReturn(false); // Rotate 180 -> 0 - mSpiedDisplayAreaOrganizer.onRotateDisplay(Surface.ROTATION_180, Surface.ROTATION_0, + mDisplayLayout.rotateTo(mContext.getResources(), Surface.ROTATION_90); + mSpiedDisplayAreaOrganizer.setDisplayLayout(mDisplayLayout); + mSpiedDisplayAreaOrganizer.onRotateDisplay(mContext, Surface.ROTATION_0, mMockWindowContainerTransaction); - verify(mSpiedDisplayAreaOrganizer, never()).finishOffset(anyInt(), anyInt()); + + verify(mSpiedDisplayAreaOrganizer).resetWindowsOffset(mMockWindowContainerTransaction); + verify(mSpiedDisplayAreaOrganizer).finishOffset(anyInt(), anyInt()); } @Test public void testRotation_landscape_90_to_landscape_90() { when(mMockLeash.isValid()).thenReturn(false); // Rotate 90 -> 90 - mSpiedDisplayAreaOrganizer.onRotateDisplay(Surface.ROTATION_90, Surface.ROTATION_90, + mDisplayLayout.rotateTo(mContext.getResources(), Surface.ROTATION_90); + mSpiedDisplayAreaOrganizer.setDisplayLayout(mDisplayLayout); + mSpiedDisplayAreaOrganizer.onRotateDisplay(mContext, Surface.ROTATION_90, + mMockWindowContainerTransaction); + + verify(mSpiedDisplayAreaOrganizer, never()).resetWindowsOffset( mMockWindowContainerTransaction); verify(mSpiedDisplayAreaOrganizer, never()).finishOffset(anyInt(), anyInt()); } @@ -298,26 +343,60 @@ public class OneHandedDisplayAreaOrganizerTest extends OneHandedTestCase { public void testRotation_landscape_90_to_seascape_270() { when(mMockLeash.isValid()).thenReturn(false); // Rotate 90 -> 270 - mSpiedDisplayAreaOrganizer.onRotateDisplay(Surface.ROTATION_90, Surface.ROTATION_270, + mDisplayLayout.rotateTo(mContext.getResources(), Surface.ROTATION_90); + mSpiedDisplayAreaOrganizer.setDisplayLayout(mDisplayLayout); + mSpiedDisplayAreaOrganizer.onRotateDisplay(mContext, Surface.ROTATION_270, mMockWindowContainerTransaction); - verify(mSpiedDisplayAreaOrganizer, never()).finishOffset(anyInt(), anyInt()); + + verify(mSpiedDisplayAreaOrganizer).resetWindowsOffset(mMockWindowContainerTransaction); + verify(mSpiedDisplayAreaOrganizer).finishOffset(anyInt(), anyInt()); } @Test public void testRotation_seascape_270_to_seascape_270() { when(mMockLeash.isValid()).thenReturn(false); // Rotate 270 -> 270 - mSpiedDisplayAreaOrganizer.onRotateDisplay(Surface.ROTATION_270, Surface.ROTATION_270, + mDisplayLayout.rotateTo(mContext.getResources(), Surface.ROTATION_270); + mSpiedDisplayAreaOrganizer.setDisplayLayout(mDisplayLayout); + mSpiedDisplayAreaOrganizer.onRotateDisplay(mContext, Surface.ROTATION_270, + mMockWindowContainerTransaction); + + verify(mSpiedDisplayAreaOrganizer, never()).resetWindowsOffset( mMockWindowContainerTransaction); verify(mSpiedDisplayAreaOrganizer, never()).finishOffset(anyInt(), anyInt()); } @Test - public void testRotation_seascape_90_to_landscape_90() { + public void testRotation_seascape_270_to_landscape_90() { when(mMockLeash.isValid()).thenReturn(false); // Rotate 270 -> 90 - mSpiedDisplayAreaOrganizer.onRotateDisplay(Surface.ROTATION_270, Surface.ROTATION_90, + mDisplayLayout.rotateTo(mContext.getResources(), Surface.ROTATION_270); + mSpiedDisplayAreaOrganizer.setDisplayLayout(mDisplayLayout); + mSpiedDisplayAreaOrganizer.onRotateDisplay(mContext, Surface.ROTATION_90, mMockWindowContainerTransaction); - verify(mSpiedDisplayAreaOrganizer, never()).finishOffset(anyInt(), anyInt()); + + verify(mSpiedDisplayAreaOrganizer).resetWindowsOffset( + mMockWindowContainerTransaction); + verify(mSpiedDisplayAreaOrganizer).finishOffset(anyInt(), anyInt()); + } + + @Test + public void testTriggerOffset() { + final Rect testBounds = mSpiedDisplayAreaOrganizer.getLastDisplayBounds(); + final int offset = 100; + testBounds.offsetTo(0, offset); + mSpiedDisplayAreaOrganizer.finishOffset(offset, TRANSITION_DIRECTION_TRIGGER); + + assertThat(mSpiedDisplayAreaOrganizer.getLastDisplayBounds()).isEqualTo(testBounds); + } + + @Test + public void testExitOffsetToZero() { + final Rect testBounds = mSpiedDisplayAreaOrganizer.getLastDisplayBounds(); + final int offset = 100; + mSpiedDisplayAreaOrganizer.finishOffset(offset, TRANSITION_DIRECTION_TRIGGER); + mSpiedDisplayAreaOrganizer.finishOffset(0, TRANSITION_DIRECTION_EXIT); + + assertThat(mSpiedDisplayAreaOrganizer.getLastDisplayBounds()).isEqualTo(testBounds); } } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedGestureHandlerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedGestureHandlerTest.java index f683e4af41bd5..5d82a700545c3 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedGestureHandlerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedGestureHandlerTest.java @@ -16,21 +16,19 @@ package com.android.wm.shell.onehanded; -import static android.view.Display.DEFAULT_DISPLAY; - import static com.google.common.truth.Truth.assertThat; -import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.testing.AndroidTestingRunner; import android.view.Surface; import android.view.ViewConfiguration; -import android.window.WindowContainerTransaction; import androidx.test.filters.SmallTest; -import com.android.wm.shell.common.DisplayController; import com.android.wm.shell.common.DisplayLayout; import com.android.wm.shell.common.ShellExecutor; @@ -44,24 +42,20 @@ import org.mockito.MockitoAnnotations; @RunWith(AndroidTestingRunner.class) public class OneHandedGestureHandlerTest extends OneHandedTestCase { OneHandedGestureHandler mGestureHandler; - @Mock - DisplayController mMockDisplayController; + DisplayLayout mDisplayLayout; @Mock DisplayLayout mMockDisplayLayout; @Mock ShellExecutor mMockShellMainExecutor; - @Mock - WindowContainerTransaction mMockWct; @Before public void setUp() { final int mockNavBarHeight = 100; MockitoAnnotations.initMocks(this); - mGestureHandler = new OneHandedGestureHandler(mContext, mWindowManager, - mMockDisplayController, ViewConfiguration.get(mTestContext), - mMockShellMainExecutor); + mDisplayLayout = new DisplayLayout(mContext, mContext.getDisplay()); + mGestureHandler = new OneHandedGestureHandler(mContext, mDisplayLayout, + ViewConfiguration.get(mTestContext), mMockShellMainExecutor); when(mMockDisplayLayout.navBarFrameHeight()).thenReturn(mockNavBarHeight); - when(mMockDisplayController.getDisplayLayout(anyInt())).thenReturn(mMockDisplayLayout); } @Test @@ -81,7 +75,7 @@ public class OneHandedGestureHandlerTest extends OneHandedTestCase { @Test public void testOneHandedDisabled_shouldDisposeInputChannel() { - mGestureHandler.onOneHandedEnabled(false); + mGestureHandler.onGestureEnabled(false); assertThat(mGestureHandler.mInputMonitor).isNull(); assertThat(mGestureHandler.mInputEventReceiver).isNull(); @@ -89,7 +83,7 @@ public class OneHandedGestureHandlerTest extends OneHandedTestCase { @Test public void testChangeNavBarToNon3Button_shouldDisposeInputChannel() { - mGestureHandler.onOneHandedEnabled(true); + mGestureHandler.onGestureEnabled(true); mGestureHandler.onThreeButtonModeEnabled(false); assertThat(mGestureHandler.mInputMonitor).isNull(); @@ -98,11 +92,38 @@ public class OneHandedGestureHandlerTest extends OneHandedTestCase { @Test public void testOnlyHandleGestureInPortraitMode() { - mGestureHandler.onOneHandedEnabled(true); - mGestureHandler.onRotateDisplay(DEFAULT_DISPLAY, Surface.ROTATION_0, Surface.ROTATION_90, - mMockWct); + mDisplayLayout.rotateTo(mContext.getResources(), Surface.ROTATION_90); + mGestureHandler.onGestureEnabled(true); + mGestureHandler.onRotateDisplay(mDisplayLayout); assertThat(mGestureHandler.mInputMonitor).isNull(); assertThat(mGestureHandler.mInputEventReceiver).isNull(); } + + @Test + public void testRotation90ShouldNotRegisterEventReceiver() throws InterruptedException { + mDisplayLayout.rotateTo(mContext.getResources(), Surface.ROTATION_90); + mGestureHandler.onGestureEnabled(true); + mGestureHandler.onRotateDisplay(mDisplayLayout); + + verify(mMockShellMainExecutor, never()).executeBlocking(any()); + } + + @Test + public void testRotation180ShouldNotRegisterEventReceiver() throws InterruptedException { + mDisplayLayout.rotateTo(mContext.getResources(), Surface.ROTATION_180); + mGestureHandler.onGestureEnabled(true); + mGestureHandler.onRotateDisplay(mDisplayLayout); + + verify(mMockShellMainExecutor, never()).executeBlocking(any()); + } + + @Test + public void testRotation270ShouldNotRegisterEventReceiver() throws InterruptedException { + mDisplayLayout.rotateTo(mContext.getResources(), Surface.ROTATION_270); + mGestureHandler.onGestureEnabled(true); + mGestureHandler.onRotateDisplay(mDisplayLayout); + + verify(mMockShellMainExecutor, never()).executeBlocking(any()); + } } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedTutorialHandlerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedTutorialHandlerTest.java index f586dda145d70..2886bb1e905ac 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedTutorialHandlerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedTutorialHandlerTest.java @@ -75,7 +75,6 @@ public class OneHandedTutorialHandlerTest extends OneHandedTestCase { when(mMockDisplayAreaOrganizer.getDisplayAreaTokenMap()).thenReturn(new ArrayMap<>()); mOneHandedController = new OneHandedController( mContext, - mWindowManager, mMockDisplayController, mMockBackgroundOrganizer, mMockDisplayAreaOrganizer, diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java index ddfa63a33149f..83ca457051b4c 100644 --- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java +++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java @@ -52,6 +52,7 @@ import com.android.wm.shell.bubbles.BubbleController; import com.android.wm.shell.bubbles.Bubbles; import com.android.wm.shell.common.DisplayController; import com.android.wm.shell.common.DisplayImeController; +import com.android.wm.shell.common.DisplayLayout; import com.android.wm.shell.common.FloatingContentCoordinator; import com.android.wm.shell.common.HandlerExecutor; import com.android.wm.shell.common.ShellExecutor; @@ -214,6 +215,12 @@ public abstract class WMShellBaseModule { return new DisplayController(context, wmService, mainExecutor); } + @WMSingleton + @Provides + static DisplayLayout provideDisplayLayout() { + return new DisplayLayout(); + } + @WMSingleton @Provides static DragAndDropController provideDragAndDropController(Context context, @@ -344,11 +351,13 @@ public abstract class WMShellBaseModule { @Provides static Optional provideOneHandedController(Context context, WindowManager windowManager, DisplayController displayController, - TaskStackListenerImpl taskStackListener, UiEventLogger uiEventLogger, + DisplayLayout displayLayout, TaskStackListenerImpl taskStackListener, + UiEventLogger uiEventLogger, @ShellMainThread ShellExecutor mainExecutor, @ShellMainThread Handler mainHandler) { return Optional.ofNullable(OneHandedController.create(context, windowManager, - displayController, taskStackListener, uiEventLogger, mainExecutor, mainHandler)); + displayController, displayLayout, taskStackListener, uiEventLogger, mainExecutor, + mainHandler)); } //