Loading core/java/android/window/BackEvent.java +21 −1 Original line number Diff line number Diff line Loading @@ -18,8 +18,10 @@ 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; Loading Loading @@ -50,6 +52,8 @@ public class BackEvent implements Parcelable { @SwipeEdge private final int mSwipeEdge; @Nullable private final RemoteAnimationTarget mDepartingAnimationTarget; /** * Creates a new {@link BackEvent} instance. Loading @@ -58,12 +62,16 @@ public class BackEvent implements Parcelable { * @param touchY Absolute Y location of the touch point of this event. * @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(float touchX, float touchY, float progress, @SwipeEdge int swipeEdge) { public BackEvent(float touchX, float touchY, float progress, @SwipeEdge int swipeEdge, @Nullable RemoteAnimationTarget departingAnimationTarget) { mTouchX = touchX; mTouchY = touchY; mProgress = progress; mSwipeEdge = swipeEdge; mDepartingAnimationTarget = departingAnimationTarget; } private BackEvent(@NonNull Parcel in) { Loading @@ -71,6 +79,7 @@ public class BackEvent implements Parcelable { mTouchY = in.readFloat(); mProgress = in.readFloat(); mSwipeEdge = in.readInt(); mDepartingAnimationTarget = in.readTypedObject(RemoteAnimationTarget.CREATOR); } public static final Creator<BackEvent> CREATOR = new Creator<BackEvent>() { Loading @@ -96,6 +105,7 @@ public class BackEvent implements Parcelable { dest.writeFloat(mTouchY); dest.writeFloat(mProgress); dest.writeInt(mSwipeEdge); dest.writeTypedObject(mDepartingAnimationTarget, flags); } /** Loading Loading @@ -126,6 +136,16 @@ public class BackEvent implements Parcelable { 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{" Loading core/java/android/window/BackProgressAnimator.java 0 → 100644 +139 −0 Original line number Diff line number Diff line /* * 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.util.FloatProperty; import com.android.internal.dynamicanimation.animation.SpringAnimation; import com.android.internal.dynamicanimation.animation.SpringForce; /** * An animator that drives the predictive back progress with a spring. * * The back gesture's latest touch point and committal state determines the final position of * the spring. The continuous movement of the spring is used to produce {@link BackEvent}s with * smoothly transitioning progress values. * * @hide */ public class BackProgressAnimator { /** * A factor to scale the input progress by, so that it works better with the spring. * We divide the output progress by this value before sending it to apps, so that apps * always receive progress values in [0, 1]. */ private static final float SCALE_FACTOR = 100f; private final SpringAnimation mSpring; private ProgressCallback mCallback; private float mProgress = 0; private BackEvent mLastBackEvent; private boolean mStarted = false; private void setProgress(float progress) { mProgress = progress; } private float getProgress() { return mProgress; } private static final FloatProperty<BackProgressAnimator> PROGRESS_PROP = new FloatProperty<BackProgressAnimator>("progress") { @Override public void setValue(BackProgressAnimator animator, float value) { animator.setProgress(value); animator.updateProgressValue(value); } @Override public Float get(BackProgressAnimator object) { return object.getProgress(); } }; /** A callback to be invoked when there's a progress value update from the animator. */ public interface ProgressCallback { /** Called when there's a progress value update. */ void onProgressUpdate(BackEvent event); } public BackProgressAnimator() { mSpring = new SpringAnimation(this, PROGRESS_PROP); mSpring.setSpring(new SpringForce() .setStiffness(SpringForce.STIFFNESS_MEDIUM) .setDampingRatio(SpringForce.DAMPING_RATIO_NO_BOUNCY)); } /** * Sets a new target position for the back progress. * * @param event the {@link BackEvent} containing the latest target progress. */ public void onBackProgressed(BackEvent event) { if (!mStarted) { return; } mLastBackEvent = event; if (mSpring == null) { return; } mSpring.animateToFinalPosition(event.getProgress() * SCALE_FACTOR); } /** * Starts the back progress animation. * * @param event the {@link BackEvent} that started the gesture. * @param callback the back callback to invoke for the gesture. It will receive back progress * dispatches as the progress animation updates. */ public void onBackStarted(BackEvent event, ProgressCallback callback) { reset(); mLastBackEvent = event; mCallback = callback; mStarted = true; } /** * Resets the back progress animation. This should be called when back is invoked or cancelled. */ public void reset() { mSpring.animateToFinalPosition(0); if (mSpring.canSkipToEnd()) { mSpring.skipToEnd(); } else { // Should never happen. mSpring.cancel(); } mStarted = false; mLastBackEvent = null; mCallback = null; mProgress = 0; } private void updateProgressValue(float progress) { if (mLastBackEvent == null || mCallback == null || !mStarted) { return; } mCallback.onProgressUpdate( new BackEvent(mLastBackEvent.getTouchX(), mLastBackEvent.getTouchY(), progress / SCALE_FACTOR, mLastBackEvent.getSwipeEdge(), mLastBackEvent.getDepartingAnimationTarget())); } } core/java/android/window/IOnBackInvokedCallback.aidl +7 −6 Original line number Diff line number Diff line Loading @@ -28,17 +28,18 @@ import android.window.BackEvent; oneway interface IOnBackInvokedCallback { /** * Called when a back gesture has been started, or back button has been pressed down. * Wraps {@link OnBackInvokedCallback#onBackStarted()}. * Wraps {@link OnBackInvokedCallback#onBackStarted(BackEvent)}. * * @param backEvent The {@link BackEvent} containing information about the touch or button press. */ void onBackStarted(); void onBackStarted(in BackEvent backEvent); /** * Called on back gesture progress. * Wraps {@link OnBackInvokedCallback#onBackProgressed()}. * Wraps {@link OnBackInvokedCallback#onBackProgressed(BackEvent)}. * * @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 The {@link BackEvent} containing information about the latest touch point * and the progress that the back animation should seek to. */ void onBackProgressed(in BackEvent backEvent); Loading core/java/android/window/OnBackAnimationCallback.java +3 −8 Original line number Diff line number Diff line Loading @@ -13,14 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ package android.window; import android.annotation.NonNull; import android.app.Activity; import android.app.Dialog; import android.view.View; /** * Interface for applications to register back animation callbacks along their custom back * handling. Loading @@ -44,7 +41,6 @@ public interface OnBackAnimationCallback extends OnBackInvokedCallback { * Called when a back gesture has been started, or back button has been pressed down. */ default void onBackStarted() { } /** * Called on back gesture progress. * Loading @@ -53,7 +49,6 @@ public interface OnBackAnimationCallback extends OnBackInvokedCallback { * @see BackEvent */ default void onBackProgressed(@NonNull BackEvent backEvent) { } /** * Called when a back gesture or back button press has been cancelled. */ Loading core/java/android/window/OnBackInvokedCallback.java +28 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package android.window; import android.annotation.NonNull; import android.app.Activity; import android.app.Dialog; import android.view.Window; Loading @@ -40,9 +41,36 @@ import android.view.Window; */ @SuppressWarnings("deprecation") public interface OnBackInvokedCallback { /** * Called when a back gesture has been started, or back button has been pressed down. * * @param backEvent The {@link BackEvent} containing information about the touch or * button press. * * @hide */ default void onBackStarted(@NonNull BackEvent backEvent) {} /** * Called when a back gesture has been progressed. * * @param backEvent The {@link BackEvent} containing information about the latest touch point * and the progress that the back animation should seek to. * * @hide */ default void onBackProgressed(@NonNull BackEvent backEvent) {} /** * Called when a back gesture has been completed and committed, or back button pressed * has been released and committed. */ void onBackInvoked(); /** * Called when a back gesture or button press has been cancelled. * * @hide */ default void onBackCancelled() {} } Loading
core/java/android/window/BackEvent.java +21 −1 Original line number Diff line number Diff line Loading @@ -18,8 +18,10 @@ 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; Loading Loading @@ -50,6 +52,8 @@ public class BackEvent implements Parcelable { @SwipeEdge private final int mSwipeEdge; @Nullable private final RemoteAnimationTarget mDepartingAnimationTarget; /** * Creates a new {@link BackEvent} instance. Loading @@ -58,12 +62,16 @@ public class BackEvent implements Parcelable { * @param touchY Absolute Y location of the touch point of this event. * @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(float touchX, float touchY, float progress, @SwipeEdge int swipeEdge) { public BackEvent(float touchX, float touchY, float progress, @SwipeEdge int swipeEdge, @Nullable RemoteAnimationTarget departingAnimationTarget) { mTouchX = touchX; mTouchY = touchY; mProgress = progress; mSwipeEdge = swipeEdge; mDepartingAnimationTarget = departingAnimationTarget; } private BackEvent(@NonNull Parcel in) { Loading @@ -71,6 +79,7 @@ public class BackEvent implements Parcelable { mTouchY = in.readFloat(); mProgress = in.readFloat(); mSwipeEdge = in.readInt(); mDepartingAnimationTarget = in.readTypedObject(RemoteAnimationTarget.CREATOR); } public static final Creator<BackEvent> CREATOR = new Creator<BackEvent>() { Loading @@ -96,6 +105,7 @@ public class BackEvent implements Parcelable { dest.writeFloat(mTouchY); dest.writeFloat(mProgress); dest.writeInt(mSwipeEdge); dest.writeTypedObject(mDepartingAnimationTarget, flags); } /** Loading Loading @@ -126,6 +136,16 @@ public class BackEvent implements Parcelable { 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{" Loading
core/java/android/window/BackProgressAnimator.java 0 → 100644 +139 −0 Original line number Diff line number Diff line /* * 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.util.FloatProperty; import com.android.internal.dynamicanimation.animation.SpringAnimation; import com.android.internal.dynamicanimation.animation.SpringForce; /** * An animator that drives the predictive back progress with a spring. * * The back gesture's latest touch point and committal state determines the final position of * the spring. The continuous movement of the spring is used to produce {@link BackEvent}s with * smoothly transitioning progress values. * * @hide */ public class BackProgressAnimator { /** * A factor to scale the input progress by, so that it works better with the spring. * We divide the output progress by this value before sending it to apps, so that apps * always receive progress values in [0, 1]. */ private static final float SCALE_FACTOR = 100f; private final SpringAnimation mSpring; private ProgressCallback mCallback; private float mProgress = 0; private BackEvent mLastBackEvent; private boolean mStarted = false; private void setProgress(float progress) { mProgress = progress; } private float getProgress() { return mProgress; } private static final FloatProperty<BackProgressAnimator> PROGRESS_PROP = new FloatProperty<BackProgressAnimator>("progress") { @Override public void setValue(BackProgressAnimator animator, float value) { animator.setProgress(value); animator.updateProgressValue(value); } @Override public Float get(BackProgressAnimator object) { return object.getProgress(); } }; /** A callback to be invoked when there's a progress value update from the animator. */ public interface ProgressCallback { /** Called when there's a progress value update. */ void onProgressUpdate(BackEvent event); } public BackProgressAnimator() { mSpring = new SpringAnimation(this, PROGRESS_PROP); mSpring.setSpring(new SpringForce() .setStiffness(SpringForce.STIFFNESS_MEDIUM) .setDampingRatio(SpringForce.DAMPING_RATIO_NO_BOUNCY)); } /** * Sets a new target position for the back progress. * * @param event the {@link BackEvent} containing the latest target progress. */ public void onBackProgressed(BackEvent event) { if (!mStarted) { return; } mLastBackEvent = event; if (mSpring == null) { return; } mSpring.animateToFinalPosition(event.getProgress() * SCALE_FACTOR); } /** * Starts the back progress animation. * * @param event the {@link BackEvent} that started the gesture. * @param callback the back callback to invoke for the gesture. It will receive back progress * dispatches as the progress animation updates. */ public void onBackStarted(BackEvent event, ProgressCallback callback) { reset(); mLastBackEvent = event; mCallback = callback; mStarted = true; } /** * Resets the back progress animation. This should be called when back is invoked or cancelled. */ public void reset() { mSpring.animateToFinalPosition(0); if (mSpring.canSkipToEnd()) { mSpring.skipToEnd(); } else { // Should never happen. mSpring.cancel(); } mStarted = false; mLastBackEvent = null; mCallback = null; mProgress = 0; } private void updateProgressValue(float progress) { if (mLastBackEvent == null || mCallback == null || !mStarted) { return; } mCallback.onProgressUpdate( new BackEvent(mLastBackEvent.getTouchX(), mLastBackEvent.getTouchY(), progress / SCALE_FACTOR, mLastBackEvent.getSwipeEdge(), mLastBackEvent.getDepartingAnimationTarget())); } }
core/java/android/window/IOnBackInvokedCallback.aidl +7 −6 Original line number Diff line number Diff line Loading @@ -28,17 +28,18 @@ import android.window.BackEvent; oneway interface IOnBackInvokedCallback { /** * Called when a back gesture has been started, or back button has been pressed down. * Wraps {@link OnBackInvokedCallback#onBackStarted()}. * Wraps {@link OnBackInvokedCallback#onBackStarted(BackEvent)}. * * @param backEvent The {@link BackEvent} containing information about the touch or button press. */ void onBackStarted(); void onBackStarted(in BackEvent backEvent); /** * Called on back gesture progress. * Wraps {@link OnBackInvokedCallback#onBackProgressed()}. * Wraps {@link OnBackInvokedCallback#onBackProgressed(BackEvent)}. * * @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 The {@link BackEvent} containing information about the latest touch point * and the progress that the back animation should seek to. */ void onBackProgressed(in BackEvent backEvent); Loading
core/java/android/window/OnBackAnimationCallback.java +3 −8 Original line number Diff line number Diff line Loading @@ -13,14 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ package android.window; import android.annotation.NonNull; import android.app.Activity; import android.app.Dialog; import android.view.View; /** * Interface for applications to register back animation callbacks along their custom back * handling. Loading @@ -44,7 +41,6 @@ public interface OnBackAnimationCallback extends OnBackInvokedCallback { * Called when a back gesture has been started, or back button has been pressed down. */ default void onBackStarted() { } /** * Called on back gesture progress. * Loading @@ -53,7 +49,6 @@ public interface OnBackAnimationCallback extends OnBackInvokedCallback { * @see BackEvent */ default void onBackProgressed(@NonNull BackEvent backEvent) { } /** * Called when a back gesture or back button press has been cancelled. */ Loading
core/java/android/window/OnBackInvokedCallback.java +28 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package android.window; import android.annotation.NonNull; import android.app.Activity; import android.app.Dialog; import android.view.Window; Loading @@ -40,9 +41,36 @@ import android.view.Window; */ @SuppressWarnings("deprecation") public interface OnBackInvokedCallback { /** * Called when a back gesture has been started, or back button has been pressed down. * * @param backEvent The {@link BackEvent} containing information about the touch or * button press. * * @hide */ default void onBackStarted(@NonNull BackEvent backEvent) {} /** * Called when a back gesture has been progressed. * * @param backEvent The {@link BackEvent} containing information about the latest touch point * and the progress that the back animation should seek to. * * @hide */ default void onBackProgressed(@NonNull BackEvent backEvent) {} /** * Called when a back gesture has been completed and committed, or back button pressed * has been released and committed. */ void onBackInvoked(); /** * Called when a back gesture or button press has been cancelled. * * @hide */ default void onBackCancelled() {} }