(1/n) Disabling OHM gesture in NavigationBar 3 Button mode
1) UX mentioned the swipe gesture in 3-Button NavgationBar area may confuse user from taping NavBar buttons(Back, Home, Recents). They decide to disable the swipe gesture and allow user to trigger One Handed Mode(3 Button Mode) through A11y shortcut. However, user can still use OHM by enabled shortcut button on both Gesture Navigation & 3-Button mode. 2) OHM gestural handler consume the touch event while window Magnification overlap with NavigationBar area in 3-button mode, this result Magnification function can no long obtain the control. Bug: 184903678 Bug: 179648683 Test: manual Test: atest WMShellUnitTests Change-Id: Ib9a06e19d749707e6f5e08c3ef803c1681f86bbc
This commit is contained in:
@@ -19,7 +19,6 @@ package com.android.wm.shell.onehanded;
|
||||
import android.content.res.Configuration;
|
||||
|
||||
import com.android.wm.shell.common.annotations.ExternalThread;
|
||||
import com.android.wm.shell.onehanded.OneHandedGestureHandler.OneHandedGestureEventCallback;
|
||||
|
||||
/**
|
||||
* Interface to engage one handed feature.
|
||||
@@ -59,11 +58,6 @@ public interface OneHanded {
|
||||
*/
|
||||
void stopOneHanded(int uiEvent);
|
||||
|
||||
/**
|
||||
* Sets navigation 3 button mode enabled or disabled by users.
|
||||
*/
|
||||
void setThreeButtonModeEnabled(boolean enabled);
|
||||
|
||||
/**
|
||||
* Sets one handed feature temporary locked in enabled or disabled state, this won't change
|
||||
* settings configuration.
|
||||
@@ -79,12 +73,6 @@ public interface OneHanded {
|
||||
*/
|
||||
void registerTransitionCallback(OneHandedTransitionCallback callback);
|
||||
|
||||
/**
|
||||
* Registers callback for one handed gesture, this gesture callback will be activated on
|
||||
* 3 button navigation mode only
|
||||
*/
|
||||
void registerGestureCallback(OneHandedGestureEventCallback callback);
|
||||
|
||||
/**
|
||||
* Receive onConfigurationChanged() events
|
||||
*/
|
||||
|
||||
@@ -41,7 +41,6 @@ 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;
|
||||
|
||||
@@ -59,7 +58,6 @@ import com.android.wm.shell.common.ShellExecutor;
|
||||
import com.android.wm.shell.common.TaskStackListenerCallback;
|
||||
import com.android.wm.shell.common.TaskStackListenerImpl;
|
||||
import com.android.wm.shell.common.annotations.ExternalThread;
|
||||
import com.android.wm.shell.onehanded.OneHandedGestureHandler.OneHandedGestureEventCallback;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
|
||||
@@ -101,7 +99,6 @@ public class OneHandedController implements RemoteCallable<OneHandedController>
|
||||
private final OneHandedImpl mImpl = new OneHandedImpl();
|
||||
|
||||
private OneHandedDisplayAreaOrganizer mDisplayAreaOrganizer;
|
||||
private OneHandedGestureHandler mGestureHandler;
|
||||
private OneHandedBackgroundPanelOrganizer mBackgroundPanelOrganizer;
|
||||
|
||||
/**
|
||||
@@ -113,7 +110,6 @@ public class OneHandedController implements RemoteCallable<OneHandedController>
|
||||
return;
|
||||
}
|
||||
mDisplayAreaOrganizer.onRotateDisplay(mContext, toRotation, wct);
|
||||
mGestureHandler.onRotateDisplay(mDisplayAreaOrganizer.getDisplayLayout());
|
||||
};
|
||||
|
||||
private final DisplayController.OnDisplaysChangedListener mDisplaysChangedListener =
|
||||
@@ -196,7 +192,7 @@ public class OneHandedController implements RemoteCallable<OneHandedController>
|
||||
|
||||
private boolean isInitialized() {
|
||||
if (mDisplayAreaOrganizer == null || mDisplayController == null
|
||||
|| mGestureHandler == null || mOneHandedSettingsUtil == null) {
|
||||
|| mOneHandedSettingsUtil == null) {
|
||||
Slog.w(TAG, "Components may not initialized yet!");
|
||||
return false;
|
||||
}
|
||||
@@ -226,8 +222,6 @@ public class OneHandedController implements RemoteCallable<OneHandedController>
|
||||
new OneHandedAnimationController(context);
|
||||
OneHandedTouchHandler touchHandler = new OneHandedTouchHandler(timeoutHandler,
|
||||
mainExecutor);
|
||||
OneHandedGestureHandler gestureHandler = new OneHandedGestureHandler(
|
||||
context, displayLayout, ViewConfiguration.get(context), mainExecutor);
|
||||
OneHandedBackgroundPanelOrganizer oneHandedBackgroundPanelOrganizer =
|
||||
new OneHandedBackgroundPanelOrganizer(context, displayLayout, mainExecutor);
|
||||
OneHandedDisplayAreaOrganizer organizer = new OneHandedDisplayAreaOrganizer(
|
||||
@@ -238,7 +232,7 @@ public class OneHandedController implements RemoteCallable<OneHandedController>
|
||||
ServiceManager.getService(Context.OVERLAY_SERVICE));
|
||||
return new OneHandedController(context, displayController,
|
||||
oneHandedBackgroundPanelOrganizer, organizer, touchHandler, tutorialHandler,
|
||||
gestureHandler, settingsUtil, accessibilityUtil, timeoutHandler, transitionState,
|
||||
settingsUtil, accessibilityUtil, timeoutHandler, transitionState,
|
||||
oneHandedUiEventsLogger, overlayManager, taskStackListener, mainExecutor,
|
||||
mainHandler);
|
||||
}
|
||||
@@ -250,7 +244,6 @@ public class OneHandedController implements RemoteCallable<OneHandedController>
|
||||
OneHandedDisplayAreaOrganizer displayAreaOrganizer,
|
||||
OneHandedTouchHandler touchHandler,
|
||||
OneHandedTutorialHandler tutorialHandler,
|
||||
OneHandedGestureHandler gestureHandler,
|
||||
OneHandedSettingsUtil settingsUtil,
|
||||
OneHandedAccessibilityUtil oneHandedAccessibilityUtil,
|
||||
OneHandedTimeoutHandler timeoutHandler,
|
||||
@@ -269,7 +262,6 @@ public class OneHandedController implements RemoteCallable<OneHandedController>
|
||||
mTouchHandler = touchHandler;
|
||||
mState = state;
|
||||
mTutorialHandler = tutorialHandler;
|
||||
mGestureHandler = gestureHandler;
|
||||
mOverlayManager = overlayManager;
|
||||
mMainExecutor = mainExecutor;
|
||||
mMainHandler = mainHandler;
|
||||
@@ -399,24 +391,15 @@ public class OneHandedController implements RemoteCallable<OneHandedController>
|
||||
mOneHandedUiEventLogger.writeEvent(uiEvent);
|
||||
}
|
||||
|
||||
private void setThreeButtonModeEnabled(boolean enabled) {
|
||||
mGestureHandler.onThreeButtonModeEnabled(enabled);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
void registerTransitionCallback(OneHandedTransitionCallback callback) {
|
||||
mDisplayAreaOrganizer.registerTransitionCallback(callback);
|
||||
}
|
||||
|
||||
private void registerGestureCallback(OneHandedGestureEventCallback callback) {
|
||||
mGestureHandler.setGestureEventListener(callback);
|
||||
}
|
||||
|
||||
private void setupCallback() {
|
||||
mTouchHandler.registerTouchEventListener(() ->
|
||||
stopOneHanded(OneHandedUiEventLogger.EVENT_ONE_HANDED_TRIGGER_OVERSPACE_OUT));
|
||||
mDisplayAreaOrganizer.registerTransitionCallback(mTouchHandler);
|
||||
mDisplayAreaOrganizer.registerTransitionCallback(mGestureHandler);
|
||||
mDisplayAreaOrganizer.registerTransitionCallback(mTutorialHandler);
|
||||
mDisplayAreaOrganizer.registerTransitionCallback(mBackgroundPanelOrganizer);
|
||||
mDisplayAreaOrganizer.registerTransitionCallback(mTransitionCallBack);
|
||||
@@ -465,7 +448,6 @@ public class OneHandedController implements RemoteCallable<OneHandedController>
|
||||
private void updateDisplayLayout(int displayId) {
|
||||
final DisplayLayout newDisplayLayout = mDisplayController.getDisplayLayout(displayId);
|
||||
mDisplayAreaOrganizer.setDisplayLayout(newDisplayLayout);
|
||||
mGestureHandler.onDisplayChanged(newDisplayLayout);
|
||||
mTutorialHandler.onDisplayChanged(newDisplayLayout);
|
||||
}
|
||||
|
||||
@@ -588,7 +570,6 @@ public class OneHandedController implements RemoteCallable<OneHandedController>
|
||||
}
|
||||
|
||||
mTouchHandler.onOneHandedEnabled(mIsOneHandedEnabled);
|
||||
mGestureHandler.onGestureEnabled(mIsOneHandedEnabled || mIsSwipeToNotificationEnabled);
|
||||
|
||||
if (!mIsOneHandedEnabled) {
|
||||
mDisplayAreaOrganizer.unregisterOrganizer();
|
||||
@@ -643,9 +624,6 @@ public class OneHandedController implements RemoteCallable<OneHandedController>
|
||||
return;
|
||||
}
|
||||
mLockedDisabled = locked && !enabled;
|
||||
|
||||
// Disabled gesture when keyguard ON
|
||||
mGestureHandler.onGestureEnabled(!mLockedDisabled && isFeatureEnabled);
|
||||
}
|
||||
|
||||
private void onConfigChanged(Configuration newConfig) {
|
||||
@@ -685,10 +663,6 @@ public class OneHandedController implements RemoteCallable<OneHandedController>
|
||||
mDisplayAreaOrganizer.dump(pw);
|
||||
}
|
||||
|
||||
if (mGestureHandler != null) {
|
||||
mGestureHandler.dump(pw);
|
||||
}
|
||||
|
||||
if (mTouchHandler != null) {
|
||||
mTouchHandler.dump(pw);
|
||||
}
|
||||
@@ -774,13 +748,6 @@ public class OneHandedController implements RemoteCallable<OneHandedController>
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setThreeButtonModeEnabled(boolean enabled) {
|
||||
mMainExecutor.execute(() -> {
|
||||
OneHandedController.this.setThreeButtonModeEnabled(enabled);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLockedDisabled(boolean locked, boolean enabled) {
|
||||
mMainExecutor.execute(() -> {
|
||||
@@ -795,13 +762,6 @@ public class OneHandedController implements RemoteCallable<OneHandedController>
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerGestureCallback(OneHandedGestureEventCallback callback) {
|
||||
mMainExecutor.execute(() -> {
|
||||
OneHandedController.this.registerGestureCallback(callback);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConfigChanged(Configuration newConfig) {
|
||||
mMainExecutor.execute(() -> {
|
||||
|
||||
@@ -1,308 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.wm.shell.onehanded;
|
||||
|
||||
import static android.view.Display.DEFAULT_DISPLAY;
|
||||
|
||||
import android.annotation.Nullable;
|
||||
import android.content.Context;
|
||||
import android.graphics.PointF;
|
||||
import android.graphics.Rect;
|
||||
import android.hardware.input.InputManager;
|
||||
import android.os.Looper;
|
||||
import android.view.Display;
|
||||
import android.view.InputChannel;
|
||||
import android.view.InputEvent;
|
||||
import android.view.InputEventReceiver;
|
||||
import android.view.InputMonitor;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.Surface;
|
||||
import android.view.ViewConfiguration;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
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;
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
private static final String TAG = "OneHandedGestureHandler";
|
||||
|
||||
private static final int ANGLE_MAX = 150;
|
||||
private static final int ANGLE_MIN = 30;
|
||||
private final float mDragDistThreshold;
|
||||
private final float mSquaredSlop;
|
||||
private final PointF mDownPos = new PointF();
|
||||
private final PointF mLastPos = new PointF();
|
||||
private final PointF mStartDragPos = new PointF();
|
||||
|
||||
private boolean mPassedSlop;
|
||||
private boolean mAllowGesture;
|
||||
private boolean mIsEnabled;
|
||||
private int mNavGestureHeight;
|
||||
private boolean mIsThreeButtonModeEnabled;
|
||||
private int mRotation = Surface.ROTATION_0;
|
||||
|
||||
@VisibleForTesting
|
||||
InputMonitor mInputMonitor;
|
||||
@VisibleForTesting
|
||||
InputEventReceiver mInputEventReceiver;
|
||||
private final ShellExecutor mMainExecutor;
|
||||
@VisibleForTesting
|
||||
@Nullable
|
||||
OneHandedGestureEventCallback mGestureEventCallback;
|
||||
private Rect mGestureRegion = new Rect();
|
||||
private boolean mIsStopGesture;
|
||||
|
||||
/**
|
||||
* Constructor of OneHandedGestureHandler, we only handle the gesture of {@link
|
||||
* Display#DEFAULT_DISPLAY}
|
||||
*
|
||||
* @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,
|
||||
DisplayLayout displayLayout,
|
||||
ViewConfiguration viewConfig,
|
||||
ShellExecutor mainExecutor) {
|
||||
mMainExecutor = mainExecutor;
|
||||
mDragDistThreshold = context.getResources().getDimensionPixelSize(
|
||||
R.dimen.gestures_onehanded_drag_threshold);
|
||||
|
||||
final float slop = viewConfig.getScaledTouchSlop();
|
||||
mSquaredSlop = slop * slop;
|
||||
onDisplayChanged(displayLayout);
|
||||
updateIsEnabled();
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies by {@link OneHandedController}, when swipe down gesture is enabled on 3 button
|
||||
* navigation bar mode.
|
||||
*
|
||||
* @param isEnabled Either one handed mode or swipe for notification function enabled or not
|
||||
*/
|
||||
public void onGestureEnabled(boolean isEnabled) {
|
||||
mIsEnabled = isEnabled;
|
||||
updateIsEnabled();
|
||||
}
|
||||
|
||||
void onThreeButtonModeEnabled(boolean isEnabled) {
|
||||
mIsThreeButtonModeEnabled = isEnabled;
|
||||
updateIsEnabled();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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()) && isGestureAvailable();
|
||||
if (mAllowGesture) {
|
||||
mDownPos.set(ev.getX(), ev.getY());
|
||||
mLastPos.set(mDownPos);
|
||||
}
|
||||
} else if (mAllowGesture) {
|
||||
switch (action) {
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
mLastPos.set(ev.getX(), ev.getY());
|
||||
if (!mPassedSlop) {
|
||||
if (squaredHypot(mLastPos.x - mDownPos.x, mLastPos.y - mDownPos.y)
|
||||
> mSquaredSlop) {
|
||||
mStartDragPos.set(mLastPos.x, mLastPos.y);
|
||||
if (isValidStartAngle(
|
||||
mDownPos.x - mLastPos.x, mDownPos.y - mLastPos.y)
|
||||
|| isValidExitAngle(
|
||||
mDownPos.x - mLastPos.x, mDownPos.y - mLastPos.y)) {
|
||||
mPassedSlop = true;
|
||||
mInputMonitor.pilferPointers();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
float distance = (float) Math.hypot(mLastPos.x - mDownPos.x,
|
||||
mLastPos.y - mDownPos.y);
|
||||
if (distance > mDragDistThreshold) {
|
||||
mIsStopGesture = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case MotionEvent.ACTION_UP:
|
||||
if (mLastPos.y >= mDownPos.y && mPassedSlop) {
|
||||
mGestureEventCallback.onStart();
|
||||
} else if (mIsStopGesture) {
|
||||
mGestureEventCallback.onStop();
|
||||
}
|
||||
clearState();
|
||||
break;
|
||||
case MotionEvent.ACTION_CANCEL:
|
||||
clearState();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void clearState() {
|
||||
mPassedSlop = false;
|
||||
mIsStopGesture = false;
|
||||
}
|
||||
|
||||
private void disposeInputChannel() {
|
||||
if (mInputEventReceiver != null) {
|
||||
mInputEventReceiver.dispose();
|
||||
mInputEventReceiver = null;
|
||||
}
|
||||
|
||||
if (mInputMonitor != null) {
|
||||
mInputMonitor.dispose();
|
||||
mInputMonitor = null;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isWithinTouchRegion(float x, float y) {
|
||||
return mGestureRegion.contains(Math.round(x), Math.round(y));
|
||||
}
|
||||
|
||||
private int getNavBarSize(@NonNull DisplayLayout displayLayout) {
|
||||
return isGestureAvailable() ? displayLayout.navBarFrameHeight() : 0 /* In landscape */;
|
||||
}
|
||||
|
||||
private void updateIsEnabled() {
|
||||
disposeInputChannel();
|
||||
|
||||
if (mIsEnabled && mIsThreeButtonModeEnabled && isGestureAvailable()) {
|
||||
mInputMonitor = InputManager.getInstance().monitorGestureInput(
|
||||
"onehanded-gesture-offset", DEFAULT_DISPLAY);
|
||||
try {
|
||||
mMainExecutor.executeBlocking(() -> {
|
||||
mInputEventReceiver = new EventReceiver(
|
||||
mInputMonitor.getInputChannel(), Looper.myLooper());
|
||||
});
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException("Failed to create input event receiver", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void onInputEvent(InputEvent ev) {
|
||||
if (ev instanceof MotionEvent) {
|
||||
onMotionEvent((MotionEvent) ev);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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();
|
||||
}
|
||||
|
||||
// TODO: Use BatchedInputEventReceiver
|
||||
private class EventReceiver extends InputEventReceiver {
|
||||
EventReceiver(InputChannel channel, Looper looper) {
|
||||
super(channel, looper);
|
||||
}
|
||||
|
||||
public void onInputEvent(InputEvent event) {
|
||||
OneHandedGestureHandler.this.onInputEvent(event);
|
||||
finishInputEvent(event, true);
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
final float angle = (float) Math.toDegrees(Math.atan2(deltaY, deltaX));
|
||||
return angle > -(ANGLE_MAX) && angle < -(ANGLE_MIN);
|
||||
}
|
||||
|
||||
private boolean isValidExitAngle(float deltaX, float deltaY) {
|
||||
final float angle = (float) Math.toDegrees(Math.atan2(deltaY, deltaX));
|
||||
return angle > ANGLE_MIN && angle < ANGLE_MAX;
|
||||
}
|
||||
|
||||
private float squaredHypot(float x, float y) {
|
||||
return x * x + y * y;
|
||||
}
|
||||
|
||||
void dump(@NonNull PrintWriter pw) {
|
||||
final String innerPrefix = " ";
|
||||
pw.println(TAG);
|
||||
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 + "mRotation=");
|
||||
pw.println(mRotation);
|
||||
}
|
||||
|
||||
/**
|
||||
* The touch(gesture) events to notify {@link OneHandedController} start or stop one handed
|
||||
*/
|
||||
public interface OneHandedGestureEventCallback {
|
||||
/**
|
||||
* Handles the start gesture.
|
||||
*/
|
||||
void onStart();
|
||||
|
||||
/**
|
||||
* Handles the exit gesture.
|
||||
*/
|
||||
void onStop();
|
||||
}
|
||||
}
|
||||
@@ -37,7 +37,6 @@ import java.io.PrintWriter;
|
||||
/**
|
||||
* Manages all the touch handling for One Handed on the Phone, including user tap outside region
|
||||
* to exit, reset timer when user is in one-handed mode.
|
||||
* Refer {@link OneHandedGestureHandler} to see start and stop one handed gesture
|
||||
*/
|
||||
public class OneHandedTouchHandler implements OneHandedTransitionCallback {
|
||||
private static final String TAG = "OneHandedTouchHandler";
|
||||
|
||||
@@ -28,7 +28,6 @@ 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;
|
||||
@@ -79,8 +78,6 @@ public class OneHandedControllerTest extends OneHandedTestCase {
|
||||
@Mock
|
||||
OneHandedTutorialHandler mMockTutorialHandler;
|
||||
@Mock
|
||||
OneHandedGestureHandler mMockGestureHandler;
|
||||
@Mock
|
||||
OneHandedSettingsUtil mMockSettingsUitl;
|
||||
@Mock
|
||||
OneHandedUiEventLogger mMockUiEventLogger;
|
||||
@@ -131,7 +128,6 @@ public class OneHandedControllerTest extends OneHandedTestCase {
|
||||
mMockDisplayAreaOrganizer,
|
||||
mMockTouchHandler,
|
||||
mMockTutorialHandler,
|
||||
mMockGestureHandler,
|
||||
mMockSettingsUitl,
|
||||
mOneHandedAccessibilityUtil,
|
||||
mSpiedTimeoutHandler,
|
||||
@@ -179,7 +175,6 @@ public class OneHandedControllerTest extends OneHandedTestCase {
|
||||
@Test
|
||||
public void testRegisterTransitionCallbackAfterInit() {
|
||||
verify(mMockDisplayAreaOrganizer).registerTransitionCallback(mMockTouchHandler);
|
||||
verify(mMockDisplayAreaOrganizer).registerTransitionCallback(mMockGestureHandler);
|
||||
verify(mMockDisplayAreaOrganizer).registerTransitionCallback(mMockTutorialHandler);
|
||||
}
|
||||
|
||||
@@ -205,7 +200,6 @@ public class OneHandedControllerTest extends OneHandedTestCase {
|
||||
mSpiedOneHandedController.setOneHandedEnabled(true);
|
||||
|
||||
verify(mMockTouchHandler, atLeastOnce()).onOneHandedEnabled(anyBoolean());
|
||||
verify(mMockGestureHandler, atLeastOnce()).onGestureEnabled(anyBoolean());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -213,7 +207,6 @@ public class OneHandedControllerTest extends OneHandedTestCase {
|
||||
mSpiedOneHandedController.setSwipeToNotificationEnabled(mDefaultSwipeToNotificationEnabled);
|
||||
|
||||
verify(mMockTouchHandler, atLeastOnce()).onOneHandedEnabled(anyBoolean());
|
||||
verify(mMockGestureHandler, atLeastOnce()).onGestureEnabled(anyBoolean());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -339,30 +332,6 @@ public class OneHandedControllerTest extends OneHandedTestCase {
|
||||
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);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStateActive_shortcutRequestActivate_skipActions() {
|
||||
when(mSpiedTransitionState.getState()).thenReturn(STATE_ACTIVE);
|
||||
|
||||
@@ -1,129 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.wm.shell.onehanded;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
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 androidx.test.filters.SmallTest;
|
||||
|
||||
import com.android.wm.shell.common.DisplayLayout;
|
||||
import com.android.wm.shell.common.ShellExecutor;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
@SmallTest
|
||||
@RunWith(AndroidTestingRunner.class)
|
||||
public class OneHandedGestureHandlerTest extends OneHandedTestCase {
|
||||
OneHandedGestureHandler mGestureHandler;
|
||||
DisplayLayout mDisplayLayout;
|
||||
@Mock
|
||||
DisplayLayout mMockDisplayLayout;
|
||||
@Mock
|
||||
ShellExecutor mMockShellMainExecutor;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
final int mockNavBarHeight = 100;
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mDisplayLayout = new DisplayLayout(mContext, mContext.getDisplay());
|
||||
mGestureHandler = new OneHandedGestureHandler(mContext, mDisplayLayout,
|
||||
ViewConfiguration.get(mTestContext), mMockShellMainExecutor);
|
||||
when(mMockDisplayLayout.navBarFrameHeight()).thenReturn(mockNavBarHeight);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetGestureEventListener() {
|
||||
OneHandedGestureHandler.OneHandedGestureEventCallback callback =
|
||||
new OneHandedGestureHandler.OneHandedGestureEventCallback() {
|
||||
@Override
|
||||
public void onStart() {}
|
||||
|
||||
@Override
|
||||
public void onStop() {}
|
||||
};
|
||||
|
||||
mGestureHandler.setGestureEventListener(callback);
|
||||
assertThat(mGestureHandler.mGestureEventCallback).isEqualTo(callback);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOneHandedDisabled_shouldDisposeInputChannel() {
|
||||
mGestureHandler.onGestureEnabled(false);
|
||||
|
||||
assertThat(mGestureHandler.mInputMonitor).isNull();
|
||||
assertThat(mGestureHandler.mInputEventReceiver).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testChangeNavBarToNon3Button_shouldDisposeInputChannel() {
|
||||
mGestureHandler.onGestureEnabled(true);
|
||||
mGestureHandler.onThreeButtonModeEnabled(false);
|
||||
|
||||
assertThat(mGestureHandler.mInputMonitor).isNull();
|
||||
assertThat(mGestureHandler.mInputEventReceiver).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOnlyHandleGestureInPortraitMode() {
|
||||
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());
|
||||
}
|
||||
}
|
||||
@@ -74,8 +74,6 @@ public class OneHandedStateTest extends OneHandedTestCase {
|
||||
@Mock
|
||||
OneHandedTutorialHandler mMockTutorialHandler;
|
||||
@Mock
|
||||
OneHandedGestureHandler mMockGestureHandler;
|
||||
@Mock
|
||||
OneHandedSettingsUtil mMockSettingsUitl;
|
||||
@Mock
|
||||
OneHandedUiEventLogger mMockUiEventLogger;
|
||||
@@ -126,7 +124,6 @@ public class OneHandedStateTest extends OneHandedTestCase {
|
||||
mMockDisplayAreaOrganizer,
|
||||
mMockTouchHandler,
|
||||
mMockTutorialHandler,
|
||||
mMockGestureHandler,
|
||||
mMockSettingsUitl,
|
||||
mOneHandedAccessibilityUtil,
|
||||
mSpiedTimeoutHandler,
|
||||
|
||||
@@ -43,8 +43,6 @@ public class OneHandedTutorialHandlerTest extends OneHandedTestCase {
|
||||
OneHandedController mOneHandedController;
|
||||
OneHandedState mSpiedTransitionState;
|
||||
|
||||
@Mock
|
||||
OneHandedGestureHandler mMockGestureHandler;
|
||||
@Mock
|
||||
OneHandedTouchHandler mMockTouchHandler;
|
||||
@Mock
|
||||
@@ -84,7 +82,6 @@ public class OneHandedTutorialHandlerTest extends OneHandedTestCase {
|
||||
mMockDisplayAreaOrganizer,
|
||||
mMockTouchHandler,
|
||||
mMockTutorialHandler,
|
||||
mMockGestureHandler,
|
||||
mMockSettingsUtil,
|
||||
mMockAccessibilityUtil,
|
||||
mTimeoutHandler,
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
package com.android.systemui.wmshell;
|
||||
|
||||
import static android.view.Display.DEFAULT_DISPLAY;
|
||||
import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON;
|
||||
|
||||
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BOUNCER_SHOWING;
|
||||
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BUBBLES_EXPANDED;
|
||||
@@ -35,7 +34,6 @@ import android.graphics.drawable.Drawable;
|
||||
import android.inputmethodservice.InputMethodService;
|
||||
import android.os.IBinder;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
import android.view.KeyEvent;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.keyguard.KeyguardUpdateMonitor;
|
||||
@@ -59,7 +57,6 @@ import com.android.wm.shell.hidedisplaycutout.HideDisplayCutout;
|
||||
import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
|
||||
import com.android.wm.shell.nano.WmShellTraceProto;
|
||||
import com.android.wm.shell.onehanded.OneHanded;
|
||||
import com.android.wm.shell.onehanded.OneHandedGestureHandler.OneHandedGestureEventCallback;
|
||||
import com.android.wm.shell.onehanded.OneHandedTransitionCallback;
|
||||
import com.android.wm.shell.onehanded.OneHandedUiEventLogger;
|
||||
import com.android.wm.shell.pip.Pip;
|
||||
@@ -230,10 +227,6 @@ public final class WMShell extends SystemUI
|
||||
|
||||
@VisibleForTesting
|
||||
void initOneHanded(OneHanded oneHanded) {
|
||||
int currentMode = mNavigationModeController.addListener(mode ->
|
||||
oneHanded.setThreeButtonModeEnabled(mode == NAV_BAR_MODE_3BUTTON));
|
||||
oneHanded.setThreeButtonModeEnabled(currentMode == NAV_BAR_MODE_3BUTTON);
|
||||
|
||||
oneHanded.registerTransitionCallback(new OneHandedTransitionCallback() {
|
||||
@Override
|
||||
public void onStartTransition(boolean isEntering) {
|
||||
@@ -260,32 +253,6 @@ public final class WMShell extends SystemUI
|
||||
}
|
||||
});
|
||||
|
||||
oneHanded.registerGestureCallback(new OneHandedGestureEventCallback() {
|
||||
@Override
|
||||
public void onStart() {
|
||||
mSysUiMainExecutor.execute(() -> {
|
||||
if (oneHanded.isOneHandedEnabled()) {
|
||||
oneHanded.startOneHanded();
|
||||
} else if (oneHanded.isSwipeToNotificationEnabled()) {
|
||||
mCommandQueue.handleSystemKey(KeyEvent.KEYCODE_SYSTEM_NAVIGATION_DOWN);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStop() {
|
||||
mSysUiMainExecutor.execute(() -> {
|
||||
if (oneHanded.isOneHandedEnabled()) {
|
||||
// Log metrics for 3-button navigation mode.
|
||||
oneHanded.stopOneHanded(
|
||||
OneHandedUiEventLogger.EVENT_ONE_HANDED_TRIGGER_GESTURE_OUT);
|
||||
} else if (oneHanded.isSwipeToNotificationEnabled()) {
|
||||
mCommandQueue.handleSystemKey(KeyEvent.KEYCODE_SYSTEM_NAVIGATION_UP);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
mOneHandedKeyguardCallback = new KeyguardUpdateMonitorCallback() {
|
||||
@Override
|
||||
public void onKeyguardBouncerChanged(boolean bouncer) {
|
||||
|
||||
@@ -37,7 +37,6 @@ import com.android.wm.shell.common.ShellExecutor;
|
||||
import com.android.wm.shell.hidedisplaycutout.HideDisplayCutout;
|
||||
import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
|
||||
import com.android.wm.shell.onehanded.OneHanded;
|
||||
import com.android.wm.shell.onehanded.OneHandedGestureHandler;
|
||||
import com.android.wm.shell.onehanded.OneHandedTransitionCallback;
|
||||
import com.android.wm.shell.pip.Pip;
|
||||
|
||||
@@ -106,11 +105,6 @@ public class WMShellTest extends SysuiTestCase {
|
||||
verify(mKeyguardUpdateMonitor).registerCallback(any(KeyguardUpdateMonitorCallback.class));
|
||||
verify(mCommandQueue).addCallback(any(CommandQueue.Callbacks.class));
|
||||
verify(mScreenLifecycle).addObserver(any(ScreenLifecycle.Observer.class));
|
||||
verify(mNavigationModeController).addListener(
|
||||
any(NavigationModeController.ModeChangedListener.class));
|
||||
|
||||
verify(mOneHanded).registerGestureCallback(any(
|
||||
OneHandedGestureHandler.OneHandedGestureEventCallback.class));
|
||||
verify(mOneHanded).registerTransitionCallback(any(OneHandedTransitionCallback.class));
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user