Loading libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java +14 −0 Original line number Diff line number Diff line Loading @@ -128,6 +128,20 @@ public abstract class PipTransitionController implements Transitions.TransitionH // Default implementation does nothing. } /** * Called when the Shell wants to start an exit-via-expand from Pip transition/animation. */ public void startExpandTransition(WindowContainerTransaction out) { // Default implementation does nothing. } /** * Called when the Shell wants to start a remove Pip transition/animation. */ public void startRemoveTransition(boolean withFadeout) { // Default implementation does nothing. } /** * Called when the Shell wants to start resizing Pip transition/animation. * Loading libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipMotionHelper.java +11 −3 Original line number Diff line number Diff line Loading @@ -344,13 +344,22 @@ public class PipMotionHelper implements PipAppOpsListener.Callback, */ @Override public void dismissPip() { dismissPip(true /* withFadeout */); } /** * Dismisses the pinned stack. * * @param withFadeout should animate with fadeout for the removal */ public void dismissPip(boolean withFadeout) { if (DEBUG) { ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE, "%s: removePip: callers=\n%s", TAG, Debug.getCallers(5, " ")); } cancelPhysicsAnimation(); mMenuController.hideMenu(ANIM_TYPE_DISMISS, false /* resize */); mPipScheduler.scheduleRemovePip(); mPipScheduler.scheduleRemovePip(withFadeout); } /** Sets the movement bounds to use to constrain PIP position animations. */ Loading Loading @@ -473,7 +482,7 @@ public class PipMotionHelper implements PipAppOpsListener.Callback, mPipBoundsState.getMovementBounds().bottom + getBounds().height() * 2, 0, mSpringConfig) .withEndActions(this::dismissPip); .withEndActions(() -> dismissPip(false /* withFadeout */)); startBoundsAnimator( getBounds().left /* toX */, getBounds().bottom + getBounds().height() /* toY */); Loading Loading @@ -772,7 +781,6 @@ public class PipMotionHelper implements PipAppOpsListener.Callback, case PipTransitionState.EXITING_PIP: // We need to force finish any local animators if about to leave PiP, to avoid // breaking the state (e.g. leashes are cleaned up upon exit). if (!mPipBoundsState.getMotionBoundsState().isInMotion()) break; cancelPhysicsAnimation(); settlePipBoundsAfterPhysicsAnimation(false /* animatingAfter */); break; Loading libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipScheduler.java +7 −26 Original line number Diff line number Diff line Loading @@ -19,9 +19,6 @@ package com.android.wm.shell.pip2.phone; import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static com.android.wm.shell.transition.Transitions.TRANSIT_EXIT_PIP; import static com.android.wm.shell.transition.Transitions.TRANSIT_REMOVE_PIP; import android.content.Context; import android.graphics.Matrix; import android.graphics.Rect; Loading Loading @@ -112,19 +109,6 @@ public class PipScheduler { return wct; } @Nullable private WindowContainerTransaction getRemovePipTransaction() { WindowContainerToken pipTaskToken = mPipTransitionState.getPipTaskToken(); if (pipTaskToken == null) { return null; } WindowContainerTransaction wct = new WindowContainerTransaction(); wct.setBounds(pipTaskToken, null); wct.setWindowingMode(pipTaskToken, WINDOWING_MODE_UNDEFINED); wct.reorder(pipTaskToken, false); return wct; } /** * Schedules exit PiP via expand transition. */ Loading @@ -133,21 +117,16 @@ public class PipScheduler { if (!mPipTransitionState.isInPip()) return; WindowContainerTransaction wct = getExitPipViaExpandTransaction(); if (wct != null) { mPipTransitionController.startExitTransition(TRANSIT_EXIT_PIP, wct, null /* destinationBounds */); mPipTransitionController.startExpandTransition(wct); } }); } /** Schedules remove PiP transition. */ public void scheduleRemovePip() { public void scheduleRemovePip(boolean withFadeout) { mMainExecutor.execute(() -> { if (!mPipTransitionState.isInPip()) return; WindowContainerTransaction wct = getRemovePipTransaction(); if (wct != null) { mPipTransitionController.startExitTransition(TRANSIT_REMOVE_PIP, wct, null /* destinationBounds */); } mPipTransitionController.startRemoveTransition(withFadeout); }); } Loading Loading @@ -216,9 +195,11 @@ public class PipScheduler { * @param degrees the angle to rotate the bounds to. */ public void scheduleUserResizePip(Rect toBounds, float degrees) { if (toBounds.isEmpty()) { if (toBounds.isEmpty() || !mPipTransitionState.isInPip()) { ProtoLog.w(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE, "%s: Attempted to user resize PIP to empty bounds, aborting.", TAG); "%s: Attempted to user resize PIP in invalid state, aborting;" + "toBounds=%s, mPipTransitionState=%s", TAG, toBounds, mPipTransitionState); return; } SurfaceControl leash = mPipTransitionState.getPinnedTaskLeash(); Loading libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java +41 −14 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ package com.android.wm.shell.pip2.phone; import static android.app.WindowConfiguration.ROTATION_UNDEFINED; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static android.view.Surface.ROTATION_0; import static android.view.Surface.ROTATION_270; import static android.view.Surface.ROTATION_90; Loading Loading @@ -126,6 +127,7 @@ public class PipTransition extends PipTransitionController implements @Nullable private IBinder mResizeTransition; private int mBoundsChangeDuration = BOUNDS_CHANGE_JUMPCUT_DURATION; private boolean mPendingRemoveWithFadeout; // Loading Loading @@ -184,15 +186,19 @@ public class PipTransition extends PipTransitionController implements // @Override public void startExitTransition(int type, WindowContainerTransaction out, @Nullable Rect destinationBounds) { if (out == null) { return; } IBinder transition = mTransitions.startTransition(type, out, this); if (type == TRANSIT_EXIT_PIP) { mExitViaExpandTransition = transition; public void startExpandTransition(WindowContainerTransaction out) { if (out == null) return; mPipTransitionState.setState(PipTransitionState.EXITING_PIP); mExitViaExpandTransition = mTransitions.startTransition(TRANSIT_EXIT_PIP, out, this); } @Override public void startRemoveTransition(boolean withFadeout) { final WindowContainerTransaction wct = getRemovePipTransaction(); if (wct == null) return; mPipTransitionState.setState(PipTransitionState.EXITING_PIP); mPendingRemoveWithFadeout = withFadeout; mTransitions.startTransition(TRANSIT_REMOVE_PIP, wct, this); } @Override Loading Loading @@ -284,7 +290,6 @@ public class PipTransition extends PipTransitionController implements finishCallback); } else if (transition == mExitViaExpandTransition) { mExitViaExpandTransition = null; mPipTransitionState.setState(PipTransitionState.EXITING_PIP); return startExpandAnimation(info, startTransaction, finishTransaction, finishCallback); } else if (transition == mResizeTransition) { mResizeTransition = null; Loading Loading @@ -690,11 +695,19 @@ public class PipTransition extends PipTransitionController implements TransitionInfo.Change pipChange = getChangeByToken(info, mPipTransitionState.getPipTaskToken()); mFinishCallback = finishCallback; finishTransaction.setAlpha(pipChange.getLeash(), 0f); if (mPendingRemoveWithFadeout) { PipAlphaAnimator animator = new PipAlphaAnimator(mContext, pipChange.getLeash(), startTransaction, PipAlphaAnimator.FADE_OUT); finishTransaction.setAlpha(pipChange.getLeash(), 0f); animator.setAnimationEndCallback(this::finishTransition); animator.start(); } else { // Jumpcut to a faded-out PiP if no fadeout animation was requested. startTransaction.setAlpha(pipChange.getLeash(), 0f); startTransaction.apply(); finishTransition(); } return true; } Loading Loading @@ -824,6 +837,19 @@ public class PipTransition extends PipTransitionController implements return wct; } @Nullable private WindowContainerTransaction getRemovePipTransaction() { WindowContainerToken pipTaskToken = mPipTransitionState.getPipTaskToken(); if (pipTaskToken == null) { return null; } WindowContainerTransaction wct = new WindowContainerTransaction(); wct.setBounds(pipTaskToken, null); wct.setWindowingMode(pipTaskToken, WINDOWING_MODE_UNDEFINED); wct.reorder(pipTaskToken, false); return wct; } private boolean isAutoEnterInButtonNavigation(@NonNull TransitionRequestInfo requestInfo) { final ActivityManager.RunningTaskInfo pipTask = requestInfo.getPipChange() != null ? requestInfo.getPipChange().getTaskInfo() : null; Loading Loading @@ -1000,6 +1026,7 @@ public class PipTransition extends PipTransitionController implements } mPipTransitionState.setPinnedTaskLeash(null); mPipTransitionState.setPipTaskInfo(null); mPendingRemoveWithFadeout = false; break; } } Loading libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransitionState.java +20 −0 Original line number Diff line number Diff line Loading @@ -27,7 +27,9 @@ import android.window.WindowContainerToken; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import com.android.internal.protolog.ProtoLog; import com.android.internal.util.Preconditions; import com.android.wm.shell.protolog.ShellProtoLogGroup; import com.android.wm.shell.shared.annotations.ShellMainThread; import java.io.PrintWriter; Loading Loading @@ -201,6 +203,13 @@ public class PipTransitionState { Preconditions.checkArgument(extra != null && !extra.isEmpty(), "No extra bundle for " + stateToString(state) + " state."); } if (!shouldTransitionToState(state)) { ProtoLog.v(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE, "%s: Attempted to transition to an invalid state=%s, while in %s", TAG, stateToString(state), this); return; } if (mState != state) { final int prevState = mState; mState = state; Loading Loading @@ -374,6 +383,17 @@ public class PipTransitionState { return ++mPrevCustomState; } private boolean shouldTransitionToState(@TransitionState int newState) { switch (newState) { case SCHEDULED_BOUNDS_CHANGE: // Allow scheduling bounds change only while in PiP, except for if another bounds // change was scheduled but hasn't started playing yet. return isInPip(); default: return true; } } private static String stateToString(int state) { switch (state) { case UNDEFINED: return "undefined"; Loading Loading
libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java +14 −0 Original line number Diff line number Diff line Loading @@ -128,6 +128,20 @@ public abstract class PipTransitionController implements Transitions.TransitionH // Default implementation does nothing. } /** * Called when the Shell wants to start an exit-via-expand from Pip transition/animation. */ public void startExpandTransition(WindowContainerTransaction out) { // Default implementation does nothing. } /** * Called when the Shell wants to start a remove Pip transition/animation. */ public void startRemoveTransition(boolean withFadeout) { // Default implementation does nothing. } /** * Called when the Shell wants to start resizing Pip transition/animation. * Loading
libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipMotionHelper.java +11 −3 Original line number Diff line number Diff line Loading @@ -344,13 +344,22 @@ public class PipMotionHelper implements PipAppOpsListener.Callback, */ @Override public void dismissPip() { dismissPip(true /* withFadeout */); } /** * Dismisses the pinned stack. * * @param withFadeout should animate with fadeout for the removal */ public void dismissPip(boolean withFadeout) { if (DEBUG) { ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE, "%s: removePip: callers=\n%s", TAG, Debug.getCallers(5, " ")); } cancelPhysicsAnimation(); mMenuController.hideMenu(ANIM_TYPE_DISMISS, false /* resize */); mPipScheduler.scheduleRemovePip(); mPipScheduler.scheduleRemovePip(withFadeout); } /** Sets the movement bounds to use to constrain PIP position animations. */ Loading Loading @@ -473,7 +482,7 @@ public class PipMotionHelper implements PipAppOpsListener.Callback, mPipBoundsState.getMovementBounds().bottom + getBounds().height() * 2, 0, mSpringConfig) .withEndActions(this::dismissPip); .withEndActions(() -> dismissPip(false /* withFadeout */)); startBoundsAnimator( getBounds().left /* toX */, getBounds().bottom + getBounds().height() /* toY */); Loading Loading @@ -772,7 +781,6 @@ public class PipMotionHelper implements PipAppOpsListener.Callback, case PipTransitionState.EXITING_PIP: // We need to force finish any local animators if about to leave PiP, to avoid // breaking the state (e.g. leashes are cleaned up upon exit). if (!mPipBoundsState.getMotionBoundsState().isInMotion()) break; cancelPhysicsAnimation(); settlePipBoundsAfterPhysicsAnimation(false /* animatingAfter */); break; Loading
libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipScheduler.java +7 −26 Original line number Diff line number Diff line Loading @@ -19,9 +19,6 @@ package com.android.wm.shell.pip2.phone; import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static com.android.wm.shell.transition.Transitions.TRANSIT_EXIT_PIP; import static com.android.wm.shell.transition.Transitions.TRANSIT_REMOVE_PIP; import android.content.Context; import android.graphics.Matrix; import android.graphics.Rect; Loading Loading @@ -112,19 +109,6 @@ public class PipScheduler { return wct; } @Nullable private WindowContainerTransaction getRemovePipTransaction() { WindowContainerToken pipTaskToken = mPipTransitionState.getPipTaskToken(); if (pipTaskToken == null) { return null; } WindowContainerTransaction wct = new WindowContainerTransaction(); wct.setBounds(pipTaskToken, null); wct.setWindowingMode(pipTaskToken, WINDOWING_MODE_UNDEFINED); wct.reorder(pipTaskToken, false); return wct; } /** * Schedules exit PiP via expand transition. */ Loading @@ -133,21 +117,16 @@ public class PipScheduler { if (!mPipTransitionState.isInPip()) return; WindowContainerTransaction wct = getExitPipViaExpandTransaction(); if (wct != null) { mPipTransitionController.startExitTransition(TRANSIT_EXIT_PIP, wct, null /* destinationBounds */); mPipTransitionController.startExpandTransition(wct); } }); } /** Schedules remove PiP transition. */ public void scheduleRemovePip() { public void scheduleRemovePip(boolean withFadeout) { mMainExecutor.execute(() -> { if (!mPipTransitionState.isInPip()) return; WindowContainerTransaction wct = getRemovePipTransaction(); if (wct != null) { mPipTransitionController.startExitTransition(TRANSIT_REMOVE_PIP, wct, null /* destinationBounds */); } mPipTransitionController.startRemoveTransition(withFadeout); }); } Loading Loading @@ -216,9 +195,11 @@ public class PipScheduler { * @param degrees the angle to rotate the bounds to. */ public void scheduleUserResizePip(Rect toBounds, float degrees) { if (toBounds.isEmpty()) { if (toBounds.isEmpty() || !mPipTransitionState.isInPip()) { ProtoLog.w(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE, "%s: Attempted to user resize PIP to empty bounds, aborting.", TAG); "%s: Attempted to user resize PIP in invalid state, aborting;" + "toBounds=%s, mPipTransitionState=%s", TAG, toBounds, mPipTransitionState); return; } SurfaceControl leash = mPipTransitionState.getPinnedTaskLeash(); Loading
libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java +41 −14 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ package com.android.wm.shell.pip2.phone; import static android.app.WindowConfiguration.ROTATION_UNDEFINED; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static android.view.Surface.ROTATION_0; import static android.view.Surface.ROTATION_270; import static android.view.Surface.ROTATION_90; Loading Loading @@ -126,6 +127,7 @@ public class PipTransition extends PipTransitionController implements @Nullable private IBinder mResizeTransition; private int mBoundsChangeDuration = BOUNDS_CHANGE_JUMPCUT_DURATION; private boolean mPendingRemoveWithFadeout; // Loading Loading @@ -184,15 +186,19 @@ public class PipTransition extends PipTransitionController implements // @Override public void startExitTransition(int type, WindowContainerTransaction out, @Nullable Rect destinationBounds) { if (out == null) { return; } IBinder transition = mTransitions.startTransition(type, out, this); if (type == TRANSIT_EXIT_PIP) { mExitViaExpandTransition = transition; public void startExpandTransition(WindowContainerTransaction out) { if (out == null) return; mPipTransitionState.setState(PipTransitionState.EXITING_PIP); mExitViaExpandTransition = mTransitions.startTransition(TRANSIT_EXIT_PIP, out, this); } @Override public void startRemoveTransition(boolean withFadeout) { final WindowContainerTransaction wct = getRemovePipTransaction(); if (wct == null) return; mPipTransitionState.setState(PipTransitionState.EXITING_PIP); mPendingRemoveWithFadeout = withFadeout; mTransitions.startTransition(TRANSIT_REMOVE_PIP, wct, this); } @Override Loading Loading @@ -284,7 +290,6 @@ public class PipTransition extends PipTransitionController implements finishCallback); } else if (transition == mExitViaExpandTransition) { mExitViaExpandTransition = null; mPipTransitionState.setState(PipTransitionState.EXITING_PIP); return startExpandAnimation(info, startTransaction, finishTransaction, finishCallback); } else if (transition == mResizeTransition) { mResizeTransition = null; Loading Loading @@ -690,11 +695,19 @@ public class PipTransition extends PipTransitionController implements TransitionInfo.Change pipChange = getChangeByToken(info, mPipTransitionState.getPipTaskToken()); mFinishCallback = finishCallback; finishTransaction.setAlpha(pipChange.getLeash(), 0f); if (mPendingRemoveWithFadeout) { PipAlphaAnimator animator = new PipAlphaAnimator(mContext, pipChange.getLeash(), startTransaction, PipAlphaAnimator.FADE_OUT); finishTransaction.setAlpha(pipChange.getLeash(), 0f); animator.setAnimationEndCallback(this::finishTransition); animator.start(); } else { // Jumpcut to a faded-out PiP if no fadeout animation was requested. startTransaction.setAlpha(pipChange.getLeash(), 0f); startTransaction.apply(); finishTransition(); } return true; } Loading Loading @@ -824,6 +837,19 @@ public class PipTransition extends PipTransitionController implements return wct; } @Nullable private WindowContainerTransaction getRemovePipTransaction() { WindowContainerToken pipTaskToken = mPipTransitionState.getPipTaskToken(); if (pipTaskToken == null) { return null; } WindowContainerTransaction wct = new WindowContainerTransaction(); wct.setBounds(pipTaskToken, null); wct.setWindowingMode(pipTaskToken, WINDOWING_MODE_UNDEFINED); wct.reorder(pipTaskToken, false); return wct; } private boolean isAutoEnterInButtonNavigation(@NonNull TransitionRequestInfo requestInfo) { final ActivityManager.RunningTaskInfo pipTask = requestInfo.getPipChange() != null ? requestInfo.getPipChange().getTaskInfo() : null; Loading Loading @@ -1000,6 +1026,7 @@ public class PipTransition extends PipTransitionController implements } mPipTransitionState.setPinnedTaskLeash(null); mPipTransitionState.setPipTaskInfo(null); mPendingRemoveWithFadeout = false; break; } } Loading
libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransitionState.java +20 −0 Original line number Diff line number Diff line Loading @@ -27,7 +27,9 @@ import android.window.WindowContainerToken; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import com.android.internal.protolog.ProtoLog; import com.android.internal.util.Preconditions; import com.android.wm.shell.protolog.ShellProtoLogGroup; import com.android.wm.shell.shared.annotations.ShellMainThread; import java.io.PrintWriter; Loading Loading @@ -201,6 +203,13 @@ public class PipTransitionState { Preconditions.checkArgument(extra != null && !extra.isEmpty(), "No extra bundle for " + stateToString(state) + " state."); } if (!shouldTransitionToState(state)) { ProtoLog.v(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE, "%s: Attempted to transition to an invalid state=%s, while in %s", TAG, stateToString(state), this); return; } if (mState != state) { final int prevState = mState; mState = state; Loading Loading @@ -374,6 +383,17 @@ public class PipTransitionState { return ++mPrevCustomState; } private boolean shouldTransitionToState(@TransitionState int newState) { switch (newState) { case SCHEDULED_BOUNDS_CHANGE: // Allow scheduling bounds change only while in PiP, except for if another bounds // change was scheduled but hasn't started playing yet. return isInPip(); default: return true; } } private static String stateToString(int state) { switch (state) { case UNDEFINED: return "undefined"; Loading