Loading libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java +50 −43 Original line number Diff line number Diff line Loading @@ -116,7 +116,7 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont private final TouchTracker mTouchTracker = new TouchTracker(); private final SparseArray<BackAnimationRunner> mAnimationDefinition = new SparseArray<>(); @Nullable private IOnBackInvokedCallback mActiveCallback; @VisibleForTesting Loading Loading @@ -180,6 +180,10 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont } private void initBackAnimationRunners() { if (!IS_U_ANIMATION_ENABLED) { return; } final CrossTaskBackAnimation crossTaskAnimation = new CrossTaskBackAnimation(mContext); mAnimationDefinition.set(BackNavigationInfo.TYPE_CROSS_TASK, new BackAnimationRunner(crossTaskAnimation.mCallback, crossTaskAnimation.mRunner)); Loading Loading @@ -207,7 +211,7 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont private void updateEnableAnimationFromSetting() { int settingValue = Global.getInt(mContext.getContentResolver(), Global.ENABLE_BACK_ANIMATION, SETTING_VALUE_OFF); boolean isEnabled = settingValue == SETTING_VALUE_ON && IS_U_ANIMATION_ENABLED; boolean isEnabled = settingValue == SETTING_VALUE_ON; mEnableAnimations.set(isEnabled); ProtoLog.d(WM_SHELL_BACK_PREVIEW, "Back animation enabled=%s", isEnabled); } Loading Loading @@ -350,10 +354,14 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont return; } final int backType = backNavigationInfo.getType(); final boolean shouldDispatchToAnimator = shouldDispatchToAnimator(backType); final boolean shouldDispatchToAnimator = shouldDispatchToAnimator(); if (shouldDispatchToAnimator) { if (mAnimationDefinition.contains(backType)) { mActiveCallback = mAnimationDefinition.get(backType).getCallback(); mAnimationDefinition.get(backType).startGesture(); } else { mActiveCallback = null; } } else { mActiveCallback = mBackNavigationInfo.getOnBackInvokedCallback(); dispatchOnBackStarted(mActiveCallback, mTouchTracker.createStartEvent(null)); Loading @@ -361,9 +369,11 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont } private void onMove() { if (!mBackGestureStarted || mBackNavigationInfo == null || !mEnableAnimations.get()) { if (!mBackGestureStarted || mBackNavigationInfo == null || !mEnableAnimations.get() || mActiveCallback == null) { return; } final BackEvent backEvent = mTouchTracker.createProgressEvent(); dispatchOnBackProgressed(mActiveCallback, backEvent); } Loading @@ -387,11 +397,10 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont } } private boolean shouldDispatchToAnimator(int backType) { private boolean shouldDispatchToAnimator() { return mEnableAnimations.get() && mBackNavigationInfo != null && mBackNavigationInfo.isPrepareRemoteAnimation() && mAnimationDefinition.contains(backType); && mBackNavigationInfo.isPrepareRemoteAnimation(); } private void dispatchOnBackStarted(IOnBackInvokedCallback callback, Loading Loading @@ -461,6 +470,30 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont mTouchTracker.setProgressThreshold(progressThreshold); } private void invokeOrCancelBack() { // Make a synchronized call to core before dispatch back event to client side. // If the close transition happens before the core receives onAnimationFinished, there will // play a second close animation for that transition. if (mBackAnimationFinishedCallback != null) { try { mBackAnimationFinishedCallback.onAnimationFinished(mTriggerBack); } catch (RemoteException e) { Log.e(TAG, "Failed call IBackAnimationFinishedCallback", e); } mBackAnimationFinishedCallback = null; } if (mBackNavigationInfo != null) { final IOnBackInvokedCallback callback = mBackNavigationInfo.getOnBackInvokedCallback(); if (mTriggerBack) { dispatchOnBackInvoked(callback); } else { dispatchOnBackCancelled(callback); } } finishBackNavigation(); } /** * Called when the gesture is released, then it could start the post commit animation. */ Loading Loading @@ -493,15 +526,9 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont } final int backType = mBackNavigationInfo.getType(); // Directly finish back navigation if no animator defined. if (!shouldDispatchToAnimator(backType)) { if (mTriggerBack) { dispatchOnBackInvoked(mActiveCallback); } else { dispatchOnBackCancelled(mActiveCallback); } // Animation missing. Simply finish back navigation. finishBackNavigation(); // Simply trigger and finish back navigation when no animator defined. if (!shouldDispatchToAnimator() || mActiveCallback == null) { invokeOrCancelBack(); return; } Loading Loading @@ -549,16 +576,7 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont ProtoLog.d(WM_SHELL_BACK_PREVIEW, "BackAnimationController: onBackAnimationFinished()"); // Trigger the real back. if (mBackNavigationInfo != null) { IOnBackInvokedCallback callback = mBackNavigationInfo.getOnBackInvokedCallback(); if (mTriggerBack) { dispatchOnBackInvoked(callback); } else { dispatchOnBackCancelled(callback); } } finishBackNavigation(); invokeOrCancelBack(); } /** Loading @@ -567,25 +585,14 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont @VisibleForTesting void finishBackNavigation() { ProtoLog.d(WM_SHELL_BACK_PREVIEW, "BackAnimationController: finishBackNavigation()"); BackNavigationInfo backNavigationInfo = mBackNavigationInfo; boolean triggerBack = mTriggerBack; mBackNavigationInfo = null; mTriggerBack = false; mShouldStartOnNextMoveEvent = false; mTouchTracker.reset(); mActiveCallback = null; if (backNavigationInfo == null) { return; } if (mBackAnimationFinishedCallback != null) { try { mBackAnimationFinishedCallback.onAnimationFinished(triggerBack); } catch (RemoteException e) { Log.e(TAG, "Failed call IBackAnimationFinishedCallback", e); } mBackAnimationFinishedCallback = null; if (mBackNavigationInfo != null) { mBackNavigationInfo.onBackNavigationFinished(mTriggerBack); mBackNavigationInfo = null; } backNavigationInfo.onBackNavigationFinished(triggerBack); mTriggerBack = false; } private void createAdapter() { Loading libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java +75 −12 Original line number Diff line number Diff line Loading @@ -38,6 +38,7 @@ import android.app.WindowConfiguration; import android.content.pm.ApplicationInfo; import android.graphics.Point; import android.graphics.Rect; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.RemoteCallback; Loading @@ -56,6 +57,7 @@ import android.window.BackNavigationInfo; import android.window.IBackAnimationFinishedCallback; import android.window.IOnBackInvokedCallback; import androidx.annotation.Nullable; import androidx.test.filters.SmallTest; import androidx.test.platform.app.InstrumentationRegistry; Loading Loading @@ -189,31 +191,23 @@ public class BackAnimationControllerTest extends ShellTestCase { } for (int type: testTypes) { boolean[] backNavigationDone = new boolean[]{false}; boolean[] triggerBack = new boolean[]{false}; final ResultListener result = new ResultListener(); createNavigationInfo(new BackNavigationInfo.Builder() .setType(type) .setOnBackInvokedCallback(mAppCallback) .setPrepareRemoteAnimation(true) .setOnBackNavigationDone( new RemoteCallback(result -> { backNavigationDone[0] = true; triggerBack[0] = result.getBoolean(KEY_TRIGGER_BACK); }))); .setOnBackNavigationDone(new RemoteCallback(result))); triggerBackGesture(); simulateRemoteAnimationStart(type); simulateRemoteAnimationFinished(); mShellExecutor.flushAll(); assertTrue("Navigation Done callback not called for " + BackNavigationInfo.typeToString(type), backNavigationDone[0]); assertTrue("TriggerBack should have been true", triggerBack[0]); + BackNavigationInfo.typeToString(type), result.mBackNavigationDone); assertTrue("TriggerBack should have been true", result.mTriggerBack); } } @Test public void backToHome_dispatchesEvents() throws RemoteException { registerAnimation(BackNavigationInfo.TYPE_RETURN_TO_HOME); Loading Loading @@ -351,6 +345,65 @@ public class BackAnimationControllerTest extends ShellTestCase { verify(mAnimatorCallback, never()).onBackInvoked(); } @Test public void animationNotDefined() throws RemoteException { final int[] testTypes = new int[] { BackNavigationInfo.TYPE_RETURN_TO_HOME, BackNavigationInfo.TYPE_CROSS_TASK, BackNavigationInfo.TYPE_CROSS_ACTIVITY, BackNavigationInfo.TYPE_DIALOG_CLOSE}; for (int type: testTypes) { final ResultListener result = new ResultListener(); createNavigationInfo(new BackNavigationInfo.Builder() .setType(type) .setOnBackInvokedCallback(mAppCallback) .setPrepareRemoteAnimation(true) .setOnBackNavigationDone(new RemoteCallback(result))); triggerBackGesture(); simulateRemoteAnimationStart(type); mShellExecutor.flushAll(); assertTrue("Navigation Done callback not called for " + BackNavigationInfo.typeToString(type), result.mBackNavigationDone); assertTrue("TriggerBack should have been true", result.mTriggerBack); } verify(mAppCallback, never()).onBackStarted(any()); verify(mAppCallback, never()).onBackProgressed(any()); verify(mAppCallback, times(testTypes.length)).onBackInvoked(); verify(mAnimatorCallback, never()).onBackStarted(any()); verify(mAnimatorCallback, never()).onBackProgressed(any()); verify(mAnimatorCallback, never()).onBackInvoked(); } @Test public void callbackShouldDeliverProgress() throws RemoteException { registerAnimation(BackNavigationInfo.TYPE_RETURN_TO_HOME); final int type = BackNavigationInfo.TYPE_CALLBACK; final ResultListener result = new ResultListener(); createNavigationInfo(new BackNavigationInfo.Builder() .setType(type) .setOnBackInvokedCallback(mAppCallback) .setOnBackNavigationDone(new RemoteCallback(result))); triggerBackGesture(); mShellExecutor.flushAll(); assertTrue("Navigation Done callback not called for " + BackNavigationInfo.typeToString(type), result.mBackNavigationDone); assertTrue("TriggerBack should have been true", result.mTriggerBack); verify(mAppCallback, times(1)).onBackStarted(any()); verify(mAppCallback, times(1)).onBackProgressed(any()); verify(mAppCallback, times(1)).onBackInvoked(); verify(mAnimatorCallback, never()).onBackStarted(any()); verify(mAnimatorCallback, never()).onBackProgressed(any()); verify(mAnimatorCallback, never()).onBackInvoked(); } private void doMotionEvent(int actionDown, int coordinate) { mController.onMotionEvent( coordinate, coordinate, Loading @@ -377,4 +430,14 @@ public class BackAnimationControllerTest extends ShellTestCase { mController.registerAnimation(type, new BackAnimationRunner(mAnimatorCallback, mBackAnimationRunner)); } private static class ResultListener implements RemoteCallback.OnResultListener { boolean mBackNavigationDone = false; boolean mTriggerBack = false; @Override public void onResult(@Nullable Bundle result) { mBackNavigationDone = true; mTriggerBack = result.getBoolean(KEY_TRIGGER_BACK); } }; } Loading
libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java +50 −43 Original line number Diff line number Diff line Loading @@ -116,7 +116,7 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont private final TouchTracker mTouchTracker = new TouchTracker(); private final SparseArray<BackAnimationRunner> mAnimationDefinition = new SparseArray<>(); @Nullable private IOnBackInvokedCallback mActiveCallback; @VisibleForTesting Loading Loading @@ -180,6 +180,10 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont } private void initBackAnimationRunners() { if (!IS_U_ANIMATION_ENABLED) { return; } final CrossTaskBackAnimation crossTaskAnimation = new CrossTaskBackAnimation(mContext); mAnimationDefinition.set(BackNavigationInfo.TYPE_CROSS_TASK, new BackAnimationRunner(crossTaskAnimation.mCallback, crossTaskAnimation.mRunner)); Loading Loading @@ -207,7 +211,7 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont private void updateEnableAnimationFromSetting() { int settingValue = Global.getInt(mContext.getContentResolver(), Global.ENABLE_BACK_ANIMATION, SETTING_VALUE_OFF); boolean isEnabled = settingValue == SETTING_VALUE_ON && IS_U_ANIMATION_ENABLED; boolean isEnabled = settingValue == SETTING_VALUE_ON; mEnableAnimations.set(isEnabled); ProtoLog.d(WM_SHELL_BACK_PREVIEW, "Back animation enabled=%s", isEnabled); } Loading Loading @@ -350,10 +354,14 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont return; } final int backType = backNavigationInfo.getType(); final boolean shouldDispatchToAnimator = shouldDispatchToAnimator(backType); final boolean shouldDispatchToAnimator = shouldDispatchToAnimator(); if (shouldDispatchToAnimator) { if (mAnimationDefinition.contains(backType)) { mActiveCallback = mAnimationDefinition.get(backType).getCallback(); mAnimationDefinition.get(backType).startGesture(); } else { mActiveCallback = null; } } else { mActiveCallback = mBackNavigationInfo.getOnBackInvokedCallback(); dispatchOnBackStarted(mActiveCallback, mTouchTracker.createStartEvent(null)); Loading @@ -361,9 +369,11 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont } private void onMove() { if (!mBackGestureStarted || mBackNavigationInfo == null || !mEnableAnimations.get()) { if (!mBackGestureStarted || mBackNavigationInfo == null || !mEnableAnimations.get() || mActiveCallback == null) { return; } final BackEvent backEvent = mTouchTracker.createProgressEvent(); dispatchOnBackProgressed(mActiveCallback, backEvent); } Loading @@ -387,11 +397,10 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont } } private boolean shouldDispatchToAnimator(int backType) { private boolean shouldDispatchToAnimator() { return mEnableAnimations.get() && mBackNavigationInfo != null && mBackNavigationInfo.isPrepareRemoteAnimation() && mAnimationDefinition.contains(backType); && mBackNavigationInfo.isPrepareRemoteAnimation(); } private void dispatchOnBackStarted(IOnBackInvokedCallback callback, Loading Loading @@ -461,6 +470,30 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont mTouchTracker.setProgressThreshold(progressThreshold); } private void invokeOrCancelBack() { // Make a synchronized call to core before dispatch back event to client side. // If the close transition happens before the core receives onAnimationFinished, there will // play a second close animation for that transition. if (mBackAnimationFinishedCallback != null) { try { mBackAnimationFinishedCallback.onAnimationFinished(mTriggerBack); } catch (RemoteException e) { Log.e(TAG, "Failed call IBackAnimationFinishedCallback", e); } mBackAnimationFinishedCallback = null; } if (mBackNavigationInfo != null) { final IOnBackInvokedCallback callback = mBackNavigationInfo.getOnBackInvokedCallback(); if (mTriggerBack) { dispatchOnBackInvoked(callback); } else { dispatchOnBackCancelled(callback); } } finishBackNavigation(); } /** * Called when the gesture is released, then it could start the post commit animation. */ Loading Loading @@ -493,15 +526,9 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont } final int backType = mBackNavigationInfo.getType(); // Directly finish back navigation if no animator defined. if (!shouldDispatchToAnimator(backType)) { if (mTriggerBack) { dispatchOnBackInvoked(mActiveCallback); } else { dispatchOnBackCancelled(mActiveCallback); } // Animation missing. Simply finish back navigation. finishBackNavigation(); // Simply trigger and finish back navigation when no animator defined. if (!shouldDispatchToAnimator() || mActiveCallback == null) { invokeOrCancelBack(); return; } Loading Loading @@ -549,16 +576,7 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont ProtoLog.d(WM_SHELL_BACK_PREVIEW, "BackAnimationController: onBackAnimationFinished()"); // Trigger the real back. if (mBackNavigationInfo != null) { IOnBackInvokedCallback callback = mBackNavigationInfo.getOnBackInvokedCallback(); if (mTriggerBack) { dispatchOnBackInvoked(callback); } else { dispatchOnBackCancelled(callback); } } finishBackNavigation(); invokeOrCancelBack(); } /** Loading @@ -567,25 +585,14 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont @VisibleForTesting void finishBackNavigation() { ProtoLog.d(WM_SHELL_BACK_PREVIEW, "BackAnimationController: finishBackNavigation()"); BackNavigationInfo backNavigationInfo = mBackNavigationInfo; boolean triggerBack = mTriggerBack; mBackNavigationInfo = null; mTriggerBack = false; mShouldStartOnNextMoveEvent = false; mTouchTracker.reset(); mActiveCallback = null; if (backNavigationInfo == null) { return; } if (mBackAnimationFinishedCallback != null) { try { mBackAnimationFinishedCallback.onAnimationFinished(triggerBack); } catch (RemoteException e) { Log.e(TAG, "Failed call IBackAnimationFinishedCallback", e); } mBackAnimationFinishedCallback = null; if (mBackNavigationInfo != null) { mBackNavigationInfo.onBackNavigationFinished(mTriggerBack); mBackNavigationInfo = null; } backNavigationInfo.onBackNavigationFinished(triggerBack); mTriggerBack = false; } private void createAdapter() { Loading
libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java +75 −12 Original line number Diff line number Diff line Loading @@ -38,6 +38,7 @@ import android.app.WindowConfiguration; import android.content.pm.ApplicationInfo; import android.graphics.Point; import android.graphics.Rect; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.RemoteCallback; Loading @@ -56,6 +57,7 @@ import android.window.BackNavigationInfo; import android.window.IBackAnimationFinishedCallback; import android.window.IOnBackInvokedCallback; import androidx.annotation.Nullable; import androidx.test.filters.SmallTest; import androidx.test.platform.app.InstrumentationRegistry; Loading Loading @@ -189,31 +191,23 @@ public class BackAnimationControllerTest extends ShellTestCase { } for (int type: testTypes) { boolean[] backNavigationDone = new boolean[]{false}; boolean[] triggerBack = new boolean[]{false}; final ResultListener result = new ResultListener(); createNavigationInfo(new BackNavigationInfo.Builder() .setType(type) .setOnBackInvokedCallback(mAppCallback) .setPrepareRemoteAnimation(true) .setOnBackNavigationDone( new RemoteCallback(result -> { backNavigationDone[0] = true; triggerBack[0] = result.getBoolean(KEY_TRIGGER_BACK); }))); .setOnBackNavigationDone(new RemoteCallback(result))); triggerBackGesture(); simulateRemoteAnimationStart(type); simulateRemoteAnimationFinished(); mShellExecutor.flushAll(); assertTrue("Navigation Done callback not called for " + BackNavigationInfo.typeToString(type), backNavigationDone[0]); assertTrue("TriggerBack should have been true", triggerBack[0]); + BackNavigationInfo.typeToString(type), result.mBackNavigationDone); assertTrue("TriggerBack should have been true", result.mTriggerBack); } } @Test public void backToHome_dispatchesEvents() throws RemoteException { registerAnimation(BackNavigationInfo.TYPE_RETURN_TO_HOME); Loading Loading @@ -351,6 +345,65 @@ public class BackAnimationControllerTest extends ShellTestCase { verify(mAnimatorCallback, never()).onBackInvoked(); } @Test public void animationNotDefined() throws RemoteException { final int[] testTypes = new int[] { BackNavigationInfo.TYPE_RETURN_TO_HOME, BackNavigationInfo.TYPE_CROSS_TASK, BackNavigationInfo.TYPE_CROSS_ACTIVITY, BackNavigationInfo.TYPE_DIALOG_CLOSE}; for (int type: testTypes) { final ResultListener result = new ResultListener(); createNavigationInfo(new BackNavigationInfo.Builder() .setType(type) .setOnBackInvokedCallback(mAppCallback) .setPrepareRemoteAnimation(true) .setOnBackNavigationDone(new RemoteCallback(result))); triggerBackGesture(); simulateRemoteAnimationStart(type); mShellExecutor.flushAll(); assertTrue("Navigation Done callback not called for " + BackNavigationInfo.typeToString(type), result.mBackNavigationDone); assertTrue("TriggerBack should have been true", result.mTriggerBack); } verify(mAppCallback, never()).onBackStarted(any()); verify(mAppCallback, never()).onBackProgressed(any()); verify(mAppCallback, times(testTypes.length)).onBackInvoked(); verify(mAnimatorCallback, never()).onBackStarted(any()); verify(mAnimatorCallback, never()).onBackProgressed(any()); verify(mAnimatorCallback, never()).onBackInvoked(); } @Test public void callbackShouldDeliverProgress() throws RemoteException { registerAnimation(BackNavigationInfo.TYPE_RETURN_TO_HOME); final int type = BackNavigationInfo.TYPE_CALLBACK; final ResultListener result = new ResultListener(); createNavigationInfo(new BackNavigationInfo.Builder() .setType(type) .setOnBackInvokedCallback(mAppCallback) .setOnBackNavigationDone(new RemoteCallback(result))); triggerBackGesture(); mShellExecutor.flushAll(); assertTrue("Navigation Done callback not called for " + BackNavigationInfo.typeToString(type), result.mBackNavigationDone); assertTrue("TriggerBack should have been true", result.mTriggerBack); verify(mAppCallback, times(1)).onBackStarted(any()); verify(mAppCallback, times(1)).onBackProgressed(any()); verify(mAppCallback, times(1)).onBackInvoked(); verify(mAnimatorCallback, never()).onBackStarted(any()); verify(mAnimatorCallback, never()).onBackProgressed(any()); verify(mAnimatorCallback, never()).onBackInvoked(); } private void doMotionEvent(int actionDown, int coordinate) { mController.onMotionEvent( coordinate, coordinate, Loading @@ -377,4 +430,14 @@ public class BackAnimationControllerTest extends ShellTestCase { mController.registerAnimation(type, new BackAnimationRunner(mAnimatorCallback, mBackAnimationRunner)); } private static class ResultListener implements RemoteCallback.OnResultListener { boolean mBackNavigationDone = false; boolean mTriggerBack = false; @Override public void onResult(@Nullable Bundle result) { mBackNavigationDone = true; mTriggerBack = result.getBoolean(KEY_TRIGGER_BACK); } }; }