Loading core/java/android/window/TransitionInfo.java +10 −0 Original line number Diff line number Diff line Loading @@ -29,6 +29,7 @@ import static android.view.Display.INVALID_DISPLAY; import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_UNSPECIFIED; import static android.view.WindowManager.TRANSIT_CHANGE; import static android.view.WindowManager.TRANSIT_CLOSE; import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_APPEARING; import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY; import static android.view.WindowManager.TRANSIT_NONE; import static android.view.WindowManager.TRANSIT_OPEN; Loading Loading @@ -360,6 +361,15 @@ public final class TransitionInfo implements Parcelable { mChanges.add(change); } /** * Whether this transition contains any changes to the window hierarchy, * including keyguard visibility. */ public boolean hasChangesOrSideEffects() { return !mChanges.isEmpty() || isKeyguardGoingAway() || (mFlags & TRANSIT_FLAG_KEYGUARD_APPEARING) != 0; } /** * Whether this transition includes keyguard going away. */ Loading libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java +22 −4 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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)) { Loading Loading @@ -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. Loading libs/WindowManager/Shell/src/com/android/wm/shell/transition/SleepHandler.java +9 −15 Original line number Diff line number Diff line Loading @@ -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. Loading @@ -34,30 +33,25 @@ import java.util.ArrayList; * don't register it like a normal handler. */ class SleepHandler implements Transitions.TransitionHandler { final ArrayList<IBinder> 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); 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); } } libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java +60 −1 Original line number Diff line number Diff line Loading @@ -1152,7 +1152,7 @@ public class ShellTransitionTests extends ShellTestCase { } @Test public void testEmptyTransitionStillReportsKeyguardGoingAway() { public void testEmptyTransition_withKeyguardGoingAway_plays() { Transitions transitions = createTestTransitions(); transitions.replaceDefaultHandlerForTest(mDefaultHandler); Loading @@ -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(); Loading packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java +9 −1 Original line number Diff line number Diff line Loading @@ -554,6 +554,12 @@ public class PagedTileLayout extends ViewPager implements QSTileLayout { if (shouldNotRunAnimation(tilesToReveal)) { return; } // This method has side effects (beings the fake drag, if it returns true). If we have // decided that we want to do a tile reveal, we do a last check to verify that we can // actually perform a fake drag. if (!beginFakeDrag()) { return; } final int lastPageNumber = mPages.size() - 1; final TileLayout lastPage = mPages.get(lastPageNumber); Loading Loading @@ -588,8 +594,10 @@ public class PagedTileLayout extends ViewPager implements QSTileLayout { } private boolean shouldNotRunAnimation(Set<String> tilesToReveal) { // None of these have side effects. That way, we don't need to rely on short-circuiting // behavior boolean noAnimationNeeded = tilesToReveal.isEmpty() || mPages.size() < 2; boolean scrollingInProgress = getScrollX() != 0 || !beginFakeDrag(); boolean scrollingInProgress = getScrollX() != 0 || !isFakeDragging(); // isRunningInTestHarness() to disable animation in functional testing as it caused // flakiness and is not needed there. Alternative solutions were more complex and would // still be either potentially flaky or modify internal data. Loading Loading
core/java/android/window/TransitionInfo.java +10 −0 Original line number Diff line number Diff line Loading @@ -29,6 +29,7 @@ import static android.view.Display.INVALID_DISPLAY; import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_UNSPECIFIED; import static android.view.WindowManager.TRANSIT_CHANGE; import static android.view.WindowManager.TRANSIT_CLOSE; import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_APPEARING; import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY; import static android.view.WindowManager.TRANSIT_NONE; import static android.view.WindowManager.TRANSIT_OPEN; Loading Loading @@ -360,6 +361,15 @@ public final class TransitionInfo implements Parcelable { mChanges.add(change); } /** * Whether this transition contains any changes to the window hierarchy, * including keyguard visibility. */ public boolean hasChangesOrSideEffects() { return !mChanges.isEmpty() || isKeyguardGoingAway() || (mFlags & TRANSIT_FLAG_KEYGUARD_APPEARING) != 0; } /** * Whether this transition includes keyguard going away. */ Loading
libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java +22 −4 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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)) { Loading Loading @@ -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. Loading
libs/WindowManager/Shell/src/com/android/wm/shell/transition/SleepHandler.java +9 −15 Original line number Diff line number Diff line Loading @@ -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. Loading @@ -34,30 +33,25 @@ import java.util.ArrayList; * don't register it like a normal handler. */ class SleepHandler implements Transitions.TransitionHandler { final ArrayList<IBinder> 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); 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); } }
libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java +60 −1 Original line number Diff line number Diff line Loading @@ -1152,7 +1152,7 @@ public class ShellTransitionTests extends ShellTestCase { } @Test public void testEmptyTransitionStillReportsKeyguardGoingAway() { public void testEmptyTransition_withKeyguardGoingAway_plays() { Transitions transitions = createTestTransitions(); transitions.replaceDefaultHandlerForTest(mDefaultHandler); Loading @@ -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(); Loading
packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java +9 −1 Original line number Diff line number Diff line Loading @@ -554,6 +554,12 @@ public class PagedTileLayout extends ViewPager implements QSTileLayout { if (shouldNotRunAnimation(tilesToReveal)) { return; } // This method has side effects (beings the fake drag, if it returns true). If we have // decided that we want to do a tile reveal, we do a last check to verify that we can // actually perform a fake drag. if (!beginFakeDrag()) { return; } final int lastPageNumber = mPages.size() - 1; final TileLayout lastPage = mPages.get(lastPageNumber); Loading Loading @@ -588,8 +594,10 @@ public class PagedTileLayout extends ViewPager implements QSTileLayout { } private boolean shouldNotRunAnimation(Set<String> tilesToReveal) { // None of these have side effects. That way, we don't need to rely on short-circuiting // behavior boolean noAnimationNeeded = tilesToReveal.isEmpty() || mPages.size() < 2; boolean scrollingInProgress = getScrollX() != 0 || !beginFakeDrag(); boolean scrollingInProgress = getScrollX() != 0 || !isFakeDragging(); // isRunningInTestHarness() to disable animation in functional testing as it caused // flakiness and is not needed there. Alternative solutions were more complex and would // still be either potentially flaky or modify internal data. Loading