Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit de0c0e22 authored by Shan Huang's avatar Shan Huang Committed by Android (Google) Code Review
Browse files

Merge "Generate progress events from app process for app animations." into main

parents dc811346 11bc9d55
Loading
Loading
Loading
Loading
+5 −4
Original line number Diff line number Diff line
@@ -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;
@@ -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 {
+1 −1
Original line number Diff line number Diff line
@@ -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(
+60 −25
Original line number Diff line number Diff line
@@ -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
@@ -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.
@@ -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;
@@ -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,
@@ -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);
    }
@@ -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.
@@ -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,
@@ -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) {
@@ -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
    }

+5 −0
Original line number Diff line number Diff line
@@ -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);
}
+88 −3
Original line number Diff line number Diff line
@@ -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) {
@@ -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,
@@ -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());
@@ -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>() {
@@ -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);
        }
    }

@@ -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.
@@ -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