Loading services/core/java/com/android/server/wm/Task.java +30 −0 Original line number Diff line number Diff line Loading @@ -4590,6 +4590,36 @@ class Task extends TaskFragment { } } /** * Abort an incomplete pip-entry. If left in this state, it will cover everything but remain * paused. If this is needed, there is a bug -- this should only be used for recovery. */ void abortPipEnter(ActivityRecord top) { // an incomplete state has the task PINNED but the activity not. if (!inPinnedWindowingMode() || top.inPinnedWindowingMode() || !canMoveTaskToBack(this)) { return; } final Transition transition = new Transition(TRANSIT_TO_BACK, 0 /* flags */, mTransitionController, mWmService.mSyncEngine); mTransitionController.moveToCollecting(transition); mTransitionController.requestStartTransition(transition, this, null /* remoteTransition */, null /* displayChange */); if (top.getLastParentBeforePip() != null) { final Task lastParentBeforePip = top.getLastParentBeforePip(); if (lastParentBeforePip.isAttached()) { top.reparent(lastParentBeforePip, lastParentBeforePip.getChildCount() /* top */, "movePinnedActivityToOriginalTask"); } } if (isAttached()) { setWindowingMode(WINDOWING_MODE_UNDEFINED); moveTaskToBackInner(this); } if (top.isAttached()) { top.setWindowingMode(WINDOWING_MODE_UNDEFINED); } } void resumeNextFocusAfterReparent() { adjustFocusToNextFocusableTask("reparent", true /* allowFocusSelf */, true /* moveDisplayToTop */); Loading services/core/java/com/android/server/wm/Transition.java +19 −0 Original line number Diff line number Diff line Loading @@ -878,6 +878,25 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { " Commit wallpaper becoming invisible: %s", wt); wt.commitVisibility(false /* visible */); } continue; } final Task tr = participant.asTask(); if (tr != null && tr.isVisibleRequested() && tr.inPinnedWindowingMode()) { final ActivityRecord top = tr.getTopNonFinishingActivity(); if (top != null && !top.inPinnedWindowingMode()) { mController.mStateValidators.add(() -> { if (!tr.isAttached() || !tr.isVisibleRequested() || !tr.inPinnedWindowingMode()) return; final ActivityRecord currTop = tr.getTopNonFinishingActivity(); if (currTop.inPinnedWindowingMode()) return; Slog.e(TAG, "Enter-PIP was started but not completed, this is a Shell/SysUI" + " bug. This state breaks gesture-nav, so attempting clean-up."); // We don't know the destination bounds, so we can't actually finish the // operation. So, to prevent the half-pipped task from covering everything, // abort the action (which moves the task to back). tr.abortPipEnter(currTop); }); } } } Loading services/core/java/com/android/server/wm/TransitionController.java +23 −0 Original line number Diff line number Diff line Loading @@ -96,6 +96,12 @@ class TransitionController { private final ArrayList<WindowManagerInternal.AppTransitionListener> mLegacyListeners = new ArrayList<>(); /** * List of runnables to run when there are no ongoing transitions. Use this for state-validation * checks (eg. to recover from incomplete states). Eventually this should be removed. */ final ArrayList<Runnable> mStateValidators = new ArrayList<>(); /** * Currently playing transitions (in the order they were started). When finished, records are * removed from this list. Loading Loading @@ -659,6 +665,23 @@ class TransitionController { updateRunningRemoteAnimation(record, false /* isPlaying */); record.finishTransition(); mRunningLock.doNotifyLocked(); // Run state-validation checks when no transitions are active anymore. if (!inTransition()) { validateStates(); } } private void validateStates() { for (int i = 0; i < mStateValidators.size(); ++i) { mStateValidators.get(i).run(); if (inTransition()) { // the validator may have started a new transition, so wait for that before // checking the rest. mStateValidators.subList(0, i + 1).clear(); return; } } mStateValidators.clear(); } void moveToPlaying(Transition transition) { Loading Loading
services/core/java/com/android/server/wm/Task.java +30 −0 Original line number Diff line number Diff line Loading @@ -4590,6 +4590,36 @@ class Task extends TaskFragment { } } /** * Abort an incomplete pip-entry. If left in this state, it will cover everything but remain * paused. If this is needed, there is a bug -- this should only be used for recovery. */ void abortPipEnter(ActivityRecord top) { // an incomplete state has the task PINNED but the activity not. if (!inPinnedWindowingMode() || top.inPinnedWindowingMode() || !canMoveTaskToBack(this)) { return; } final Transition transition = new Transition(TRANSIT_TO_BACK, 0 /* flags */, mTransitionController, mWmService.mSyncEngine); mTransitionController.moveToCollecting(transition); mTransitionController.requestStartTransition(transition, this, null /* remoteTransition */, null /* displayChange */); if (top.getLastParentBeforePip() != null) { final Task lastParentBeforePip = top.getLastParentBeforePip(); if (lastParentBeforePip.isAttached()) { top.reparent(lastParentBeforePip, lastParentBeforePip.getChildCount() /* top */, "movePinnedActivityToOriginalTask"); } } if (isAttached()) { setWindowingMode(WINDOWING_MODE_UNDEFINED); moveTaskToBackInner(this); } if (top.isAttached()) { top.setWindowingMode(WINDOWING_MODE_UNDEFINED); } } void resumeNextFocusAfterReparent() { adjustFocusToNextFocusableTask("reparent", true /* allowFocusSelf */, true /* moveDisplayToTop */); Loading
services/core/java/com/android/server/wm/Transition.java +19 −0 Original line number Diff line number Diff line Loading @@ -878,6 +878,25 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { " Commit wallpaper becoming invisible: %s", wt); wt.commitVisibility(false /* visible */); } continue; } final Task tr = participant.asTask(); if (tr != null && tr.isVisibleRequested() && tr.inPinnedWindowingMode()) { final ActivityRecord top = tr.getTopNonFinishingActivity(); if (top != null && !top.inPinnedWindowingMode()) { mController.mStateValidators.add(() -> { if (!tr.isAttached() || !tr.isVisibleRequested() || !tr.inPinnedWindowingMode()) return; final ActivityRecord currTop = tr.getTopNonFinishingActivity(); if (currTop.inPinnedWindowingMode()) return; Slog.e(TAG, "Enter-PIP was started but not completed, this is a Shell/SysUI" + " bug. This state breaks gesture-nav, so attempting clean-up."); // We don't know the destination bounds, so we can't actually finish the // operation. So, to prevent the half-pipped task from covering everything, // abort the action (which moves the task to back). tr.abortPipEnter(currTop); }); } } } Loading
services/core/java/com/android/server/wm/TransitionController.java +23 −0 Original line number Diff line number Diff line Loading @@ -96,6 +96,12 @@ class TransitionController { private final ArrayList<WindowManagerInternal.AppTransitionListener> mLegacyListeners = new ArrayList<>(); /** * List of runnables to run when there are no ongoing transitions. Use this for state-validation * checks (eg. to recover from incomplete states). Eventually this should be removed. */ final ArrayList<Runnable> mStateValidators = new ArrayList<>(); /** * Currently playing transitions (in the order they were started). When finished, records are * removed from this list. Loading Loading @@ -659,6 +665,23 @@ class TransitionController { updateRunningRemoteAnimation(record, false /* isPlaying */); record.finishTransition(); mRunningLock.doNotifyLocked(); // Run state-validation checks when no transitions are active anymore. if (!inTransition()) { validateStates(); } } private void validateStates() { for (int i = 0; i < mStateValidators.size(); ++i) { mStateValidators.get(i).run(); if (inTransition()) { // the validator may have started a new transition, so wait for that before // checking the rest. mStateValidators.subList(0, i + 1).clear(); return; } } mStateValidators.clear(); } void moveToPlaying(Transition transition) { Loading