Loading libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java +2 −1 Original line number Diff line number Diff line Loading @@ -597,9 +597,10 @@ public abstract class WMShellModule { TransactionPool transactionPool, Transitions transitions, @ShellMainThread ShellExecutor executor, @ShellMainThread Handler handler, ShellInit shellInit) { return new UnfoldTransitionHandler(shellInit, progressProvider.get(), animator, unfoldAnimator, transactionPool, executor, transitions); unfoldAnimator, transactionPool, executor, handler, transitions); } @WMSingleton Loading libs/WindowManager/Shell/src/com/android/wm/shell/unfold/UnfoldTransitionHandler.java +22 −0 Original line number Diff line number Diff line Loading @@ -24,7 +24,9 @@ import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_TRANSITI import android.animation.ValueAnimator; import android.app.ActivityManager; import android.os.Handler; import android.os.IBinder; import android.util.Slog; import android.view.SurfaceControl; import android.window.TransitionInfo; import android.window.TransitionRequestInfo; Loading @@ -33,6 +35,7 @@ import android.window.WindowContainerTransaction; import androidx.annotation.IntDef; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; import com.android.internal.protolog.ProtoLog; import com.android.wm.shell.shared.TransactionPool; Loading @@ -59,6 +62,10 @@ import java.util.concurrent.Executor; */ public class UnfoldTransitionHandler implements TransitionHandler, UnfoldListener { private static final String TAG = "UnfoldTransitionHandler"; @VisibleForTesting static final int FINISH_ANIMATION_TIMEOUT_MILLIS = 5_000; @Retention(RetentionPolicy.SOURCE) @IntDef({ DefaultDisplayChange.DEFAULT_DISPLAY_NO_CHANGE, Loading @@ -75,6 +82,7 @@ public class UnfoldTransitionHandler implements TransitionHandler, UnfoldListene private final Transitions mTransitions; private final Executor mExecutor; private final TransactionPool mTransactionPool; private final Handler mHandler; @Nullable private TransitionFinishCallback mFinishCallback; Loading @@ -87,17 +95,25 @@ public class UnfoldTransitionHandler implements TransitionHandler, UnfoldListene private float mLastAnimationProgress = 0.0f; private final List<UnfoldTaskAnimator> mAnimators = new ArrayList<>(); private final Runnable mAnimationPlayingTimeoutRunnable = () -> { Slog.wtf(TAG, "Timeout occurred when playing the unfold animation, " + "force finishing the transition"); finishTransitionIfNeeded(); }; public UnfoldTransitionHandler(ShellInit shellInit, ShellUnfoldProgressProvider unfoldProgressProvider, FullscreenUnfoldTaskAnimator fullscreenUnfoldAnimator, SplitTaskUnfoldAnimator splitUnfoldTaskAnimator, TransactionPool transactionPool, Executor executor, Handler handler, Transitions transitions) { mUnfoldProgressProvider = unfoldProgressProvider; mTransitions = transitions; mTransactionPool = transactionPool; mExecutor = executor; mHandler = handler; mAnimators.add(splitUnfoldTaskAnimator); mAnimators.add(fullscreenUnfoldAnimator); Loading Loading @@ -159,6 +175,11 @@ public class UnfoldTransitionHandler implements TransitionHandler, UnfoldListene // finish shell transition immediately if (mAnimationFinished) { finishTransitionIfNeeded(); } else { // TODO: b/318803244 - remove timeout handling when we could guarantee that // the animation will be always finished after receiving startAnimation mHandler.removeCallbacks(mAnimationPlayingTimeoutRunnable); mHandler.postDelayed(mAnimationPlayingTimeoutRunnable, FINISH_ANIMATION_TIMEOUT_MILLIS); } return true; Loading Loading @@ -333,6 +354,7 @@ public class UnfoldTransitionHandler implements TransitionHandler, UnfoldListene animator.stop(); } mHandler.removeCallbacks(mAnimationPlayingTimeoutRunnable); mFinishCallback.onTransitionFinished(null); mFinishCallback = null; mTransition = null; Loading libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/unfold/UnfoldTransitionHandlerTest.java +30 −0 Original line number Diff line number Diff line Loading @@ -20,6 +20,8 @@ import static android.view.WindowManager.TRANSIT_CHANGE; import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY; import static android.view.WindowManager.TRANSIT_NONE; import static com.android.wm.shell.unfold.UnfoldTransitionHandler.FINISH_ANIMATION_TIMEOUT_MILLIS; import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; Loading @@ -32,7 +34,9 @@ import static org.mockito.Mockito.verify; import android.app.ActivityManager; import android.graphics.Rect; import android.os.Binder; import android.os.Handler; import android.os.IBinder; import android.os.test.TestLooper; import android.view.Display; import android.view.SurfaceControl; import android.window.TransitionInfo; Loading Loading @@ -67,6 +71,8 @@ public class UnfoldTransitionHandlerTest { private FullscreenUnfoldTaskAnimator mFullscreenUnfoldTaskAnimator; private SplitTaskUnfoldAnimator mSplitTaskUnfoldAnimator; private Transitions mTransitions; private TestLooper mTestLooper; private Handler mHandler; private final IBinder mTransition = new Binder(); Loading @@ -75,6 +81,9 @@ public class UnfoldTransitionHandlerTest { final ShellExecutor executor = new TestSyncExecutor(); final ShellInit shellInit = new ShellInit(executor); mTestLooper = new TestLooper(); mHandler = new Handler(mTestLooper.getLooper()); mFullscreenUnfoldTaskAnimator = mock(FullscreenUnfoldTaskAnimator.class); mSplitTaskUnfoldAnimator = mock(SplitTaskUnfoldAnimator.class); mTransitions = mock(Transitions.class); Loading @@ -86,6 +95,7 @@ public class UnfoldTransitionHandlerTest { mSplitTaskUnfoldAnimator, mTransactionPool, executor, mHandler, mTransitions ); Loading Loading @@ -159,6 +169,7 @@ public class UnfoldTransitionHandlerTest { TransitionFinishCallback mergeFinishCallback = mock(TransitionFinishCallback.class); mUnfoldTransitionHandler.mergeAnimation(new Binder(), createFoldTransitionInfo(), mock(SurfaceControl.Transaction.class), mTransition, mergeFinishCallback); mTestLooper.dispatchAll(); // Verify that fold transition is merged into unfold and that unfold is finished final InOrder inOrder = inOrder(mergeFinishCallback, finishCallback); Loading Loading @@ -200,6 +211,25 @@ public class UnfoldTransitionHandlerTest { assertThat(animationStarted).isTrue(); } @Test public void startAnimation_animationHasNotFinishedAfterTimeout_finishesTheTransition() { TransitionRequestInfo requestInfo = createUnfoldTransitionRequestInfo(); mUnfoldTransitionHandler.handleRequest(mTransition, requestInfo); TransitionFinishCallback finishCallback = mock(TransitionFinishCallback.class); mUnfoldTransitionHandler.startAnimation( mTransition, mock(TransitionInfo.class), mock(SurfaceControl.Transaction.class), mock(SurfaceControl.Transaction.class), finishCallback ); mTestLooper.moveTimeForward(FINISH_ANIMATION_TIMEOUT_MILLIS + 1); mTestLooper.dispatchAll(); verify(finishCallback).onTransitionFinished(any()); } @Test public void startAnimation_differentTransitionFromRequestWithResize_doesNotStartAnimation() { mUnfoldTransitionHandler.handleRequest(new Binder(), createNoneTransitionInfo()); Loading Loading
libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java +2 −1 Original line number Diff line number Diff line Loading @@ -597,9 +597,10 @@ public abstract class WMShellModule { TransactionPool transactionPool, Transitions transitions, @ShellMainThread ShellExecutor executor, @ShellMainThread Handler handler, ShellInit shellInit) { return new UnfoldTransitionHandler(shellInit, progressProvider.get(), animator, unfoldAnimator, transactionPool, executor, transitions); unfoldAnimator, transactionPool, executor, handler, transitions); } @WMSingleton Loading
libs/WindowManager/Shell/src/com/android/wm/shell/unfold/UnfoldTransitionHandler.java +22 −0 Original line number Diff line number Diff line Loading @@ -24,7 +24,9 @@ import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_TRANSITI import android.animation.ValueAnimator; import android.app.ActivityManager; import android.os.Handler; import android.os.IBinder; import android.util.Slog; import android.view.SurfaceControl; import android.window.TransitionInfo; import android.window.TransitionRequestInfo; Loading @@ -33,6 +35,7 @@ import android.window.WindowContainerTransaction; import androidx.annotation.IntDef; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; import com.android.internal.protolog.ProtoLog; import com.android.wm.shell.shared.TransactionPool; Loading @@ -59,6 +62,10 @@ import java.util.concurrent.Executor; */ public class UnfoldTransitionHandler implements TransitionHandler, UnfoldListener { private static final String TAG = "UnfoldTransitionHandler"; @VisibleForTesting static final int FINISH_ANIMATION_TIMEOUT_MILLIS = 5_000; @Retention(RetentionPolicy.SOURCE) @IntDef({ DefaultDisplayChange.DEFAULT_DISPLAY_NO_CHANGE, Loading @@ -75,6 +82,7 @@ public class UnfoldTransitionHandler implements TransitionHandler, UnfoldListene private final Transitions mTransitions; private final Executor mExecutor; private final TransactionPool mTransactionPool; private final Handler mHandler; @Nullable private TransitionFinishCallback mFinishCallback; Loading @@ -87,17 +95,25 @@ public class UnfoldTransitionHandler implements TransitionHandler, UnfoldListene private float mLastAnimationProgress = 0.0f; private final List<UnfoldTaskAnimator> mAnimators = new ArrayList<>(); private final Runnable mAnimationPlayingTimeoutRunnable = () -> { Slog.wtf(TAG, "Timeout occurred when playing the unfold animation, " + "force finishing the transition"); finishTransitionIfNeeded(); }; public UnfoldTransitionHandler(ShellInit shellInit, ShellUnfoldProgressProvider unfoldProgressProvider, FullscreenUnfoldTaskAnimator fullscreenUnfoldAnimator, SplitTaskUnfoldAnimator splitUnfoldTaskAnimator, TransactionPool transactionPool, Executor executor, Handler handler, Transitions transitions) { mUnfoldProgressProvider = unfoldProgressProvider; mTransitions = transitions; mTransactionPool = transactionPool; mExecutor = executor; mHandler = handler; mAnimators.add(splitUnfoldTaskAnimator); mAnimators.add(fullscreenUnfoldAnimator); Loading Loading @@ -159,6 +175,11 @@ public class UnfoldTransitionHandler implements TransitionHandler, UnfoldListene // finish shell transition immediately if (mAnimationFinished) { finishTransitionIfNeeded(); } else { // TODO: b/318803244 - remove timeout handling when we could guarantee that // the animation will be always finished after receiving startAnimation mHandler.removeCallbacks(mAnimationPlayingTimeoutRunnable); mHandler.postDelayed(mAnimationPlayingTimeoutRunnable, FINISH_ANIMATION_TIMEOUT_MILLIS); } return true; Loading Loading @@ -333,6 +354,7 @@ public class UnfoldTransitionHandler implements TransitionHandler, UnfoldListene animator.stop(); } mHandler.removeCallbacks(mAnimationPlayingTimeoutRunnable); mFinishCallback.onTransitionFinished(null); mFinishCallback = null; mTransition = null; Loading
libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/unfold/UnfoldTransitionHandlerTest.java +30 −0 Original line number Diff line number Diff line Loading @@ -20,6 +20,8 @@ import static android.view.WindowManager.TRANSIT_CHANGE; import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY; import static android.view.WindowManager.TRANSIT_NONE; import static com.android.wm.shell.unfold.UnfoldTransitionHandler.FINISH_ANIMATION_TIMEOUT_MILLIS; import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; Loading @@ -32,7 +34,9 @@ import static org.mockito.Mockito.verify; import android.app.ActivityManager; import android.graphics.Rect; import android.os.Binder; import android.os.Handler; import android.os.IBinder; import android.os.test.TestLooper; import android.view.Display; import android.view.SurfaceControl; import android.window.TransitionInfo; Loading Loading @@ -67,6 +71,8 @@ public class UnfoldTransitionHandlerTest { private FullscreenUnfoldTaskAnimator mFullscreenUnfoldTaskAnimator; private SplitTaskUnfoldAnimator mSplitTaskUnfoldAnimator; private Transitions mTransitions; private TestLooper mTestLooper; private Handler mHandler; private final IBinder mTransition = new Binder(); Loading @@ -75,6 +81,9 @@ public class UnfoldTransitionHandlerTest { final ShellExecutor executor = new TestSyncExecutor(); final ShellInit shellInit = new ShellInit(executor); mTestLooper = new TestLooper(); mHandler = new Handler(mTestLooper.getLooper()); mFullscreenUnfoldTaskAnimator = mock(FullscreenUnfoldTaskAnimator.class); mSplitTaskUnfoldAnimator = mock(SplitTaskUnfoldAnimator.class); mTransitions = mock(Transitions.class); Loading @@ -86,6 +95,7 @@ public class UnfoldTransitionHandlerTest { mSplitTaskUnfoldAnimator, mTransactionPool, executor, mHandler, mTransitions ); Loading Loading @@ -159,6 +169,7 @@ public class UnfoldTransitionHandlerTest { TransitionFinishCallback mergeFinishCallback = mock(TransitionFinishCallback.class); mUnfoldTransitionHandler.mergeAnimation(new Binder(), createFoldTransitionInfo(), mock(SurfaceControl.Transaction.class), mTransition, mergeFinishCallback); mTestLooper.dispatchAll(); // Verify that fold transition is merged into unfold and that unfold is finished final InOrder inOrder = inOrder(mergeFinishCallback, finishCallback); Loading Loading @@ -200,6 +211,25 @@ public class UnfoldTransitionHandlerTest { assertThat(animationStarted).isTrue(); } @Test public void startAnimation_animationHasNotFinishedAfterTimeout_finishesTheTransition() { TransitionRequestInfo requestInfo = createUnfoldTransitionRequestInfo(); mUnfoldTransitionHandler.handleRequest(mTransition, requestInfo); TransitionFinishCallback finishCallback = mock(TransitionFinishCallback.class); mUnfoldTransitionHandler.startAnimation( mTransition, mock(TransitionInfo.class), mock(SurfaceControl.Transaction.class), mock(SurfaceControl.Transaction.class), finishCallback ); mTestLooper.moveTimeForward(FINISH_ANIMATION_TIMEOUT_MILLIS + 1); mTestLooper.dispatchAll(); verify(finishCallback).onTransitionFinished(any()); } @Test public void startAnimation_differentTransitionFromRequestWithResize_doesNotStartAnimation() { mUnfoldTransitionHandler.handleRequest(new Binder(), createNoneTransitionInfo()); Loading