Merge "Use movement of the motion events on the screen instead of on the trackpad since they are proportional"

This commit is contained in:
Tracy Zhou
2023-02-09 21:01:41 +00:00
committed by Android (Google) Code Review
8 changed files with 17 additions and 326 deletions

View File

@@ -1,31 +0,0 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.systemui.plugins;
import android.view.MotionEvent;
/** Handles both trackpad and touch events and report displacements in both axis's. */
public interface MotionEventsHandlerBase {
void onMotionEvent(MotionEvent ev);
float getDisplacementX(MotionEvent ev);
float getDisplacementY(MotionEvent ev);
String dump();
}

View File

@@ -48,9 +48,6 @@ public interface NavigationEdgeBackPlugin extends Plugin {
/** Sets the base LayoutParams for the UI. */
void setLayoutParams(WindowManager.LayoutParams layoutParams);
/** Sets the motion events handler for the plugin. */
default void setMotionEventsHandler(MotionEventsHandlerBase motionEventsHandler) {}
/** Updates the UI based on the motion events passed in device coordinates. */
void onMotionEvent(MotionEvent motionEvent);

View File

@@ -36,7 +36,6 @@ import androidx.core.view.isVisible
import androidx.dynamicanimation.animation.DynamicAnimation
import com.android.internal.util.LatencyTracker
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.plugins.MotionEventsHandlerBase
import com.android.systemui.plugins.NavigationEdgeBackPlugin
import com.android.systemui.statusbar.VibratorHelper
import com.android.systemui.statusbar.policy.ConfigurationController
@@ -592,10 +591,6 @@ class BackPanelController internal constructor(
windowManager.addView(mView, layoutParams)
}
override fun setMotionEventsHandler(motionEventsHandler: MotionEventsHandlerBase?) {
// TODO(255697805): Integrate MotionEventHandler for trackpad.
}
private fun isDragAwayFromEdge(velocityPxPerSecThreshold: Int = 0) = velocityTracker!!.run {
computeCurrentVelocity(PX_PER_SEC)
val velocity = xVelocity.takeIf { mView.isLeftPanel } ?: (xVelocity * -1)
@@ -1048,4 +1043,4 @@ class Step<T>(
else -> startValue
}.also { previousValue = it }
}
}
}

View File

@@ -18,7 +18,6 @@ package com.android.systemui.navigationbar.gestural;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_EXCLUDE_FROM_SCREEN_MAGNIFICATION;
import static com.android.systemui.classifier.Classifier.BACK_GESTURE;
import static com.android.systemui.navigationbar.gestural.Utilities.getTrackpadScale;
import static com.android.systemui.navigationbar.gestural.Utilities.isTrackpadMotionEvent;
import android.annotation.NonNull;
@@ -272,7 +271,6 @@ public class EdgeBackGestureHandler implements PluginListener<NavigationEdgeBack
private LogArray mGestureLogOutsideInsets = new LogArray(MAX_NUM_LOGGED_GESTURES);
private final GestureNavigationSettingsObserver mGestureNavigationSettingsObserver;
private final MotionEventsHandler mMotionEventsHandler;
private final NavigationEdgeBackPlugin.BackCallback mBackCallback =
new NavigationEdgeBackPlugin.BackCallback() {
@@ -404,7 +402,6 @@ public class EdgeBackGestureHandler implements PluginListener<NavigationEdgeBack
mGestureNavigationSettingsObserver = new GestureNavigationSettingsObserver(
mContext.getMainThreadHandler(), mContext, this::onNavigationSettingsChanged);
mMotionEventsHandler = new MotionEventsHandler(featureFlags, getTrackpadScale(context));
updateCurrentUserResources();
}
@@ -624,7 +621,6 @@ public class EdgeBackGestureHandler implements PluginListener<NavigationEdgeBack
Trace.beginSection("setEdgeBackPlugin");
mEdgeBackPlugin = edgeBackPlugin;
mEdgeBackPlugin.setBackCallback(mBackCallback);
mEdgeBackPlugin.setMotionEventsHandler(mMotionEventsHandler);
mEdgeBackPlugin.setLayoutParams(createLayoutParams());
updateDisplaySize();
} finally {
@@ -871,7 +867,7 @@ public class EdgeBackGestureHandler implements PluginListener<NavigationEdgeBack
}
private void onMotionEvent(MotionEvent ev) {
mMotionEventsHandler.onMotionEvent(ev);
boolean isTrackpadEvent = isTrackpadMotionEvent(mIsTrackpadGestureBackEnabled, ev);
int action = ev.getActionMasked();
if (action == MotionEvent.ACTION_DOWN) {
if (DEBUG_MISSING_GESTURE) {
@@ -881,7 +877,6 @@ public class EdgeBackGestureHandler implements PluginListener<NavigationEdgeBack
// Verify if this is in within the touch region and we aren't in immersive mode, and
// either the bouncer is showing or the notification panel is hidden
mInputEventReceiver.setBatchingEnabled(false);
boolean isTrackpadEvent = isTrackpadMotionEvent(mIsTrackpadGestureBackEnabled, ev);
if (isTrackpadEvent) {
// TODO: show the back arrow based on the direction of the swipe.
mIsOnLeftEdge = false;
@@ -921,7 +916,7 @@ public class EdgeBackGestureHandler implements PluginListener<NavigationEdgeBack
if (!mThresholdCrossed) {
mEndPoint.x = (int) ev.getX();
mEndPoint.y = (int) ev.getY();
if (action == MotionEvent.ACTION_POINTER_DOWN) {
if (action == MotionEvent.ACTION_POINTER_DOWN && !isTrackpadEvent) {
if (mAllowGesture) {
logGesture(SysUiStatsLog.BACK_GESTURE__TYPE__INCOMPLETE_MULTI_TOUCH);
if (DEBUG_MISSING_GESTURE) {
@@ -947,8 +942,8 @@ public class EdgeBackGestureHandler implements PluginListener<NavigationEdgeBack
mLogGesture = false;
return;
}
float dx = Math.abs(mMotionEventsHandler.getDisplacementX(ev));
float dy = Math.abs(mMotionEventsHandler.getDisplacementY(ev));
float dx = Math.abs(ev.getX() - mDownPoint.x);
float dy = Math.abs(ev.getY() - mDownPoint.y);
if (dy > dx && dy > mTouchSlop) {
if (mAllowGesture) {
logGesture(SysUiStatsLog.BACK_GESTURE__TYPE__INCOMPLETE_VERTICAL_MOVE);
@@ -1086,7 +1081,6 @@ public class EdgeBackGestureHandler implements PluginListener<NavigationEdgeBack
pw.println(" mGestureLogInsideInsets=" + String.join("\n", mGestureLogInsideInsets));
pw.println(" mGestureLogOutsideInsets=" + String.join("\n", mGestureLogOutsideInsets));
pw.println(" mEdgeBackPlugin=" + mEdgeBackPlugin);
pw.println(" mMotionEventsHandler=" + mMotionEventsHandler);
if (mEdgeBackPlugin != null) {
mEdgeBackPlugin.dump(pw);
}

View File

@@ -1,114 +0,0 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.systemui.navigationbar.gestural;
import static android.view.MotionEvent.AXIS_GESTURE_X_OFFSET;
import static android.view.MotionEvent.AXIS_GESTURE_Y_OFFSET;
import static com.android.systemui.navigationbar.gestural.Utilities.isTrackpadMotionEvent;
import android.graphics.PointF;
import android.view.MotionEvent;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.Flags;
import com.android.systemui.plugins.MotionEventsHandlerBase;
/** Handles both trackpad and touch events and report displacements in both axis's. */
public class MotionEventsHandler implements MotionEventsHandlerBase {
private final boolean mIsTrackpadGestureBackEnabled;
private final int mScale;
private final PointF mDownPos = new PointF();
private final PointF mLastPos = new PointF();
private float mCurrentTrackpadOffsetX = 0;
private float mCurrentTrackpadOffsetY = 0;
public MotionEventsHandler(FeatureFlags featureFlags, int scale) {
mIsTrackpadGestureBackEnabled = featureFlags.isEnabled(Flags.TRACKPAD_GESTURE_BACK);
mScale = scale;
}
@Override
public void onMotionEvent(MotionEvent ev) {
switch (ev.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
onActionDown(ev);
break;
case MotionEvent.ACTION_MOVE:
onActionMove(ev);
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
onActionUp(ev);
break;
default:
break;
}
}
private void onActionDown(MotionEvent ev) {
reset();
if (!isTrackpadMotionEvent(mIsTrackpadGestureBackEnabled, ev)) {
mDownPos.set(ev.getX(), ev.getY());
mLastPos.set(mDownPos);
}
}
private void onActionMove(MotionEvent ev) {
updateMovements(ev);
}
private void onActionUp(MotionEvent ev) {
updateMovements(ev);
}
private void updateMovements(MotionEvent ev) {
if (isTrackpadMotionEvent(mIsTrackpadGestureBackEnabled, ev)) {
mCurrentTrackpadOffsetX += ev.getAxisValue(AXIS_GESTURE_X_OFFSET) * mScale;
mCurrentTrackpadOffsetY += ev.getAxisValue(AXIS_GESTURE_Y_OFFSET) * mScale;
} else {
mLastPos.set(ev.getX(), ev.getY());
}
}
private void reset() {
mDownPos.set(0, 0);
mLastPos.set(0, 0);
mCurrentTrackpadOffsetX = 0;
mCurrentTrackpadOffsetY = 0;
}
@Override
public float getDisplacementX(MotionEvent ev) {
return isTrackpadMotionEvent(mIsTrackpadGestureBackEnabled, ev) ? mCurrentTrackpadOffsetX
: mLastPos.x - mDownPos.x;
}
@Override
public float getDisplacementY(MotionEvent ev) {
return isTrackpadMotionEvent(mIsTrackpadGestureBackEnabled, ev) ? mCurrentTrackpadOffsetY
: mLastPos.y - mDownPos.y;
}
@Override
public String dump() {
return "mDownPos: " + mDownPos + ", mLastPos: " + mLastPos + ", mCurrentTrackpadOffsetX: "
+ mCurrentTrackpadOffsetX + ", mCurrentTrackpadOffsetY: " + mCurrentTrackpadOffsetY;
}
}

View File

@@ -53,7 +53,6 @@ import com.android.settingslib.Utils;
import com.android.systemui.R;
import com.android.systemui.animation.Interpolators;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.plugins.MotionEventsHandlerBase;
import com.android.systemui.plugins.NavigationEdgeBackPlugin;
import com.android.systemui.settings.DisplayTracker;
import com.android.systemui.shared.navigationbar.RegionSamplingHelper;
@@ -200,6 +199,8 @@ public class NavigationBarEdgePanel extends View implements NavigationEdgeBackPl
*/
private boolean mIsLeftPanel;
private float mStartX;
private float mStartY;
private float mCurrentAngle;
/**
* The current translation of the arrow
@@ -230,8 +231,6 @@ public class NavigationBarEdgePanel extends View implements NavigationEdgeBackPl
private final Handler mHandler = new Handler();
private final Runnable mFailsafeRunnable = this::onFailsafe;
private MotionEventsHandlerBase mMotionEventsHandler;
private DynamicAnimation.OnAnimationEndListener mSetGoneEndListener
= new DynamicAnimation.OnAnimationEndListener() {
@Override
@@ -438,11 +437,6 @@ public class NavigationBarEdgePanel extends View implements NavigationEdgeBackPl
mWindowManager.addView(this, mLayoutParams);
}
@Override
public void setMotionEventsHandler(MotionEventsHandlerBase motionEventsHandler) {
mMotionEventsHandler = motionEventsHandler;
}
/**
* Adjusts the sampling rect to conform to the actual visible bounding box of the arrow.
*/
@@ -487,6 +481,8 @@ public class NavigationBarEdgePanel extends View implements NavigationEdgeBackPl
case MotionEvent.ACTION_DOWN:
mDragSlopPassed = false;
resetOnDown();
mStartX = event.getX();
mStartY = event.getY();
setVisibility(VISIBLE);
updatePosition(event.getY());
mRegionSamplingHelper.start(mSamplingRect);
@@ -730,9 +726,10 @@ public class NavigationBarEdgePanel extends View implements NavigationEdgeBackPl
}
private void handleMoveEvent(MotionEvent event) {
float xOffset = mMotionEventsHandler.getDisplacementX(event);
float touchTranslation = MathUtils.abs(xOffset);
float yOffset = mMotionEventsHandler.getDisplacementY(event);
float x = event.getX();
float y = event.getY();
float touchTranslation = MathUtils.abs(x - mStartX);
float yOffset = y - mStartY;
float delta = touchTranslation - mPreviousTouchTranslation;
if (Math.abs(delta) > 0) {
if (Math.signum(delta) == Math.signum(mTotalTouchDelta)) {
@@ -793,14 +790,16 @@ public class NavigationBarEdgePanel extends View implements NavigationEdgeBackPl
}
// Last if the direction in Y is bigger than X * 2 we also abort
if (Math.abs(yOffset) > Math.abs(xOffset) * 2) {
if (Math.abs(yOffset) > Math.abs(x - mStartX) * 2) {
triggerBack = false;
}
if (DEBUG_MISSING_GESTURE && mTriggerBack != triggerBack) {
Log.d(DEBUG_MISSING_GESTURE_TAG, "set mTriggerBack=" + triggerBack
+ ", mTotalTouchDelta=" + mTotalTouchDelta
+ ", mMinDeltaForSwitch=" + mMinDeltaForSwitch
+ ", yOffset=" + yOffset + mMotionEventsHandler.dump());
+ ", yOffset=" + yOffset
+ ", x=" + x
+ ", mStartX=" + mStartX);
}
setTriggerBack(triggerBack, true /* animated */);

View File

@@ -18,21 +18,13 @@ package com.android.systemui.navigationbar.gestural;
import static android.view.MotionEvent.CLASSIFICATION_MULTI_FINGER_SWIPE;
import android.content.Context;
import android.view.MotionEvent;
import android.view.ViewConfiguration;
public final class Utilities {
private static final int TRACKPAD_GESTURE_SCALE = 200;
public static boolean isTrackpadMotionEvent(boolean isTrackpadGestureBackEnabled,
MotionEvent event) {
return isTrackpadGestureBackEnabled
&& event.getClassification() == CLASSIFICATION_MULTI_FINGER_SWIPE;
}
public static int getTrackpadScale(Context context) {
return ViewConfiguration.get(context).getScaledTouchSlop() * TRACKPAD_GESTURE_SCALE;
}
}

View File

@@ -1,141 +0,0 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.systemui.navigationbar.gestural;
import static android.view.InputDevice.SOURCE_MOUSE;
import static android.view.MotionEvent.AXIS_GESTURE_X_OFFSET;
import static android.view.MotionEvent.AXIS_GESTURE_Y_OFFSET;
import static android.view.MotionEvent.CLASSIFICATION_MULTI_FINGER_SWIPE;
import static com.google.common.truth.Truth.assertThat;
import android.view.MotionEvent;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.flags.FakeFeatureFlags;
import com.android.systemui.flags.Flags;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
/**
* Tests for {@link MotionEventsHandler}.
*/
@RunWith(AndroidJUnit4.class)
@SmallTest
public class MotionEventsHandlerTest extends SysuiTestCase {
private final FakeFeatureFlags mFeatureFlags = new FakeFeatureFlags();
private static int SCALE = 100;
private MotionEventsHandler mMotionEventsHandler;
@Before
public void setUp() {
mFeatureFlags.set(Flags.TRACKPAD_GESTURE_BACK, true);
mMotionEventsHandler = new MotionEventsHandler(mFeatureFlags, SCALE);
}
@Test
public void onTouchEvent_touchScreen_hasCorrectDisplacements() {
MotionEvent down = MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 100, 100, 0);
MotionEvent move1 = MotionEvent.obtain(0, 1, MotionEvent.ACTION_MOVE, 150, 125, 0);
MotionEvent move2 = MotionEvent.obtain(0, 2, MotionEvent.ACTION_MOVE, 200, 150, 0);
MotionEvent up = MotionEvent.obtain(0, 3, MotionEvent.ACTION_UP, 250, 175, 0);
mMotionEventsHandler.onMotionEvent(down);
mMotionEventsHandler.onMotionEvent(move1);
assertThat(mMotionEventsHandler.getDisplacementX(move1)).isEqualTo(50);
assertThat(mMotionEventsHandler.getDisplacementY(move1)).isEqualTo(25);
mMotionEventsHandler.onMotionEvent(move2);
assertThat(mMotionEventsHandler.getDisplacementX(move2)).isEqualTo(100);
assertThat(mMotionEventsHandler.getDisplacementY(move2)).isEqualTo(50);
mMotionEventsHandler.onMotionEvent(up);
assertThat(mMotionEventsHandler.getDisplacementX(up)).isEqualTo(150);
assertThat(mMotionEventsHandler.getDisplacementY(up)).isEqualTo(75);
}
@Test
public void onTouchEvent_trackpad_hasCorrectDisplacements() {
MotionEvent.PointerCoords[] downPointerCoords = new MotionEvent.PointerCoords[1];
downPointerCoords[0] = new MotionEvent.PointerCoords();
downPointerCoords[0].setAxisValue(AXIS_GESTURE_X_OFFSET, 0.1f);
downPointerCoords[0].setAxisValue(AXIS_GESTURE_Y_OFFSET, 0.1f);
MotionEvent.PointerProperties[] downPointerProperties =
new MotionEvent.PointerProperties[1];
downPointerProperties[0] = new MotionEvent.PointerProperties();
downPointerProperties[0].id = 1;
downPointerProperties[0].toolType = MotionEvent.TOOL_TYPE_FINGER;
MotionEvent down = MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 1,
downPointerProperties, downPointerCoords, 0, 0, 1.0f, 1.0f, 0, 0, SOURCE_MOUSE,
0, 0, CLASSIFICATION_MULTI_FINGER_SWIPE);
MotionEvent.PointerCoords[] movePointerCoords1 = new MotionEvent.PointerCoords[1];
movePointerCoords1[0] = new MotionEvent.PointerCoords();
movePointerCoords1[0].setAxisValue(AXIS_GESTURE_X_OFFSET, 0.2f);
movePointerCoords1[0].setAxisValue(AXIS_GESTURE_Y_OFFSET, 0.1f);
MotionEvent.PointerProperties[] movePointerProperties1 =
new MotionEvent.PointerProperties[1];
movePointerProperties1[0] = new MotionEvent.PointerProperties();
movePointerProperties1[0].id = 1;
movePointerProperties1[0].toolType = MotionEvent.TOOL_TYPE_FINGER;
MotionEvent move1 = MotionEvent.obtain(0, 1, MotionEvent.ACTION_MOVE, 1,
movePointerProperties1, movePointerCoords1, 0, 0, 1.0f, 1.0f, 0, 0, SOURCE_MOUSE,
0, 0, CLASSIFICATION_MULTI_FINGER_SWIPE);
MotionEvent.PointerCoords[] movePointerCoords2 = new MotionEvent.PointerCoords[1];
movePointerCoords2[0] = new MotionEvent.PointerCoords();
movePointerCoords2[0].setAxisValue(AXIS_GESTURE_X_OFFSET, 0.1f);
movePointerCoords2[0].setAxisValue(AXIS_GESTURE_Y_OFFSET, 0.4f);
MotionEvent.PointerProperties[] movePointerProperties2 =
new MotionEvent.PointerProperties[1];
movePointerProperties2[0] = new MotionEvent.PointerProperties();
movePointerProperties2[0].id = 1;
movePointerProperties2[0].toolType = MotionEvent.TOOL_TYPE_FINGER;
MotionEvent move2 = MotionEvent.obtain(0, 2, MotionEvent.ACTION_MOVE, 1,
movePointerProperties2, movePointerCoords2, 0, 0, 1.0f, 1.0f, 0, 0, SOURCE_MOUSE,
0, 0, CLASSIFICATION_MULTI_FINGER_SWIPE);
MotionEvent.PointerCoords[] upPointerCoords = new MotionEvent.PointerCoords[1];
upPointerCoords[0] = new MotionEvent.PointerCoords();
upPointerCoords[0].setAxisValue(AXIS_GESTURE_X_OFFSET, 0.1f);
upPointerCoords[0].setAxisValue(AXIS_GESTURE_Y_OFFSET, 0.1f);
MotionEvent.PointerProperties[] upPointerProperties2 =
new MotionEvent.PointerProperties[1];
upPointerProperties2[0] = new MotionEvent.PointerProperties();
upPointerProperties2[0].id = 1;
upPointerProperties2[0].toolType = MotionEvent.TOOL_TYPE_FINGER;
MotionEvent up = MotionEvent.obtain(0, 2, MotionEvent.ACTION_UP, 1,
upPointerProperties2, upPointerCoords, 0, 0, 1.0f, 1.0f, 0, 0, SOURCE_MOUSE,
0, 0, CLASSIFICATION_MULTI_FINGER_SWIPE);
mMotionEventsHandler.onMotionEvent(down);
mMotionEventsHandler.onMotionEvent(move1);
assertThat(mMotionEventsHandler.getDisplacementX(move1)).isEqualTo(20f);
assertThat(mMotionEventsHandler.getDisplacementY(move1)).isEqualTo(10f);
mMotionEventsHandler.onMotionEvent(move2);
assertThat(mMotionEventsHandler.getDisplacementX(move2)).isEqualTo(30f);
assertThat(mMotionEventsHandler.getDisplacementY(move2)).isEqualTo(50f);
mMotionEventsHandler.onMotionEvent(up);
assertThat(mMotionEventsHandler.getDisplacementX(up)).isEqualTo(40f);
assertThat(mMotionEventsHandler.getDisplacementY(up)).isEqualTo(60f);
}
}