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
This commit is contained in:
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<OneHandedController>
|
||||
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<OneHandedController>
|
||||
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<OneHandedController>
|
||||
*/
|
||||
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<OneHandedController>
|
||||
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<OneHandedController>
|
||||
}
|
||||
};
|
||||
|
||||
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<OneHandedController>
|
||||
@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<OneHandedController>
|
||||
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<OneHandedController>
|
||||
|
||||
@VisibleForTesting
|
||||
OneHandedController(Context context,
|
||||
WindowManager windowManager,
|
||||
DisplayController displayController,
|
||||
OneHandedBackgroundPanelOrganizer backgroundPanelOrganizer,
|
||||
OneHandedDisplayAreaOrganizer displayAreaOrganizer,
|
||||
@@ -205,7 +230,6 @@ public class OneHandedController implements RemoteCallable<OneHandedController>
|
||||
Handler mainHandler) {
|
||||
mContext = context;
|
||||
mOneHandedSettingsUtil = settingsUtil;
|
||||
mWindowManager = windowManager;
|
||||
mBackgroundPanelOrganizer = backgroundPanelOrganizer;
|
||||
mDisplayAreaOrganizer = displayAreaOrganizer;
|
||||
mDisplayController = displayController;
|
||||
@@ -218,6 +242,7 @@ public class OneHandedController implements RemoteCallable<OneHandedController>
|
||||
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<OneHandedController>
|
||||
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<OneHandedController>
|
||||
.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<OneHandedController>
|
||||
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<OneHandedController>
|
||||
}
|
||||
|
||||
mTouchHandler.onOneHandedEnabled(mIsOneHandedEnabled);
|
||||
mGestureHandler.onOneHandedEnabled(mIsOneHandedEnabled || mIsSwipeToNotificationEnabled);
|
||||
mGestureHandler.onGestureEnabled(mIsOneHandedEnabled || mIsSwipeToNotificationEnabled);
|
||||
|
||||
if (!mIsOneHandedEnabled) {
|
||||
mDisplayAreaOrganizer.unregisterOrganizer();
|
||||
@@ -532,10 +551,15 @@ public class OneHandedController implements RemoteCallable<OneHandedController>
|
||||
|
||||
@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<OneHandedController>
|
||||
pw.print(innerPrefix + "mLockedDisabled=");
|
||||
pw.println(mLockedDisabled);
|
||||
|
||||
if (mBackgroundPanelOrganizer != null) {
|
||||
mBackgroundPanelOrganizer.dump(pw);
|
||||
}
|
||||
|
||||
if (mDisplayAreaOrganizer != null) {
|
||||
mDisplayAreaOrganizer.dump(pw);
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,7 +75,6 @@ public class OneHandedTutorialHandlerTest extends OneHandedTestCase {
|
||||
when(mMockDisplayAreaOrganizer.getDisplayAreaTokenMap()).thenReturn(new ArrayMap<>());
|
||||
mOneHandedController = new OneHandedController(
|
||||
mContext,
|
||||
mWindowManager,
|
||||
mMockDisplayController,
|
||||
mMockBackgroundOrganizer,
|
||||
mMockDisplayAreaOrganizer,
|
||||
|
||||
@@ -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<OneHandedController> 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));
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
Reference in New Issue
Block a user