Loading core/java/android/view/ViewGroup.java +5 −4 Original line number Diff line number Diff line Loading @@ -49,7 +49,6 @@ import android.os.Build; import android.os.Bundle; import android.os.Parcelable; import android.os.SystemClock; import android.service.autofill.Flags; import android.util.AttributeSet; import android.util.IntArray; import android.util.Log; Loading Loading @@ -2652,10 +2651,12 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager // Check for interception. final boolean intercepted; if (actionMasked == MotionEvent.ACTION_DOWN || mFirstTouchTarget != null) { ViewRootImpl viewRootImpl = getViewRootImpl(); if (actionMasked == MotionEvent.ACTION_DOWN || mFirstTouchTarget != null) { final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0; if (!disallowIntercept) { final boolean isDispatchingBack = (viewRootImpl != null && viewRootImpl.getOnBackInvokedDispatcher().isDispatching()); if (!disallowIntercept || isDispatchingBack) { // Allow back to intercept touch intercepted = onInterceptTouchEvent(ev); ev.setAction(action); // restore action in case it was changed } else { Loading core/java/android/view/ViewRootImpl.java +1 −1 Original line number Diff line number Diff line Loading @@ -1282,7 +1282,7 @@ public final class ViewRootImpl implements ViewParent, mImeFocusController = new ImeFocusController(this); mScrollCaptureRequestTimeout = SCROLL_CAPTURE_REQUEST_TIMEOUT_MILLIS; mOnBackInvokedDispatcher = new WindowOnBackInvokedDispatcher(context); mOnBackInvokedDispatcher = new WindowOnBackInvokedDispatcher(context, Looper.myLooper()); if (sensitiveContentAppProtection()) { mSensitiveContentProtectionService = ISensitiveContentProtectionManager.Stub.asInterface( Loading libs/WindowManager/Shell/src/com/android/wm/shell/back/TouchTracker.java→core/java/android/window/BackTouchTracker.java +60 −25 Original line number Diff line number Diff line Loading @@ -14,22 +14,21 @@ * limitations under the License. */ package com.android.wm.shell.back; package android.window; import android.annotation.FloatRange; import android.os.SystemProperties; import android.util.MathUtils; import android.view.MotionEvent; import android.view.RemoteAnimationTarget; import android.window.BackEvent; import android.window.BackMotionEvent; import java.io.PrintWriter; /** * Helper class to record the touch location for gesture and generate back events. * @hide */ class TouchTracker { public class BackTouchTracker { private static final String PREDICTIVE_BACK_LINEAR_DISTANCE_PROP = "persist.wm.debug.predictive_back_linear_distance"; private static final int LINEAR_DISTANCE = SystemProperties Loading @@ -53,9 +52,13 @@ class TouchTracker { private float mLatestVelocityY; private float mStartThresholdX; private int mSwipeEdge; private boolean mShouldUpdateStartLocation = false; private TouchTrackerState mState = TouchTrackerState.INITIAL; void update(float touchX, float touchY, float velocityX, float velocityY) { /** * Updates the tracker with a new motion event. */ public void update(float touchX, float touchY, float velocityX, float velocityY) { /** * If back was previously cancelled but the user has started swiping in the forward * direction again, restart back. Loading @@ -74,34 +77,52 @@ class TouchTracker { mLatestVelocityY = velocityY; } void setTriggerBack(boolean triggerBack) { /** Sets whether the back gesture is past the trigger threshold. */ public void setTriggerBack(boolean triggerBack) { if (mTriggerBack != triggerBack && !triggerBack) { mStartThresholdX = mLatestTouchX; } mTriggerBack = triggerBack; } boolean getTriggerBack() { /** Gets whether the back gesture is past the trigger threshold. */ public boolean getTriggerBack() { return mTriggerBack; } void setState(TouchTrackerState state) { /** Returns if the start location should be updated. */ public boolean shouldUpdateStartLocation() { return mShouldUpdateStartLocation; } /** Sets if the start location should be updated. */ public void setShouldUpdateStartLocation(boolean shouldUpdate) { mShouldUpdateStartLocation = shouldUpdate; } /** Sets the state of the touch tracker. */ public void setState(TouchTrackerState state) { mState = state; } boolean isInInitialState() { /** Returns if the tracker is in initial state. */ public boolean isInInitialState() { return mState == TouchTrackerState.INITIAL; } boolean isActive() { /** Returns if a back gesture is active. */ public boolean isActive() { return mState == TouchTrackerState.ACTIVE; } boolean isFinished() { /** Returns if a back gesture has been finished. */ public boolean isFinished() { return mState == TouchTrackerState.FINISHED; } void setGestureStartLocation(float touchX, float touchY, int swipeEdge) { /** Sets the start location of the back gesture. */ public void setGestureStartLocation(float touchX, float touchY, int swipeEdge) { mInitTouchX = touchX; mInitTouchY = touchY; mLatestTouchX = touchX; Loading @@ -110,25 +131,27 @@ class TouchTracker { mStartThresholdX = mInitTouchX; } /** Update the start location used to compute the progress * to the latest touch location. */ void updateStartLocation() { /** Update the start location used to compute the progress to the latest touch location. */ public void updateStartLocation() { mInitTouchX = mLatestTouchX; mInitTouchY = mLatestTouchY; mStartThresholdX = mInitTouchX; mShouldUpdateStartLocation = false; } void reset() { /** Resets the tracker. */ public void reset() { mInitTouchX = 0; mInitTouchY = 0; mStartThresholdX = 0; mTriggerBack = false; mState = TouchTrackerState.INITIAL; mSwipeEdge = BackEvent.EDGE_LEFT; mShouldUpdateStartLocation = false; } BackMotionEvent createStartEvent(RemoteAnimationTarget target) { /** Creates a start {@link BackMotionEvent}. */ public BackMotionEvent createStartEvent(RemoteAnimationTarget target) { return new BackMotionEvent( /* touchX = */ mInitTouchX, /* touchY = */ mInitTouchY, Loading @@ -140,7 +163,8 @@ class TouchTracker { /* departingAnimationTarget = */ target); } BackMotionEvent createProgressEvent() { /** Creates a progress {@link BackMotionEvent}. */ public BackMotionEvent createProgressEvent() { float progress = getProgress(mLatestTouchX); return createProgressEvent(progress); } Loading @@ -152,7 +176,7 @@ class TouchTracker { * @return progress value */ @FloatRange(from = 0.0, to = 1.0) float getProgress(float touchX) { public float getProgress(float touchX) { // If back is committed, progress is the distance between the last and first touch // point, divided by the max drag distance. Otherwise, it's the distance between // the last touch point and the starting threshold, divided by max drag distance. Loading Loading @@ -200,11 +224,20 @@ class TouchTracker { * Maximum distance in pixels. * Progress is considered to be completed (1f) when this limit is exceeded. */ float getMaxDistance() { public float getMaxDistance() { return mMaxDistance; } BackMotionEvent createProgressEvent(float progress) { public float getLinearDistance() { return mLinearDistance; } public float getNonLinearFactor() { return mNonLinearFactor; } /** Creates a progress {@link BackMotionEvent} for the given progress. */ public BackMotionEvent createProgressEvent(float progress) { return new BackMotionEvent( /* touchX = */ mLatestTouchX, /* touchY = */ mLatestTouchY, Loading @@ -216,6 +249,7 @@ class TouchTracker { /* departingAnimationTarget = */ null); } /** Sets the thresholds for computing progress. */ public void setProgressThresholds(float linearDistance, float maxDistance, float nonLinearFactor) { if (LINEAR_DISTANCE >= 0) { Loading @@ -227,13 +261,14 @@ class TouchTracker { mNonLinearFactor = nonLinearFactor; } void dump(PrintWriter pw, String prefix) { pw.println(prefix + "TouchTracker state:"); /** Dumps debugging info. */ public void dump(PrintWriter pw, String prefix) { pw.println(prefix + "BackTouchTracker state:"); pw.println(prefix + " mState=" + mState); pw.println(prefix + " mTriggerBack=" + mTriggerBack); } enum TouchTrackerState { public enum TouchTrackerState { INITIAL, ACTIVE, FINISHED } Loading core/java/android/window/IOnBackInvokedCallback.aidl +5 −0 Original line number Diff line number Diff line Loading @@ -56,4 +56,9 @@ oneway interface IOnBackInvokedCallback { * Wraps {@link OnBackInvokedCallback#onBackInvoked()}. */ void onBackInvoked(); /** * Sets whether the back gesture is past the trigger threshold. */ void setTriggerBack(in boolean triggerBack); } core/java/android/window/ImeOnBackInvokedDispatcher.java +88 −3 Original line number Diff line number Diff line Loading @@ -48,10 +48,17 @@ public class ImeOnBackInvokedDispatcher implements OnBackInvokedDispatcher, Parc static final String RESULT_KEY_PRIORITY = "priority"; static final int RESULT_CODE_REGISTER = 0; static final int RESULT_CODE_UNREGISTER = 1; static final int RESULT_CODE_START_DISPATCHING = 2; static final int RESULT_CODE_STOP_DISPATCHING = 3; @NonNull private final ResultReceiver mResultReceiver; @NonNull private final BackProgressAnimator mProgressAnimator = new BackProgressAnimator(); @NonNull private final BackTouchTracker mTouchTracker = new BackTouchTracker(); // The handler to run callbacks on. This should be on the same thread // the ViewRootImpl holding IME's WindowOnBackInvokedDispatcher is created on. private Handler mHandler; public ImeOnBackInvokedDispatcher(Handler handler) { mResultReceiver = new ResultReceiver(handler) { Loading @@ -78,6 +85,10 @@ public class ImeOnBackInvokedDispatcher implements OnBackInvokedDispatcher, Parc mResultReceiver = in.readTypedObject(ResultReceiver.CREATOR); } void setHandler(@NonNull Handler handler) { mHandler = handler; } @Override public void registerOnBackInvokedCallback( @OnBackInvokedDispatcher.Priority int priority, Loading @@ -89,8 +100,13 @@ public class ImeOnBackInvokedDispatcher implements OnBackInvokedDispatcher, Parc // the app process, which may treat the IME callback as weakly referenced. This will not // cause a memory leak because the app side already clears the reference correctly. final IOnBackInvokedCallback iCallback = new WindowOnBackInvokedDispatcher.OnBackInvokedCallbackWrapper( callback, mProgressAnimator, false /* useWeakRef */); new ImeOnBackInvokedCallbackWrapper( callback, mTouchTracker, mProgressAnimator, this, mHandler != null ? mHandler : Handler.getMain(), false /* useWeakRef */); bundle.putBinder(RESULT_KEY_CALLBACK, iCallback.asBinder()); bundle.putInt(RESULT_KEY_PRIORITY, priority); bundle.putInt(RESULT_KEY_ID, callback.hashCode()); Loading @@ -115,6 +131,12 @@ public class ImeOnBackInvokedDispatcher implements OnBackInvokedDispatcher, Parc dest.writeTypedObject(mResultReceiver, flags); } /** Sets the progress thresholds for touch tracking */ public void setProgressThresholds(float linearDistance, float maxDistance, float nonLinearFactor) { mTouchTracker.setProgressThresholds(linearDistance, maxDistance, nonLinearFactor); } @NonNull public static final Parcelable.Creator<ImeOnBackInvokedDispatcher> CREATOR = new Parcelable.Creator<ImeOnBackInvokedDispatcher>() { Loading @@ -131,15 +153,20 @@ public class ImeOnBackInvokedDispatcher implements OnBackInvokedDispatcher, Parc private void receive( int resultCode, Bundle resultData, @NonNull WindowOnBackInvokedDispatcher receivingDispatcher) { final int callbackId = resultData.getInt(RESULT_KEY_ID); if (resultCode == RESULT_CODE_REGISTER) { final int callbackId = resultData.getInt(RESULT_KEY_ID); int priority = resultData.getInt(RESULT_KEY_PRIORITY); final IOnBackInvokedCallback callback = IOnBackInvokedCallback.Stub.asInterface( resultData.getBinder(RESULT_KEY_CALLBACK)); registerReceivedCallback( callback, priority, callbackId, receivingDispatcher); } else if (resultCode == RESULT_CODE_UNREGISTER) { final int callbackId = resultData.getInt(RESULT_KEY_ID); unregisterReceivedCallback(callbackId, receivingDispatcher); } else if (resultCode == RESULT_CODE_START_DISPATCHING) { receiveStartDispatching(receivingDispatcher); } else if (resultCode == RESULT_CODE_STOP_DISPATCHING) { receiveStopDispatching(receivingDispatcher); } } Loading Loading @@ -181,6 +208,63 @@ public class ImeOnBackInvokedDispatcher implements OnBackInvokedDispatcher, Parc mImeCallbacks.remove(callback); } static class ImeOnBackInvokedCallbackWrapper extends WindowOnBackInvokedDispatcher.OnBackInvokedCallbackWrapper { @NonNull private final ImeOnBackInvokedDispatcher mDispatcher; ImeOnBackInvokedCallbackWrapper( @NonNull OnBackInvokedCallback callback, @NonNull BackTouchTracker touchTracker, @NonNull BackProgressAnimator progressAnimator, @NonNull ImeOnBackInvokedDispatcher dispatcher, @NonNull Handler handler, boolean useWeakRef) { super(callback, touchTracker, progressAnimator, handler, useWeakRef); mDispatcher = dispatcher; } @Override public void onBackStarted(BackMotionEvent backEvent) { super.onBackStarted(backEvent); mDispatcher.sendStartDispatching(); } @Override public void onBackCancelled() { super.onBackCancelled(); mDispatcher.sendStopDispatching(); } @Override public void onBackInvoked() throws RemoteException { super.onBackInvoked(); mDispatcher.sendStopDispatching(); } } /** Notifies the app process that we've stopped dispatching to an IME callback */ private void sendStopDispatching() { mResultReceiver.send(RESULT_CODE_STOP_DISPATCHING, null /* unused bundle */); } /** Notifies the app process that we've started dispatching to an IME callback */ private void sendStartDispatching() { mResultReceiver.send(RESULT_CODE_START_DISPATCHING, null /* unused bundle */); } /** Receives IME's message that dispatching has started. */ private void receiveStopDispatching( @NonNull WindowOnBackInvokedDispatcher receivingDispatcher) { receivingDispatcher.onStopImeDispatching(); } /** Receives IME's message that dispatching has stopped. */ private void receiveStartDispatching( @NonNull WindowOnBackInvokedDispatcher receivingDispatcher) { receivingDispatcher.onStartImeDispatching(); } /** Clears all registered callbacks on the instance. */ public void clear() { // Unregister previously registered callbacks if there's any. Loading @@ -193,6 +277,7 @@ public class ImeOnBackInvokedDispatcher implements OnBackInvokedDispatcher, Parc // We should also stop running animations since all callbacks have been removed. // note: mSpring.skipToEnd(), in ProgressAnimator.reset(), requires the main handler. Handler.getMain().post(mProgressAnimator::reset); sendStopDispatching(); } static class ImeOnBackInvokedCallback implements OnBackInvokedCallback { Loading Loading
core/java/android/view/ViewGroup.java +5 −4 Original line number Diff line number Diff line Loading @@ -49,7 +49,6 @@ import android.os.Build; import android.os.Bundle; import android.os.Parcelable; import android.os.SystemClock; import android.service.autofill.Flags; import android.util.AttributeSet; import android.util.IntArray; import android.util.Log; Loading Loading @@ -2652,10 +2651,12 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager // Check for interception. final boolean intercepted; if (actionMasked == MotionEvent.ACTION_DOWN || mFirstTouchTarget != null) { ViewRootImpl viewRootImpl = getViewRootImpl(); if (actionMasked == MotionEvent.ACTION_DOWN || mFirstTouchTarget != null) { final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0; if (!disallowIntercept) { final boolean isDispatchingBack = (viewRootImpl != null && viewRootImpl.getOnBackInvokedDispatcher().isDispatching()); if (!disallowIntercept || isDispatchingBack) { // Allow back to intercept touch intercepted = onInterceptTouchEvent(ev); ev.setAction(action); // restore action in case it was changed } else { Loading
core/java/android/view/ViewRootImpl.java +1 −1 Original line number Diff line number Diff line Loading @@ -1282,7 +1282,7 @@ public final class ViewRootImpl implements ViewParent, mImeFocusController = new ImeFocusController(this); mScrollCaptureRequestTimeout = SCROLL_CAPTURE_REQUEST_TIMEOUT_MILLIS; mOnBackInvokedDispatcher = new WindowOnBackInvokedDispatcher(context); mOnBackInvokedDispatcher = new WindowOnBackInvokedDispatcher(context, Looper.myLooper()); if (sensitiveContentAppProtection()) { mSensitiveContentProtectionService = ISensitiveContentProtectionManager.Stub.asInterface( Loading
libs/WindowManager/Shell/src/com/android/wm/shell/back/TouchTracker.java→core/java/android/window/BackTouchTracker.java +60 −25 Original line number Diff line number Diff line Loading @@ -14,22 +14,21 @@ * limitations under the License. */ package com.android.wm.shell.back; package android.window; import android.annotation.FloatRange; import android.os.SystemProperties; import android.util.MathUtils; import android.view.MotionEvent; import android.view.RemoteAnimationTarget; import android.window.BackEvent; import android.window.BackMotionEvent; import java.io.PrintWriter; /** * Helper class to record the touch location for gesture and generate back events. * @hide */ class TouchTracker { public class BackTouchTracker { private static final String PREDICTIVE_BACK_LINEAR_DISTANCE_PROP = "persist.wm.debug.predictive_back_linear_distance"; private static final int LINEAR_DISTANCE = SystemProperties Loading @@ -53,9 +52,13 @@ class TouchTracker { private float mLatestVelocityY; private float mStartThresholdX; private int mSwipeEdge; private boolean mShouldUpdateStartLocation = false; private TouchTrackerState mState = TouchTrackerState.INITIAL; void update(float touchX, float touchY, float velocityX, float velocityY) { /** * Updates the tracker with a new motion event. */ public void update(float touchX, float touchY, float velocityX, float velocityY) { /** * If back was previously cancelled but the user has started swiping in the forward * direction again, restart back. Loading @@ -74,34 +77,52 @@ class TouchTracker { mLatestVelocityY = velocityY; } void setTriggerBack(boolean triggerBack) { /** Sets whether the back gesture is past the trigger threshold. */ public void setTriggerBack(boolean triggerBack) { if (mTriggerBack != triggerBack && !triggerBack) { mStartThresholdX = mLatestTouchX; } mTriggerBack = triggerBack; } boolean getTriggerBack() { /** Gets whether the back gesture is past the trigger threshold. */ public boolean getTriggerBack() { return mTriggerBack; } void setState(TouchTrackerState state) { /** Returns if the start location should be updated. */ public boolean shouldUpdateStartLocation() { return mShouldUpdateStartLocation; } /** Sets if the start location should be updated. */ public void setShouldUpdateStartLocation(boolean shouldUpdate) { mShouldUpdateStartLocation = shouldUpdate; } /** Sets the state of the touch tracker. */ public void setState(TouchTrackerState state) { mState = state; } boolean isInInitialState() { /** Returns if the tracker is in initial state. */ public boolean isInInitialState() { return mState == TouchTrackerState.INITIAL; } boolean isActive() { /** Returns if a back gesture is active. */ public boolean isActive() { return mState == TouchTrackerState.ACTIVE; } boolean isFinished() { /** Returns if a back gesture has been finished. */ public boolean isFinished() { return mState == TouchTrackerState.FINISHED; } void setGestureStartLocation(float touchX, float touchY, int swipeEdge) { /** Sets the start location of the back gesture. */ public void setGestureStartLocation(float touchX, float touchY, int swipeEdge) { mInitTouchX = touchX; mInitTouchY = touchY; mLatestTouchX = touchX; Loading @@ -110,25 +131,27 @@ class TouchTracker { mStartThresholdX = mInitTouchX; } /** Update the start location used to compute the progress * to the latest touch location. */ void updateStartLocation() { /** Update the start location used to compute the progress to the latest touch location. */ public void updateStartLocation() { mInitTouchX = mLatestTouchX; mInitTouchY = mLatestTouchY; mStartThresholdX = mInitTouchX; mShouldUpdateStartLocation = false; } void reset() { /** Resets the tracker. */ public void reset() { mInitTouchX = 0; mInitTouchY = 0; mStartThresholdX = 0; mTriggerBack = false; mState = TouchTrackerState.INITIAL; mSwipeEdge = BackEvent.EDGE_LEFT; mShouldUpdateStartLocation = false; } BackMotionEvent createStartEvent(RemoteAnimationTarget target) { /** Creates a start {@link BackMotionEvent}. */ public BackMotionEvent createStartEvent(RemoteAnimationTarget target) { return new BackMotionEvent( /* touchX = */ mInitTouchX, /* touchY = */ mInitTouchY, Loading @@ -140,7 +163,8 @@ class TouchTracker { /* departingAnimationTarget = */ target); } BackMotionEvent createProgressEvent() { /** Creates a progress {@link BackMotionEvent}. */ public BackMotionEvent createProgressEvent() { float progress = getProgress(mLatestTouchX); return createProgressEvent(progress); } Loading @@ -152,7 +176,7 @@ class TouchTracker { * @return progress value */ @FloatRange(from = 0.0, to = 1.0) float getProgress(float touchX) { public float getProgress(float touchX) { // If back is committed, progress is the distance between the last and first touch // point, divided by the max drag distance. Otherwise, it's the distance between // the last touch point and the starting threshold, divided by max drag distance. Loading Loading @@ -200,11 +224,20 @@ class TouchTracker { * Maximum distance in pixels. * Progress is considered to be completed (1f) when this limit is exceeded. */ float getMaxDistance() { public float getMaxDistance() { return mMaxDistance; } BackMotionEvent createProgressEvent(float progress) { public float getLinearDistance() { return mLinearDistance; } public float getNonLinearFactor() { return mNonLinearFactor; } /** Creates a progress {@link BackMotionEvent} for the given progress. */ public BackMotionEvent createProgressEvent(float progress) { return new BackMotionEvent( /* touchX = */ mLatestTouchX, /* touchY = */ mLatestTouchY, Loading @@ -216,6 +249,7 @@ class TouchTracker { /* departingAnimationTarget = */ null); } /** Sets the thresholds for computing progress. */ public void setProgressThresholds(float linearDistance, float maxDistance, float nonLinearFactor) { if (LINEAR_DISTANCE >= 0) { Loading @@ -227,13 +261,14 @@ class TouchTracker { mNonLinearFactor = nonLinearFactor; } void dump(PrintWriter pw, String prefix) { pw.println(prefix + "TouchTracker state:"); /** Dumps debugging info. */ public void dump(PrintWriter pw, String prefix) { pw.println(prefix + "BackTouchTracker state:"); pw.println(prefix + " mState=" + mState); pw.println(prefix + " mTriggerBack=" + mTriggerBack); } enum TouchTrackerState { public enum TouchTrackerState { INITIAL, ACTIVE, FINISHED } Loading
core/java/android/window/IOnBackInvokedCallback.aidl +5 −0 Original line number Diff line number Diff line Loading @@ -56,4 +56,9 @@ oneway interface IOnBackInvokedCallback { * Wraps {@link OnBackInvokedCallback#onBackInvoked()}. */ void onBackInvoked(); /** * Sets whether the back gesture is past the trigger threshold. */ void setTriggerBack(in boolean triggerBack); }
core/java/android/window/ImeOnBackInvokedDispatcher.java +88 −3 Original line number Diff line number Diff line Loading @@ -48,10 +48,17 @@ public class ImeOnBackInvokedDispatcher implements OnBackInvokedDispatcher, Parc static final String RESULT_KEY_PRIORITY = "priority"; static final int RESULT_CODE_REGISTER = 0; static final int RESULT_CODE_UNREGISTER = 1; static final int RESULT_CODE_START_DISPATCHING = 2; static final int RESULT_CODE_STOP_DISPATCHING = 3; @NonNull private final ResultReceiver mResultReceiver; @NonNull private final BackProgressAnimator mProgressAnimator = new BackProgressAnimator(); @NonNull private final BackTouchTracker mTouchTracker = new BackTouchTracker(); // The handler to run callbacks on. This should be on the same thread // the ViewRootImpl holding IME's WindowOnBackInvokedDispatcher is created on. private Handler mHandler; public ImeOnBackInvokedDispatcher(Handler handler) { mResultReceiver = new ResultReceiver(handler) { Loading @@ -78,6 +85,10 @@ public class ImeOnBackInvokedDispatcher implements OnBackInvokedDispatcher, Parc mResultReceiver = in.readTypedObject(ResultReceiver.CREATOR); } void setHandler(@NonNull Handler handler) { mHandler = handler; } @Override public void registerOnBackInvokedCallback( @OnBackInvokedDispatcher.Priority int priority, Loading @@ -89,8 +100,13 @@ public class ImeOnBackInvokedDispatcher implements OnBackInvokedDispatcher, Parc // the app process, which may treat the IME callback as weakly referenced. This will not // cause a memory leak because the app side already clears the reference correctly. final IOnBackInvokedCallback iCallback = new WindowOnBackInvokedDispatcher.OnBackInvokedCallbackWrapper( callback, mProgressAnimator, false /* useWeakRef */); new ImeOnBackInvokedCallbackWrapper( callback, mTouchTracker, mProgressAnimator, this, mHandler != null ? mHandler : Handler.getMain(), false /* useWeakRef */); bundle.putBinder(RESULT_KEY_CALLBACK, iCallback.asBinder()); bundle.putInt(RESULT_KEY_PRIORITY, priority); bundle.putInt(RESULT_KEY_ID, callback.hashCode()); Loading @@ -115,6 +131,12 @@ public class ImeOnBackInvokedDispatcher implements OnBackInvokedDispatcher, Parc dest.writeTypedObject(mResultReceiver, flags); } /** Sets the progress thresholds for touch tracking */ public void setProgressThresholds(float linearDistance, float maxDistance, float nonLinearFactor) { mTouchTracker.setProgressThresholds(linearDistance, maxDistance, nonLinearFactor); } @NonNull public static final Parcelable.Creator<ImeOnBackInvokedDispatcher> CREATOR = new Parcelable.Creator<ImeOnBackInvokedDispatcher>() { Loading @@ -131,15 +153,20 @@ public class ImeOnBackInvokedDispatcher implements OnBackInvokedDispatcher, Parc private void receive( int resultCode, Bundle resultData, @NonNull WindowOnBackInvokedDispatcher receivingDispatcher) { final int callbackId = resultData.getInt(RESULT_KEY_ID); if (resultCode == RESULT_CODE_REGISTER) { final int callbackId = resultData.getInt(RESULT_KEY_ID); int priority = resultData.getInt(RESULT_KEY_PRIORITY); final IOnBackInvokedCallback callback = IOnBackInvokedCallback.Stub.asInterface( resultData.getBinder(RESULT_KEY_CALLBACK)); registerReceivedCallback( callback, priority, callbackId, receivingDispatcher); } else if (resultCode == RESULT_CODE_UNREGISTER) { final int callbackId = resultData.getInt(RESULT_KEY_ID); unregisterReceivedCallback(callbackId, receivingDispatcher); } else if (resultCode == RESULT_CODE_START_DISPATCHING) { receiveStartDispatching(receivingDispatcher); } else if (resultCode == RESULT_CODE_STOP_DISPATCHING) { receiveStopDispatching(receivingDispatcher); } } Loading Loading @@ -181,6 +208,63 @@ public class ImeOnBackInvokedDispatcher implements OnBackInvokedDispatcher, Parc mImeCallbacks.remove(callback); } static class ImeOnBackInvokedCallbackWrapper extends WindowOnBackInvokedDispatcher.OnBackInvokedCallbackWrapper { @NonNull private final ImeOnBackInvokedDispatcher mDispatcher; ImeOnBackInvokedCallbackWrapper( @NonNull OnBackInvokedCallback callback, @NonNull BackTouchTracker touchTracker, @NonNull BackProgressAnimator progressAnimator, @NonNull ImeOnBackInvokedDispatcher dispatcher, @NonNull Handler handler, boolean useWeakRef) { super(callback, touchTracker, progressAnimator, handler, useWeakRef); mDispatcher = dispatcher; } @Override public void onBackStarted(BackMotionEvent backEvent) { super.onBackStarted(backEvent); mDispatcher.sendStartDispatching(); } @Override public void onBackCancelled() { super.onBackCancelled(); mDispatcher.sendStopDispatching(); } @Override public void onBackInvoked() throws RemoteException { super.onBackInvoked(); mDispatcher.sendStopDispatching(); } } /** Notifies the app process that we've stopped dispatching to an IME callback */ private void sendStopDispatching() { mResultReceiver.send(RESULT_CODE_STOP_DISPATCHING, null /* unused bundle */); } /** Notifies the app process that we've started dispatching to an IME callback */ private void sendStartDispatching() { mResultReceiver.send(RESULT_CODE_START_DISPATCHING, null /* unused bundle */); } /** Receives IME's message that dispatching has started. */ private void receiveStopDispatching( @NonNull WindowOnBackInvokedDispatcher receivingDispatcher) { receivingDispatcher.onStopImeDispatching(); } /** Receives IME's message that dispatching has stopped. */ private void receiveStartDispatching( @NonNull WindowOnBackInvokedDispatcher receivingDispatcher) { receivingDispatcher.onStartImeDispatching(); } /** Clears all registered callbacks on the instance. */ public void clear() { // Unregister previously registered callbacks if there's any. Loading @@ -193,6 +277,7 @@ public class ImeOnBackInvokedDispatcher implements OnBackInvokedDispatcher, Parc // We should also stop running animations since all callbacks have been removed. // note: mSpring.skipToEnd(), in ProgressAnimator.reset(), requires the main handler. Handler.getMain().post(mProgressAnimator::reset); sendStopDispatching(); } static class ImeOnBackInvokedCallback implements OnBackInvokedCallback { Loading