Loading libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java +6 −70 Original line number Diff line number Diff line Loading @@ -19,9 +19,6 @@ package com.android.wm.shell.back; import static com.android.wm.shell.common.ExecutorUtils.executeRemoteCallWithTaskPermission; import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_BACK_PREVIEW; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ValueAnimator; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityTaskManager; Loading Loading @@ -223,14 +220,11 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont private void initAnimation(MotionEvent event) { ProtoLog.d(WM_SHELL_BACK_PREVIEW, "initAnimation mMotionStarted=%b", mBackGestureStarted); if (mBackGestureStarted) { if (mBackGestureStarted || mBackNavigationInfo != null) { Log.e(TAG, "Animation is being initialized but is already started."); return; } if (mBackNavigationInfo != null) { finishAnimation(); } mInitTouchLocation.set(event.getX(), event.getY()); mBackGestureStarted = true; Loading Loading @@ -304,8 +298,6 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont return; } int deltaX = Math.round(event.getX() - mInitTouchLocation.x); int deltaY = Math.round(event.getY() - mInitTouchLocation.y); ProtoLog.v(WM_SHELL_BACK_PREVIEW, "Runner move: %d %d", deltaX, deltaY); float progressThreshold = PROGRESS_THRESHOLD >= 0 ? PROGRESS_THRESHOLD : mProgressThreshold; float progress = Math.min(Math.max(Math.abs(deltaX) / progressThreshold, 0), 1); int backType = mBackNavigationInfo.getType(); Loading @@ -317,11 +309,7 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont targetCallback = mBackToLauncherCallback; } else if (backType == BackNavigationInfo.TYPE_CROSS_TASK || backType == BackNavigationInfo.TYPE_CROSS_ACTIVITY) { if (animationTarget != null) { mTransaction.setPosition(animationTarget.leash, deltaX, deltaY); mTouchEventDelta.set(deltaX, deltaY); mTransaction.apply(); } // TODO(208427216) Run the actual animation } else if (backType == BackNavigationInfo.TYPE_CALLBACK) { targetCallback = mBackNavigationInfo.getOnBackInvokedCallback(); } Loading @@ -343,19 +331,9 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont } else { dispatchOnBackCancelled(targetCallback); } if (backType == BackNavigationInfo.TYPE_CALLBACK) { finishAnimation(); } else if (backType == BackNavigationInfo.TYPE_RETURN_TO_HOME && !shouldDispatchToLauncher) { if (backType != BackNavigationInfo.TYPE_RETURN_TO_HOME || !shouldDispatchToLauncher) { // Launcher callback missing. Simply finish animation. finishAnimation(); } else if (backType == BackNavigationInfo.TYPE_CROSS_ACTIVITY || backType == BackNavigationInfo.TYPE_CROSS_TASK) { if (mTriggerBack) { prepareTransition(); } else { resetPositionAnimated(); } } } Loading Loading @@ -403,8 +381,8 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont } } private static void dispatchOnBackProgressed( IOnBackInvokedCallback callback, BackEvent backEvent) { private static void dispatchOnBackProgressed(IOnBackInvokedCallback callback, BackEvent backEvent) { if (callback == null) { return; } Loading @@ -415,48 +393,6 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont } } /** * Animate the top window leash to its initial position. */ private void resetPositionAnimated() { mBackGestureStarted = false; // TODO(208786853) Handle overlap with a new coming gesture. ProtoLog.d(WM_SHELL_BACK_PREVIEW, "Runner: Back not triggered, cancelling animation " + "mLastPos=%s mInitTouch=%s", mTouchEventDelta, mInitTouchLocation); // TODO(208427216) : Replace placeholder animation with an actual one. ValueAnimator animation = ValueAnimator.ofFloat(0f, 1f).setDuration(200); animation.addUpdateListener(animation1 -> { if (mBackNavigationInfo == null) { return; } float fraction = animation1.getAnimatedFraction(); int deltaX = Math.round(mTouchEventDelta.x - (mTouchEventDelta.x * fraction)); int deltaY = Math.round(mTouchEventDelta.y - (mTouchEventDelta.y * fraction)); RemoteAnimationTarget animationTarget = mBackNavigationInfo.getDepartingAnimationTarget(); if (animationTarget != null) { mTransaction.setPosition(animationTarget.leash, deltaX, deltaY); mTransaction.apply(); } }); animation.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { ProtoLog.d(WM_SHELL_BACK_PREVIEW, "BackAnimationController: onAnimationEnd"); finishAnimation(); } }); animation.start(); } private void prepareTransition() { ProtoLog.d(WM_SHELL_BACK_PREVIEW, "prepareTransition()"); mTriggerBack = false; mBackGestureStarted = false; } /** * Sets to true when the back gesture has passed the triggering threshold, false otherwise. */ Loading libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java +48 −1 Original line number Diff line number Diff line Loading @@ -16,10 +16,16 @@ package com.android.wm.shell.back; import static android.window.BackNavigationInfo.KEY_TRIGGER_BACK; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import android.app.IActivityTaskManager; Loading Loading @@ -101,6 +107,14 @@ public class BackAnimationControllerTest { } } private void createNavigationInfo(BackNavigationInfo.Builder builder) { try { doReturn(builder.build()).when(mActivityTaskManager).startBackNavigation(); } catch (RemoteException ex) { ex.rethrowFromSystemServer(); } } RemoteAnimationTarget createAnimationTarget() { SurfaceControl topWindowLeash = new SurfaceControl(); return new RemoteAnimationTarget(-1, RemoteAnimationTarget.MODE_CLOSING, topWindowLeash, Loading @@ -109,6 +123,18 @@ public class BackAnimationControllerTest { true, null, null, null, false, -1); } private void triggerBackGesture() { MotionEvent event = MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 0, 0, 0); mController.onMotionEvent(event, event.getAction(), BackEvent.EDGE_LEFT); event = MotionEvent.obtain(10, 0, MotionEvent.ACTION_MOVE, 100, 100, 0); mController.onMotionEvent(event, event.getAction(), BackEvent.EDGE_LEFT); mController.setTriggerBack(true); event = MotionEvent.obtain(10, 0, MotionEvent.ACTION_UP, 100, 100, 0); mController.onMotionEvent(event, event.getAction(), BackEvent.EDGE_LEFT); } @Test @Ignore("b/207481538") public void crossActivity_screenshotAttachedAndVisible() { Loading Loading @@ -140,10 +166,31 @@ public class BackAnimationControllerTest { MotionEvent.obtain(10, 0, MotionEvent.ACTION_MOVE, 100, 100, 0), MotionEvent.ACTION_MOVE, BackEvent.EDGE_LEFT); verify(mTransaction).setPosition(animationTarget.leash, 100, 100); // b/207481538, we check that the surface is not moved for now, we can re-enable this once // we implement the animation verify(mTransaction, never()).setScale(eq(screenshotSurface), anyInt(), anyInt()); verify(mTransaction, never()).setPosition(animationTarget.leash, 100, 100); verify(mTransaction, atLeastOnce()).apply(); } @Test public void verifyAnimationFinishes() { RemoteAnimationTarget animationTarget = createAnimationTarget(); boolean[] backNavigationDone = new boolean[]{false}; boolean[] triggerBack = new boolean[]{false}; createNavigationInfo(new BackNavigationInfo.Builder() .setDepartingAnimationTarget(animationTarget) .setType(BackNavigationInfo.TYPE_CROSS_ACTIVITY) .setOnBackNavigationDone( new RemoteCallback(result -> { backNavigationDone[0] = true; triggerBack[0] = result.getBoolean(KEY_TRIGGER_BACK); }))); triggerBackGesture(); assertTrue("Navigation Done callback not called", backNavigationDone[0]); assertTrue("TriggerBack should have been true", triggerBack[0]); } @Test public void backToHome_dispatchesEvents() throws RemoteException { mController.setBackToLauncherCallback(mIOnBackInvokedCallback); Loading Loading
libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java +6 −70 Original line number Diff line number Diff line Loading @@ -19,9 +19,6 @@ package com.android.wm.shell.back; import static com.android.wm.shell.common.ExecutorUtils.executeRemoteCallWithTaskPermission; import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_BACK_PREVIEW; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ValueAnimator; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityTaskManager; Loading Loading @@ -223,14 +220,11 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont private void initAnimation(MotionEvent event) { ProtoLog.d(WM_SHELL_BACK_PREVIEW, "initAnimation mMotionStarted=%b", mBackGestureStarted); if (mBackGestureStarted) { if (mBackGestureStarted || mBackNavigationInfo != null) { Log.e(TAG, "Animation is being initialized but is already started."); return; } if (mBackNavigationInfo != null) { finishAnimation(); } mInitTouchLocation.set(event.getX(), event.getY()); mBackGestureStarted = true; Loading Loading @@ -304,8 +298,6 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont return; } int deltaX = Math.round(event.getX() - mInitTouchLocation.x); int deltaY = Math.round(event.getY() - mInitTouchLocation.y); ProtoLog.v(WM_SHELL_BACK_PREVIEW, "Runner move: %d %d", deltaX, deltaY); float progressThreshold = PROGRESS_THRESHOLD >= 0 ? PROGRESS_THRESHOLD : mProgressThreshold; float progress = Math.min(Math.max(Math.abs(deltaX) / progressThreshold, 0), 1); int backType = mBackNavigationInfo.getType(); Loading @@ -317,11 +309,7 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont targetCallback = mBackToLauncherCallback; } else if (backType == BackNavigationInfo.TYPE_CROSS_TASK || backType == BackNavigationInfo.TYPE_CROSS_ACTIVITY) { if (animationTarget != null) { mTransaction.setPosition(animationTarget.leash, deltaX, deltaY); mTouchEventDelta.set(deltaX, deltaY); mTransaction.apply(); } // TODO(208427216) Run the actual animation } else if (backType == BackNavigationInfo.TYPE_CALLBACK) { targetCallback = mBackNavigationInfo.getOnBackInvokedCallback(); } Loading @@ -343,19 +331,9 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont } else { dispatchOnBackCancelled(targetCallback); } if (backType == BackNavigationInfo.TYPE_CALLBACK) { finishAnimation(); } else if (backType == BackNavigationInfo.TYPE_RETURN_TO_HOME && !shouldDispatchToLauncher) { if (backType != BackNavigationInfo.TYPE_RETURN_TO_HOME || !shouldDispatchToLauncher) { // Launcher callback missing. Simply finish animation. finishAnimation(); } else if (backType == BackNavigationInfo.TYPE_CROSS_ACTIVITY || backType == BackNavigationInfo.TYPE_CROSS_TASK) { if (mTriggerBack) { prepareTransition(); } else { resetPositionAnimated(); } } } Loading Loading @@ -403,8 +381,8 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont } } private static void dispatchOnBackProgressed( IOnBackInvokedCallback callback, BackEvent backEvent) { private static void dispatchOnBackProgressed(IOnBackInvokedCallback callback, BackEvent backEvent) { if (callback == null) { return; } Loading @@ -415,48 +393,6 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont } } /** * Animate the top window leash to its initial position. */ private void resetPositionAnimated() { mBackGestureStarted = false; // TODO(208786853) Handle overlap with a new coming gesture. ProtoLog.d(WM_SHELL_BACK_PREVIEW, "Runner: Back not triggered, cancelling animation " + "mLastPos=%s mInitTouch=%s", mTouchEventDelta, mInitTouchLocation); // TODO(208427216) : Replace placeholder animation with an actual one. ValueAnimator animation = ValueAnimator.ofFloat(0f, 1f).setDuration(200); animation.addUpdateListener(animation1 -> { if (mBackNavigationInfo == null) { return; } float fraction = animation1.getAnimatedFraction(); int deltaX = Math.round(mTouchEventDelta.x - (mTouchEventDelta.x * fraction)); int deltaY = Math.round(mTouchEventDelta.y - (mTouchEventDelta.y * fraction)); RemoteAnimationTarget animationTarget = mBackNavigationInfo.getDepartingAnimationTarget(); if (animationTarget != null) { mTransaction.setPosition(animationTarget.leash, deltaX, deltaY); mTransaction.apply(); } }); animation.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { ProtoLog.d(WM_SHELL_BACK_PREVIEW, "BackAnimationController: onAnimationEnd"); finishAnimation(); } }); animation.start(); } private void prepareTransition() { ProtoLog.d(WM_SHELL_BACK_PREVIEW, "prepareTransition()"); mTriggerBack = false; mBackGestureStarted = false; } /** * Sets to true when the back gesture has passed the triggering threshold, false otherwise. */ Loading
libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java +48 −1 Original line number Diff line number Diff line Loading @@ -16,10 +16,16 @@ package com.android.wm.shell.back; import static android.window.BackNavigationInfo.KEY_TRIGGER_BACK; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import android.app.IActivityTaskManager; Loading Loading @@ -101,6 +107,14 @@ public class BackAnimationControllerTest { } } private void createNavigationInfo(BackNavigationInfo.Builder builder) { try { doReturn(builder.build()).when(mActivityTaskManager).startBackNavigation(); } catch (RemoteException ex) { ex.rethrowFromSystemServer(); } } RemoteAnimationTarget createAnimationTarget() { SurfaceControl topWindowLeash = new SurfaceControl(); return new RemoteAnimationTarget(-1, RemoteAnimationTarget.MODE_CLOSING, topWindowLeash, Loading @@ -109,6 +123,18 @@ public class BackAnimationControllerTest { true, null, null, null, false, -1); } private void triggerBackGesture() { MotionEvent event = MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 0, 0, 0); mController.onMotionEvent(event, event.getAction(), BackEvent.EDGE_LEFT); event = MotionEvent.obtain(10, 0, MotionEvent.ACTION_MOVE, 100, 100, 0); mController.onMotionEvent(event, event.getAction(), BackEvent.EDGE_LEFT); mController.setTriggerBack(true); event = MotionEvent.obtain(10, 0, MotionEvent.ACTION_UP, 100, 100, 0); mController.onMotionEvent(event, event.getAction(), BackEvent.EDGE_LEFT); } @Test @Ignore("b/207481538") public void crossActivity_screenshotAttachedAndVisible() { Loading Loading @@ -140,10 +166,31 @@ public class BackAnimationControllerTest { MotionEvent.obtain(10, 0, MotionEvent.ACTION_MOVE, 100, 100, 0), MotionEvent.ACTION_MOVE, BackEvent.EDGE_LEFT); verify(mTransaction).setPosition(animationTarget.leash, 100, 100); // b/207481538, we check that the surface is not moved for now, we can re-enable this once // we implement the animation verify(mTransaction, never()).setScale(eq(screenshotSurface), anyInt(), anyInt()); verify(mTransaction, never()).setPosition(animationTarget.leash, 100, 100); verify(mTransaction, atLeastOnce()).apply(); } @Test public void verifyAnimationFinishes() { RemoteAnimationTarget animationTarget = createAnimationTarget(); boolean[] backNavigationDone = new boolean[]{false}; boolean[] triggerBack = new boolean[]{false}; createNavigationInfo(new BackNavigationInfo.Builder() .setDepartingAnimationTarget(animationTarget) .setType(BackNavigationInfo.TYPE_CROSS_ACTIVITY) .setOnBackNavigationDone( new RemoteCallback(result -> { backNavigationDone[0] = true; triggerBack[0] = result.getBoolean(KEY_TRIGGER_BACK); }))); triggerBackGesture(); assertTrue("Navigation Done callback not called", backNavigationDone[0]); assertTrue("TriggerBack should have been true", triggerBack[0]); } @Test public void backToHome_dispatchesEvents() throws RemoteException { mController.setBackToLauncherCallback(mIOnBackInvokedCallback); Loading