From 81fc7b47af86535b8a047cb34278d72371058852 Mon Sep 17 00:00:00 2001 From: Robin Lee Date: Thu, 12 Oct 2023 16:37:06 +0000 Subject: Play SLEEP transitions if they contain changes Since queued transitions aren't always cleanly chunked the way we'd imagine them to be, we may end up with actual events in the transition info if we happen to be turning screens on/off/foldingat the same time as doing things with the device. In this case, the SLEEP transition would have come first and the actual changes second, so we should assume these are changes that need to be played. Test: atest ShellTransitionTests Bug: 304713150 (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:ce1a438ce1fb20fbf031e37677013f93f32c2b5a) (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:b121eda4ec93492a690458770155158705e7ffce) Merged-In: I4bbaa8ad033aaadcb1c0b54889b7c81fb003b001 Change-Id: I4bbaa8ad033aaadcb1c0b54889b7c81fb003b001 --- .../android/wm/shell/transition/SleepHandler.java | 24 ++++----- .../wm/shell/transition/ShellTransitionTests.java | 61 +++++++++++++++++++++- 2 files changed, 69 insertions(+), 16 deletions(-) (limited to 'libs') diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/SleepHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/SleepHandler.java index 87c438a5b37d..ba0ef20c412e 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/SleepHandler.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/SleepHandler.java @@ -19,13 +19,12 @@ package com.android.wm.shell.transition; import android.annotation.NonNull; import android.annotation.Nullable; import android.os.IBinder; +import android.util.Slog; import android.view.SurfaceControl; import android.window.TransitionInfo; import android.window.TransitionRequestInfo; import android.window.WindowContainerTransaction; -import java.util.ArrayList; - /** * A Simple handler that tracks SLEEP transitions. We track them specially since we (ab)use these * as sentinels for fast-forwarding through animations when the screen is off. @@ -34,30 +33,25 @@ import java.util.ArrayList; * don't register it like a normal handler. */ class SleepHandler implements Transitions.TransitionHandler { - final ArrayList mSleepTransitions = new ArrayList<>(); - @Override public boolean startAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction startTransaction, @NonNull SurfaceControl.Transaction finishTransaction, @NonNull Transitions.TransitionFinishCallback finishCallback) { - mSleepTransitions.remove(transition); - startTransaction.apply(); - finishCallback.onTransitionFinished(null); - return true; + if (info.hasChangesOrSideEffects()) { + Slog.e(Transitions.TAG, "Real changes included in a SLEEP transition"); + return false; + } else { + startTransaction.apply(); + finishCallback.onTransitionFinished(null); + return true; + } } @Override @Nullable public WindowContainerTransaction handleRequest(@NonNull IBinder transition, @NonNull TransitionRequestInfo request) { - mSleepTransitions.add(transition); return new WindowContainerTransaction(); } - - @Override - public void onTransitionConsumed(@NonNull IBinder transition, boolean aborted, - @Nullable SurfaceControl.Transaction finishTransaction) { - mSleepTransitions.remove(transition); - } } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java index 99a1ac663286..b32e0d6b4b39 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java @@ -1152,7 +1152,7 @@ public class ShellTransitionTests extends ShellTestCase { } @Test - public void testEmptyTransitionStillReportsKeyguardGoingAway() { + public void testEmptyTransition_withKeyguardGoingAway_plays() { Transitions transitions = createTestTransitions(); transitions.replaceDefaultHandlerForTest(mDefaultHandler); @@ -1170,6 +1170,65 @@ public class ShellTransitionTests extends ShellTestCase { assertEquals(1, mDefaultHandler.activeCount()); } + @Test + public void testSleepTransition_withKeyguardGoingAway_plays(){ + Transitions transitions = createTestTransitions(); + transitions.replaceDefaultHandlerForTest(mDefaultHandler); + + IBinder transitToken = new Binder(); + transitions.requestStartTransition(transitToken, + new TransitionRequestInfo(TRANSIT_SLEEP, null /* trigger */, null /* remote */)); + + // Make a no-op transition + TransitionInfo info = new TransitionInfoBuilder( + TRANSIT_SLEEP, TRANSIT_FLAG_KEYGUARD_GOING_AWAY, true /* noOp */).build(); + transitions.onTransitionReady(transitToken, info, new StubTransaction(), + new StubTransaction()); + + // If keyguard-going-away flag set, then it shouldn't be aborted. + assertEquals(1, mDefaultHandler.activeCount()); + } + + @Test + public void testSleepTransition_withChanges_plays(){ + Transitions transitions = createTestTransitions(); + transitions.replaceDefaultHandlerForTest(mDefaultHandler); + + IBinder transitToken = new Binder(); + transitions.requestStartTransition(transitToken, + new TransitionRequestInfo(TRANSIT_SLEEP, null /* trigger */, null /* remote */)); + + // Make a transition with some changes + TransitionInfo info = new TransitionInfoBuilder(TRANSIT_SLEEP) + .addChange(TRANSIT_OPEN).build(); + info.setTrack(0); + transitions.onTransitionReady(transitToken, info, new StubTransaction(), + new StubTransaction()); + + // If there is an actual change, then it shouldn't be aborted. + assertEquals(1, mDefaultHandler.activeCount()); + } + + + @Test + public void testSleepTransition_empty_SyncBySleepHandler() { + Transitions transitions = createTestTransitions(); + transitions.replaceDefaultHandlerForTest(mDefaultHandler); + + IBinder transitToken = new Binder(); + transitions.requestStartTransition(transitToken, + new TransitionRequestInfo(TRANSIT_SLEEP, null /* trigger */, null /* remote */)); + + // Make a no-op transition + TransitionInfo info = new TransitionInfoBuilder( + TRANSIT_SLEEP, 0x0, true /* noOp */).build(); + transitions.onTransitionReady(transitToken, info, new StubTransaction(), + new StubTransaction()); + + // If there is nothing to actually play, it should not be offered to handlers. + assertEquals(0, mDefaultHandler.activeCount()); + } + @Test public void testMultipleTracks() { Transitions transitions = createTestTransitions(); -- cgit v1.2.3-59-g8ed1b From eab387346443f4d8eff986f9a5363556df342924 Mon Sep 17 00:00:00 2001 From: Winson Chung Date: Fri, 13 Oct 2023 04:08:52 +0000 Subject: Allow mixed handler to handle transitions that might enter PIP - The split transitions currently don't handle this case properly when an adjacent task is launched triggering a split task to enter PIP. Fixes: 303755768 Test: Split YT & Gmail, click link from Gmail Test: http://recall/-/g6hkB0pXjyQSvfA8STqRAT/hrdzWmMHFGHJKaSyLxb8yh (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:6f1b98014920a36c55aa5110494f4428e038d51f) Merged-In: I390ded4075211c8b5c0d328dcda42d189bee1fa8 Change-Id: I390ded4075211c8b5c0d328dcda42d189bee1fa8 --- .../wm/shell/splitscreen/StageCoordinator.java | 26 ++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) (limited to 'libs') diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java index 3b1801b8d821..c95c9f099f20 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java @@ -23,6 +23,7 @@ import static android.app.ComponentOptions.KEY_PENDING_INTENT_BACKGROUND_ACTIVIT import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; +import static android.content.Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT; import static android.content.res.Configuration.SMALLEST_SCREEN_WIDTH_DP_UNDEFINED; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.RemoteAnimationTarget.MODE_OPENING; @@ -392,6 +393,13 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, return mMainStage.isActive(); } + /** @return whether this transition-request has the launch-adjacent flag. */ + public boolean requestHasLaunchAdjacentFlag(TransitionRequestInfo request) { + final ActivityManager.RunningTaskInfo triggerTask = request.getTriggerTask(); + return triggerTask != null && triggerTask.baseIntent != null + && (triggerTask.baseIntent.getFlags() & FLAG_ACTIVITY_LAUNCH_ADJACENT) != 0; + } + /** @return whether the transition-request implies entering pip from split. */ public boolean requestImpliesSplitToPip(TransitionRequestInfo request) { if (!isSplitActive() || !mMixedHandler.requestHasPipEnter(request)) { @@ -2434,10 +2442,20 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, EXIT_REASON_SCREEN_LOCKED_SHOW_ON_TOP); } - // When split in the background, it should be only opening/dismissing transition and - // would keep out not empty. Prevent intercepting all transitions for split screen when - // it is in the background and not identify to handle it. - return (!out.isEmpty() || isSplitScreenVisible()) ? out : null; + if (!out.isEmpty()) { + // One of the cases above handled it + return out; + } else if (isSplitScreenVisible()) { + // If split is visible, only defer handling this transition if it's launching + // adjacent while there is already a split pair -- this may trigger PIP and + // that should be handled by the mixed handler. + final boolean deferTransition = requestHasLaunchAdjacentFlag(request) + && mMainStage.getChildCount() != 0 && mSideStage.getChildCount() != 0; + return !deferTransition ? out : null; + } + // Don't intercept the transition if we are not handling it as a part of one of the + // cases above and it is not already visible + return null; } else { if (isOpening && getStageOfTask(triggerTask) != null) { // One task is appearing into split, prepare to enter split screen. -- cgit v1.2.3-59-g8ed1b