Create BackEvent interface for back navigation parameters.

Bug: b/210539672, b/195946584
Test: m -j
Change-Id: I0264d0995aed8a73563bece0d15d2a9aac0ebf06
This commit is contained in:
Shan Huang
2022-01-31 20:41:17 +00:00
parent 56fc3f5e5c
commit a39fa74923
10 changed files with 219 additions and 23 deletions

View File

@@ -18,6 +18,7 @@ package android.view;
import android.app.Activity;
import android.app.Dialog;
import android.window.BackEvent;
/**
* Interface for applications to register back invocation callbacks. This allows the client
@@ -46,14 +47,12 @@ public interface OnBackInvokedCallback {
/**
* Called on back gesture progress.
*
* @param touchX Absolute X location of the touch point.
* @param touchY Absolute Y location of the touch point.
* @param progress Value between 0 and 1 on how far along the back gesture is.
* @param backEvent An {@link android.window.BackEvent} object describing the progress event.
*
* @see android.window.BackEvent
* @hide
*/
// TODO(b/210539672): combine back progress params into BackEvent.
default void onBackProgressed(int touchX, int touchY, float progress) { };
default void onBackProgressed(BackEvent backEvent) { };
/**
* Called when a back gesture or back button press has been cancelled.

View File

@@ -0,0 +1,22 @@
/*
* 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 android.window;
/**
* @hide
*/
parcelable BackEvent;

View File

@@ -0,0 +1,159 @@
/*
* 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 android.window;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.Parcel;
import android.os.Parcelable;
import android.view.RemoteAnimationTarget;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
* Represents an event that is sent out by the system during back navigation gesture.
* Holds information about the touch event, swipe direction and overall progress of the gesture
* interaction.
*
* @hide
*/
public class BackEvent implements Parcelable {
/** Indicates that the edge swipe starts from the left edge of the screen */
public static final int EDGE_LEFT = 0;
/** Indicates that the edge swipe starts from the right edge of the screen */
public static final int EDGE_RIGHT = 1;
@IntDef({
EDGE_LEFT,
EDGE_RIGHT,
})
@Retention(RetentionPolicy.SOURCE)
public @interface SwipeEdge{}
private final int mTouchX;
private final int mTouchY;
private final float mProgress;
@SwipeEdge
private final int mSwipeEdge;
@Nullable
private final RemoteAnimationTarget mDepartingAnimationTarget;
/**
* Creates a new {@link BackEvent} instance.
*
* @param touchX Absolute X location of the touch point.
* @param touchY Absolute Y location of the touch point.
* @param progress Value between 0 and 1 on how far along the back gesture is.
* @param swipeEdge Indicates which edge the swipe starts from.
* @param departingAnimationTarget The remote animation target of the departing application
* window.
*/
public BackEvent(int touchX, int touchY, float progress, @SwipeEdge int swipeEdge,
@Nullable RemoteAnimationTarget departingAnimationTarget) {
mTouchX = touchX;
mTouchY = touchY;
mProgress = progress;
mSwipeEdge = swipeEdge;
mDepartingAnimationTarget = departingAnimationTarget;
}
private BackEvent(@NonNull Parcel in) {
mTouchX = in.readInt();
mTouchY = in.readInt();
mProgress = in.readFloat();
mSwipeEdge = in.readInt();
mDepartingAnimationTarget = in.readTypedObject(RemoteAnimationTarget.CREATOR);
}
public static final Creator<BackEvent> CREATOR = new Creator<BackEvent>() {
@Override
public BackEvent createFromParcel(Parcel in) {
return new BackEvent(in);
}
@Override
public BackEvent[] newArray(int size) {
return new BackEvent[size];
}
};
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeInt(mTouchX);
dest.writeInt(mTouchY);
dest.writeFloat(mProgress);
dest.writeInt(mSwipeEdge);
dest.writeTypedObject(mDepartingAnimationTarget, flags);
}
/**
* Returns a value between 0 and 1 on how far along the back gesture is.
*/
public float getProgress() {
return mProgress;
}
/**
* Returns the absolute X location of the touch point.
*/
public int getTouchX() {
return mTouchX;
}
/**
* Returns the absolute Y location of the touch point.
*/
public int getTouchY() {
return mTouchY;
}
/**
* Returns the screen edge that the swipe starts from.
*/
public int getSwipeEdge() {
return mSwipeEdge;
}
/**
* Returns the {@link RemoteAnimationTarget} of the top departing application window,
* or {@code null} if the top window should not be moved for the current type of back
* destination.
*/
@Nullable
public RemoteAnimationTarget getDepartingAnimationTarget() {
return mDepartingAnimationTarget;
}
@Override
public String toString() {
return "BackEvent{"
+ "mTouchX=" + mTouchX
+ ", mTouchY=" + mTouchY
+ ", mProgress=" + mProgress
+ ", mSwipeEdge" + mSwipeEdge
+ ", mDepartingAnimationTarget" + mDepartingAnimationTarget
+ "}";
}
}

View File

@@ -17,6 +17,8 @@
package android.window;
import android.window.BackEvent;
/**
* Interface that wraps a {@link OnBackInvokedCallback} object, to be stored in window manager
* and called from back handling process when back is invoked.
@@ -38,7 +40,7 @@ oneway interface IOnBackInvokedCallback {
* @param touchY Absolute Y location of the touch point.
* @param progress Value between 0 and 1 on how far along the back gesture is.
*/
void onBackProgressed(int touchX, int touchY, float progress);
void onBackProgressed(in BackEvent backEvent);
/**
* Called when a back gesture or back button press has been cancelled.

View File

@@ -202,9 +202,9 @@ public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher {
}
@Override
public void onBackProgressed(int touchX, int touchY, float progress)
public void onBackProgressed(BackEvent backEvent)
throws RemoteException {
Handler.getMain().post(() -> mCallback.onBackProgressed(touchX, touchY, progress));
Handler.getMain().post(() -> mCallback.onBackProgressed(backEvent));
}
@Override

View File

@@ -17,6 +17,7 @@
package com.android.wm.shell.back;
import android.view.MotionEvent;
import android.window.BackEvent;
import com.android.wm.shell.common.annotations.ExternalThread;
@@ -29,7 +30,7 @@ public interface BackAnimation {
/**
* Called when a {@link MotionEvent} is generated by a back gesture.
*/
void onBackMotion(MotionEvent event);
void onBackMotion(MotionEvent event, @BackEvent.SwipeEdge int swipeEdge);
/**
* Sets whether the back gesture is past the trigger threshold or not.

View File

@@ -36,6 +36,7 @@ import android.os.SystemProperties;
import android.util.Log;
import android.view.MotionEvent;
import android.view.SurfaceControl;
import android.window.BackEvent;
import android.window.BackNavigationInfo;
import android.window.IOnBackInvokedCallback;
@@ -127,8 +128,8 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
}
@Override
public void onBackMotion(MotionEvent event) {
mShellExecutor.execute(() -> onMotionEvent(event));
public void onBackMotion(MotionEvent event, @BackEvent.SwipeEdge int swipeEdge) {
mShellExecutor.execute(() -> onMotionEvent(event, swipeEdge));
}
@Override
@@ -183,12 +184,12 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
* Called when a new motion event needs to be transferred to this
* {@link BackAnimationController}
*/
public void onMotionEvent(MotionEvent event) {
public void onMotionEvent(MotionEvent event, @BackEvent.SwipeEdge int swipeEdge) {
int action = event.getActionMasked();
if (action == MotionEvent.ACTION_DOWN) {
initAnimation(event);
} else if (action == MotionEvent.ACTION_MOVE) {
onMove(event);
onMove(event, swipeEdge);
} else if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
onGestureFinished();
}
@@ -264,7 +265,7 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
mTransaction.setVisibility(screenshotSurface, true);
}
private void onMove(MotionEvent event) {
private void onMove(MotionEvent event, @BackEvent.SwipeEdge int swipeEdge) {
if (!mBackGestureStarted || mBackNavigationInfo == null) {
return;
}

View File

@@ -30,6 +30,7 @@ import android.os.RemoteException;
import android.testing.AndroidTestingRunner;
import android.view.MotionEvent;
import android.view.SurfaceControl;
import android.window.BackEvent;
import android.window.BackNavigationInfo;
import androidx.test.filters.SmallTest;
@@ -94,7 +95,9 @@ public class BackAnimationControllerTest {
SurfaceControl screenshotSurface = new SurfaceControl();
HardwareBuffer hardwareBuffer = mock(HardwareBuffer.class);
createNavigationInfo(topWindowLeash, screenshotSurface, hardwareBuffer);
mController.onMotionEvent(MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 0, 0, 0));
mController.onMotionEvent(
MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 0, 0, 0),
BackEvent.EDGE_LEFT);
verify(mTransaction).setBuffer(screenshotSurface, hardwareBuffer);
verify(mTransaction).setVisibility(screenshotSurface, true);
verify(mTransaction).apply();
@@ -106,8 +109,12 @@ public class BackAnimationControllerTest {
SurfaceControl screenshotSurface = new SurfaceControl();
HardwareBuffer hardwareBuffer = mock(HardwareBuffer.class);
createNavigationInfo(topWindowLeash, screenshotSurface, hardwareBuffer);
mController.onMotionEvent(MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 0, 0, 0));
mController.onMotionEvent(MotionEvent.obtain(10, 0, MotionEvent.ACTION_MOVE, 100, 100, 0));
mController.onMotionEvent(
MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 0, 0, 0),
BackEvent.EDGE_LEFT);
mController.onMotionEvent(
MotionEvent.obtain(10, 0, MotionEvent.ACTION_MOVE, 100, 100, 0),
BackEvent.EDGE_LEFT);
verify(mTransaction).setPosition(topWindowLeash, 100, 100);
verify(mTransaction, atLeastOnce()).apply();
}

View File

@@ -263,11 +263,14 @@ public class EdgeBackGestureHandler extends CurrentUserTracker
// Notify FalsingManager that an intentional gesture has occurred.
// TODO(b/186519446): use a different method than isFalseTouch
mFalsingManager.isFalseTouch(BACK_GESTURE);
boolean sendDown = sendEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_BACK);
boolean sendUp = sendEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_BACK);
if (DEBUG_MISSING_GESTURE) {
Log.d(DEBUG_MISSING_GESTURE_TAG, "Triggered back: down=" + sendDown
+ ", up=" + sendUp);
// Only inject back keycodes when ahead-of-time back dispatching is disabled.
if (mBackAnimation == null) {
boolean sendDown = sendEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_BACK);
boolean sendUp = sendEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_BACK);
if (DEBUG_MISSING_GESTURE) {
Log.d(DEBUG_MISSING_GESTURE_TAG, "Triggered back: down="
+ sendDown + ", up=" + sendUp);
}
}
mOverviewProxyService.notifyBackAction(true, (int) mDownPoint.x,

View File

@@ -43,6 +43,7 @@ import android.view.View;
import android.view.WindowManager;
import android.view.animation.Interpolator;
import android.view.animation.PathInterpolator;
import android.window.BackEvent;
import androidx.core.graphics.ColorUtils;
import androidx.dynamicanimation.animation.DynamicAnimation;
@@ -464,7 +465,8 @@ public class NavigationBarEdgePanel extends View implements NavigationEdgeBackPl
@Override
public void onMotionEvent(MotionEvent event) {
if (mBackAnimation != null) {
mBackAnimation.onBackMotion(event);
mBackAnimation.onBackMotion(
event, mIsLeftPanel ? BackEvent.EDGE_LEFT : BackEvent.EDGE_RIGHT);
}
if (mVelocityTracker == null) {
mVelocityTracker = VelocityTracker.obtain();