Support for OnBackAnimationCallback: added for 3-button navigation / hardware keys
The callback can be called as follows if it supports the `onBackStarted()` and `onBackCancelled()` methods: - `onBackStarted()` is called when the back button is pressed (`ACTION_DOWN`) and `keyEvent.getRepeatCount()` is `0`. - `onBackCancelled()` is called when the back button is released (`ACTION_UP`) and the `keyEvent.isCanceled()` is `true`. - `onBackInvoked()` is called when the back button is released (`ACTION_UP`) and the `keyEvent.isCanceled()` is `false`. Test: atest OnBackInvokedCallbackGestureTest Bug: 278634019 Change-Id: Iba5a27e68607ce33c38dbbc818d66e8753688761
This commit is contained in:
@@ -200,8 +200,10 @@ import android.view.contentcapture.MainContentCaptureSession;
|
||||
import android.view.inputmethod.ImeTracker;
|
||||
import android.view.inputmethod.InputMethodManager;
|
||||
import android.widget.Scroller;
|
||||
import android.window.BackEvent;
|
||||
import android.window.ClientWindowFrames;
|
||||
import android.window.CompatOnBackInvokedCallback;
|
||||
import android.window.OnBackAnimationCallback;
|
||||
import android.window.OnBackInvokedCallback;
|
||||
import android.window.OnBackInvokedDispatcher;
|
||||
import android.window.ScreenCapture;
|
||||
@@ -6508,6 +6510,7 @@ public final class ViewRootImpl implements ViewParent,
|
||||
*/
|
||||
final class NativePreImeInputStage extends AsyncInputStage
|
||||
implements InputQueue.FinishedInputEventCallback {
|
||||
|
||||
public NativePreImeInputStage(InputStage next, String traceCounter) {
|
||||
super(next, traceCounter);
|
||||
}
|
||||
@@ -6515,32 +6518,62 @@ public final class ViewRootImpl implements ViewParent,
|
||||
@Override
|
||||
protected int onProcess(QueuedInputEvent q) {
|
||||
if (q.mEvent instanceof KeyEvent) {
|
||||
final KeyEvent event = (KeyEvent) q.mEvent;
|
||||
final KeyEvent keyEvent = (KeyEvent) q.mEvent;
|
||||
|
||||
// If the new back dispatch is enabled, intercept KEYCODE_BACK before it reaches the
|
||||
// view tree or IME, and invoke the appropriate {@link OnBackInvokedCallback}.
|
||||
if (isBack(event)
|
||||
if (isBack(keyEvent)
|
||||
&& mContext != null
|
||||
&& mOnBackInvokedDispatcher.isOnBackInvokedCallbackEnabled()) {
|
||||
OnBackInvokedCallback topCallback =
|
||||
getOnBackInvokedDispatcher().getTopCallback();
|
||||
if (event.getAction() == KeyEvent.ACTION_UP) {
|
||||
if (topCallback != null) {
|
||||
return doOnBackKeyEvent(keyEvent);
|
||||
}
|
||||
|
||||
if (mInputQueue != null) {
|
||||
mInputQueue.sendInputEvent(q.mEvent, q, true, this);
|
||||
return DEFER;
|
||||
}
|
||||
}
|
||||
return FORWARD;
|
||||
}
|
||||
|
||||
private int doOnBackKeyEvent(KeyEvent keyEvent) {
|
||||
OnBackInvokedCallback topCallback = getOnBackInvokedDispatcher().getTopCallback();
|
||||
if (topCallback instanceof OnBackAnimationCallback) {
|
||||
final OnBackAnimationCallback animationCallback =
|
||||
(OnBackAnimationCallback) topCallback;
|
||||
switch (keyEvent.getAction()) {
|
||||
case KeyEvent.ACTION_DOWN:
|
||||
// ACTION_DOWN is emitted twice: once when the user presses the button,
|
||||
// and again a few milliseconds later.
|
||||
// Based on the result of `keyEvent.getRepeatCount()` we have:
|
||||
// - 0 means the button was pressed.
|
||||
// - 1 means the button continues to be pressed (long press).
|
||||
if (keyEvent.getRepeatCount() == 0) {
|
||||
animationCallback.onBackStarted(
|
||||
new BackEvent(0, 0, 0f, BackEvent.EDGE_LEFT));
|
||||
}
|
||||
break;
|
||||
case KeyEvent.ACTION_UP:
|
||||
if (keyEvent.isCanceled()) {
|
||||
animationCallback.onBackCancelled();
|
||||
} else {
|
||||
topCallback.onBackInvoked();
|
||||
return FINISH_HANDLED;
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else if (topCallback != null) {
|
||||
if (keyEvent.getAction() == KeyEvent.ACTION_UP) {
|
||||
if (!keyEvent.isCanceled()) {
|
||||
topCallback.onBackInvoked();
|
||||
return FINISH_HANDLED;
|
||||
} else {
|
||||
// Drop other actions such as {@link KeyEvent.ACTION_DOWN}.
|
||||
return FINISH_NOT_HANDLED;
|
||||
Log.d(mTag, "Skip onBackInvoked(), reason: keyEvent.isCanceled=true");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (mInputQueue != null && q.mEvent instanceof KeyEvent) {
|
||||
mInputQueue.sendInputEvent(q.mEvent, q, true, this);
|
||||
return DEFER;
|
||||
}
|
||||
return FORWARD;
|
||||
return FINISH_NOT_HANDLED;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
Reference in New Issue
Block a user