Let BackProgressAnimator could play cancel animation
Add cancel and the cancel callback in BackProgressAnimator so it could animate to start position and invoke the callback after finished. Bug: 259608500 Test: atest BackAnimationControllerTest BackNavigationControllerTests Test: atest BackProgressAnimatorTest Change-Id: I94303ba530d155f4b264dafa21bd23185a6b44bd
This commit is contained in:
@@ -74,6 +74,9 @@ public final class BackEvent {
|
||||
* and animation should seek to its end state. Exact end value may vary depending on
|
||||
* screen size.
|
||||
* </ol>
|
||||
* <li> After the gesture finishes in cancel state, this method keeps getting invoked until the
|
||||
* progress value animates back to 0.
|
||||
* </ol>
|
||||
* In-between locations are linearly interpolated based on horizontal distance from the starting
|
||||
* edge and smooth clamped to 1 when the distance exceeds a system-wide threshold.
|
||||
*/
|
||||
|
||||
@@ -16,8 +16,10 @@
|
||||
|
||||
package android.window;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.util.FloatProperty;
|
||||
|
||||
import com.android.internal.dynamicanimation.animation.DynamicAnimation;
|
||||
import com.android.internal.dynamicanimation.animation.SpringAnimation;
|
||||
import com.android.internal.dynamicanimation.animation.SpringForce;
|
||||
|
||||
@@ -126,6 +128,27 @@ public class BackProgressAnimator {
|
||||
mProgress = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Animate the back progress animation from current progress to start position.
|
||||
* This should be called when back is cancelled.
|
||||
*
|
||||
* @param finishCallback the callback to be invoked when the progress is reach to 0.
|
||||
*/
|
||||
public void onBackCancelled(@NonNull Runnable finishCallback) {
|
||||
final DynamicAnimation.OnAnimationEndListener listener =
|
||||
new DynamicAnimation.OnAnimationEndListener() {
|
||||
@Override
|
||||
public void onAnimationEnd(DynamicAnimation animation, boolean canceled, float value,
|
||||
float velocity) {
|
||||
mSpring.removeEndListener(this);
|
||||
finishCallback.run();
|
||||
reset();
|
||||
}
|
||||
};
|
||||
mSpring.addEndListener(listener);
|
||||
mSpring.animateToFinalPosition(0);
|
||||
}
|
||||
|
||||
private void updateProgressValue(float progress) {
|
||||
if (mLastBackEvent == null || mCallback == null || !mStarted) {
|
||||
return;
|
||||
|
||||
@@ -266,11 +266,12 @@ public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher {
|
||||
@Override
|
||||
public void onBackCancelled() {
|
||||
Handler.getMain().post(() -> {
|
||||
mProgressAnimator.reset();
|
||||
final OnBackAnimationCallback callback = getBackAnimationCallback();
|
||||
if (callback != null) {
|
||||
callback.onBackCancelled();
|
||||
}
|
||||
mProgressAnimator.onBackCancelled(() -> {
|
||||
final OnBackAnimationCallback callback = getBackAnimationCallback();
|
||||
if (callback != null) {
|
||||
callback.onBackCancelled();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -171,6 +171,7 @@ class CrossActivityAnimation {
|
||||
mInitialTouchPos.set(0, 0);
|
||||
mEnteringWindowShow = false;
|
||||
mEnteringMargin = 0;
|
||||
mEnteringAnimator = null;
|
||||
|
||||
if (mFinishCallback != null) {
|
||||
try {
|
||||
@@ -276,7 +277,7 @@ class CrossActivityAnimation {
|
||||
}
|
||||
|
||||
// End the fade in animation.
|
||||
if (mEnteringAnimator.isRunning()) {
|
||||
if (mEnteringAnimator != null && mEnteringAnimator.isRunning()) {
|
||||
mEnteringAnimator.cancel();
|
||||
}
|
||||
|
||||
@@ -329,12 +330,10 @@ class CrossActivityAnimation {
|
||||
@Override
|
||||
public void onBackCancelled() {
|
||||
// End the fade in animation.
|
||||
if (mEnteringAnimator.isRunning()) {
|
||||
if (mEnteringAnimator != null && mEnteringAnimator.isRunning()) {
|
||||
mEnteringAnimator.cancel();
|
||||
}
|
||||
// TODO (b259608500): Let BackProgressAnimator could play cancel animation.
|
||||
mProgressAnimator.reset();
|
||||
finishAnimation();
|
||||
mProgressAnimator.onBackCancelled(CrossActivityAnimation.this::finishAnimation);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -329,8 +329,7 @@ class CrossTaskBackAnimation {
|
||||
|
||||
@Override
|
||||
public void onBackCancelled() {
|
||||
mProgressAnimator.reset();
|
||||
finishAnimation();
|
||||
mProgressAnimator.onBackCancelled(CrossTaskBackAnimation.this::finishAnimation);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
* 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 com.android.wm.shell.back;
|
||||
|
||||
import static android.window.BackEvent.EDGE_LEFT;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.testing.AndroidTestingRunner;
|
||||
import android.testing.TestableLooper;
|
||||
import android.window.BackEvent;
|
||||
import android.window.BackMotionEvent;
|
||||
import android.window.BackProgressAnimator;
|
||||
|
||||
import androidx.test.filters.SmallTest;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@SmallTest
|
||||
@TestableLooper.RunWithLooper
|
||||
@RunWith(AndroidTestingRunner.class)
|
||||
public class BackProgressAnimatorTest {
|
||||
private BackProgressAnimator mProgressAnimator;
|
||||
private BackEvent mReceivedBackEvent;
|
||||
private float mTargetProgress = 0.5f;
|
||||
private CountDownLatch mTargetProgressCalled = new CountDownLatch(1);
|
||||
private Handler mMainThreadHandler;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
mMainThreadHandler = new Handler(Looper.getMainLooper());
|
||||
final BackMotionEvent backEvent = new BackMotionEvent(
|
||||
0, 0,
|
||||
0, EDGE_LEFT, null);
|
||||
mMainThreadHandler.post(
|
||||
() -> {
|
||||
mProgressAnimator = new BackProgressAnimator();
|
||||
mProgressAnimator.onBackStarted(backEvent, this::onGestureProgress);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBackProgressed() throws InterruptedException {
|
||||
final BackMotionEvent backEvent = new BackMotionEvent(
|
||||
100, 0,
|
||||
mTargetProgress, EDGE_LEFT, null);
|
||||
mMainThreadHandler.post(
|
||||
() -> mProgressAnimator.onBackProgressed(backEvent));
|
||||
|
||||
mTargetProgressCalled.await(1, TimeUnit.SECONDS);
|
||||
|
||||
assertNotNull(mReceivedBackEvent);
|
||||
assertEquals(mReceivedBackEvent.getProgress(), mTargetProgress, 0 /* delta */);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBackCancelled() throws InterruptedException {
|
||||
// Give the animator some progress.
|
||||
final BackMotionEvent backEvent = new BackMotionEvent(
|
||||
100, 0,
|
||||
mTargetProgress, EDGE_LEFT, null);
|
||||
mMainThreadHandler.post(
|
||||
() -> mProgressAnimator.onBackProgressed(backEvent));
|
||||
mTargetProgressCalled.await(1, TimeUnit.SECONDS);
|
||||
assertNotNull(mReceivedBackEvent);
|
||||
|
||||
// Trigger animation cancel, the target progress should be 0.
|
||||
mTargetProgress = 0;
|
||||
mTargetProgressCalled = new CountDownLatch(1);
|
||||
CountDownLatch cancelCallbackCalled = new CountDownLatch(1);
|
||||
mMainThreadHandler.post(
|
||||
() -> mProgressAnimator.onBackCancelled(() -> cancelCallbackCalled.countDown()));
|
||||
cancelCallbackCalled.await(1, TimeUnit.SECONDS);
|
||||
mTargetProgressCalled.await(1, TimeUnit.SECONDS);
|
||||
assertNotNull(mReceivedBackEvent);
|
||||
assertEquals(mReceivedBackEvent.getProgress(), mTargetProgress, 0 /* delta */);
|
||||
}
|
||||
|
||||
private void onGestureProgress(BackEvent backEvent) {
|
||||
if (mTargetProgress == backEvent.getProgress()) {
|
||||
mReceivedBackEvent = backEvent;
|
||||
mTargetProgressCalled.countDown();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user