Loading libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java +27 −22 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ import android.animation.Animator; import android.animation.RectEvaluator; import android.animation.ValueAnimator; import android.annotation.IntDef; import android.app.TaskInfo; import android.graphics.Rect; import android.view.Choreographer; import android.view.SurfaceControl; Loading Loading @@ -99,18 +100,20 @@ public class PipAnimationController { @SuppressWarnings("unchecked") @VisibleForTesting public PipTransitionAnimator getAnimator(SurfaceControl leash, public PipTransitionAnimator getAnimator(TaskInfo taskInfo, SurfaceControl leash, Rect destinationBounds, float alphaStart, float alphaEnd) { if (mCurrentAnimator == null) { mCurrentAnimator = setupPipTransitionAnimator( PipTransitionAnimator.ofAlpha(leash, destinationBounds, alphaStart, alphaEnd)); PipTransitionAnimator.ofAlpha(taskInfo, leash, destinationBounds, alphaStart, alphaEnd)); } else if (mCurrentAnimator.getAnimationType() == ANIM_TYPE_ALPHA && mCurrentAnimator.isRunning()) { mCurrentAnimator.updateEndValue(alphaEnd); } else { mCurrentAnimator.cancel(); mCurrentAnimator = setupPipTransitionAnimator( PipTransitionAnimator.ofAlpha(leash, destinationBounds, alphaStart, alphaEnd)); PipTransitionAnimator.ofAlpha(taskInfo, leash, destinationBounds, alphaStart, alphaEnd)); } return mCurrentAnimator; } Loading @@ -131,13 +134,13 @@ public class PipAnimationController { * the PiP original bounds, rather than the {@param startBounds}, which is post-transformed. */ @VisibleForTesting public PipTransitionAnimator getAnimator(SurfaceControl leash, Rect baseBounds, Rect startBounds, Rect endBounds, Rect sourceHintRect, public PipTransitionAnimator getAnimator(TaskInfo taskInfo, SurfaceControl leash, Rect baseBounds, Rect startBounds, Rect endBounds, Rect sourceHintRect, @PipAnimationController.TransitionDirection int direction, float startingAngle) { if (mCurrentAnimator == null) { mCurrentAnimator = setupPipTransitionAnimator( PipTransitionAnimator.ofBounds(leash, startBounds, startBounds, endBounds, sourceHintRect, direction, 0 /* startingAngle */)); PipTransitionAnimator.ofBounds(taskInfo, leash, startBounds, startBounds, endBounds, sourceHintRect, direction, 0 /* startingAngle */)); } else if (mCurrentAnimator.getAnimationType() == ANIM_TYPE_ALPHA && mCurrentAnimator.isRunning()) { // If we are still animating the fade into pip, then just move the surface and ensure Loading @@ -152,8 +155,8 @@ public class PipAnimationController { } else { mCurrentAnimator.cancel(); mCurrentAnimator = setupPipTransitionAnimator( PipTransitionAnimator.ofBounds(leash, baseBounds, startBounds, endBounds, sourceHintRect, direction, startingAngle)); PipTransitionAnimator.ofBounds(taskInfo, leash, baseBounds, startBounds, endBounds, sourceHintRect, direction, startingAngle)); } return mCurrentAnimator; } Loading @@ -177,18 +180,18 @@ public class PipAnimationController { /** * Called when PiP animation is started. */ public void onPipAnimationStart(PipTransitionAnimator animator) {} public void onPipAnimationStart(TaskInfo taskInfo, PipTransitionAnimator animator) {} /** * Called when PiP animation is ended. */ public void onPipAnimationEnd(SurfaceControl.Transaction tx, public void onPipAnimationEnd(TaskInfo taskInfo, SurfaceControl.Transaction tx, PipTransitionAnimator animator) {} /** * Called when PiP animation is cancelled. */ public void onPipAnimationCancel(PipTransitionAnimator animator) {} public void onPipAnimationCancel(TaskInfo taskInfo, PipTransitionAnimator animator) {} } /** Loading @@ -198,6 +201,7 @@ public class PipAnimationController { public abstract static class PipTransitionAnimator<T> extends ValueAnimator implements ValueAnimator.AnimatorUpdateListener, ValueAnimator.AnimatorListener { private final TaskInfo mTaskInfo; private final SurfaceControl mLeash; private final @AnimationType int mAnimationType; private final Rect mDestinationBounds = new Rect(); Loading @@ -213,9 +217,10 @@ public class PipAnimationController { private PipSurfaceTransactionHelper mSurfaceTransactionHelper; private @TransitionDirection int mTransitionDirection; private PipTransitionAnimator(SurfaceControl leash, @AnimationType int animationType, Rect destinationBounds, T baseValue, T startValue, T endValue, float startingAngle) { private PipTransitionAnimator(TaskInfo taskInfo, SurfaceControl leash, @AnimationType int animationType, Rect destinationBounds, T baseValue, T startValue, T endValue, float startingAngle) { mTaskInfo = taskInfo; mLeash = leash; mAnimationType = animationType; mDestinationBounds.set(destinationBounds); Loading @@ -234,7 +239,7 @@ public class PipAnimationController { mCurrentValue = mStartValue; onStartTransaction(mLeash, newSurfaceControlTransaction()); if (mPipAnimationCallback != null) { mPipAnimationCallback.onPipAnimationStart(this); mPipAnimationCallback.onPipAnimationStart(mTaskInfo, this); } } Loading @@ -250,14 +255,14 @@ public class PipAnimationController { final SurfaceControl.Transaction tx = newSurfaceControlTransaction(); onEndTransaction(mLeash, tx, mTransitionDirection); if (mPipAnimationCallback != null) { mPipAnimationCallback.onPipAnimationEnd(tx, this); mPipAnimationCallback.onPipAnimationEnd(mTaskInfo, tx, this); } } @Override public void onAnimationCancel(Animator animation) { if (mPipAnimationCallback != null) { mPipAnimationCallback.onPipAnimationCancel(this); mPipAnimationCallback.onPipAnimationCancel(mTaskInfo, this); } } Loading Loading @@ -368,9 +373,9 @@ public class PipAnimationController { abstract void applySurfaceControlTransaction(SurfaceControl leash, SurfaceControl.Transaction tx, float fraction); static PipTransitionAnimator<Float> ofAlpha(SurfaceControl leash, static PipTransitionAnimator<Float> ofAlpha(TaskInfo taskInfo, SurfaceControl leash, Rect destinationBounds, float startValue, float endValue) { return new PipTransitionAnimator<Float>(leash, ANIM_TYPE_ALPHA, return new PipTransitionAnimator<Float>(taskInfo, leash, ANIM_TYPE_ALPHA, destinationBounds, startValue, startValue, endValue, 0) { @Override void applySurfaceControlTransaction(SurfaceControl leash, Loading Loading @@ -403,7 +408,7 @@ public class PipAnimationController { }; } static PipTransitionAnimator<Rect> ofBounds(SurfaceControl leash, static PipTransitionAnimator<Rect> ofBounds(TaskInfo taskInfo, SurfaceControl leash, Rect baseValue, Rect startValue, Rect endValue, Rect sourceHintRect, @PipAnimationController.TransitionDirection int direction, float startingAngle) { // Just for simplicity we'll interpolate between the source rect hint insets and empty Loading @@ -427,7 +432,7 @@ public class PipAnimationController { final Rect sourceInsets = new Rect(0, 0, 0, 0); // construct new Rect instances in case they are recycled return new PipTransitionAnimator<Rect>(leash, ANIM_TYPE_BOUNDS, return new PipTransitionAnimator<Rect>(taskInfo, leash, ANIM_TYPE_BOUNDS, endValue, new Rect(baseValue), new Rect(startValue), new Rect(endValue), startingAngle) { private final RectEvaluator mRectEvaluator = new RectEvaluator(new Rect()); Loading libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsAlgorithm.java +44 −1 Original line number Diff line number Diff line Loading @@ -19,7 +19,9 @@ package com.android.wm.shell.pip; import static android.util.TypedValue.COMPLEX_UNIT_DIP; import android.annotation.NonNull; import android.app.PictureInPictureParams; import android.content.Context; import android.content.pm.ActivityInfo; import android.content.res.Resources; import android.graphics.Point; import android.graphics.PointF; Loading @@ -27,7 +29,6 @@ import android.graphics.Rect; import android.util.DisplayMetrics; import android.util.Size; import android.util.TypedValue; import android.view.DisplayInfo; import android.view.Gravity; import com.android.wm.shell.common.DisplayLayout; Loading Loading @@ -142,10 +143,52 @@ public class PipBoundsAlgorithm { true /* useCurrentMinEdgeSize */, false /* useCurrentSize */); } /** * * Get the smallest/most minimal size allowed. */ public Size getMinimalSize(ActivityInfo activityInfo) { if (activityInfo == null || activityInfo.windowLayout == null) { return null; } final ActivityInfo.WindowLayout windowLayout = activityInfo.windowLayout; // -1 will be populated if an activity specifies defaultWidth/defaultHeight in <layout> // without minWidth/minHeight if (windowLayout.minWidth > 0 && windowLayout.minHeight > 0) { return new Size(windowLayout.minWidth, windowLayout.minHeight); } return null; } /** * Returns the source hint rect if it is valid (if provided and is contained by the current * task bounds). */ public static Rect getValidSourceHintRect(PictureInPictureParams params, Rect sourceBounds) { final Rect sourceHintRect = params != null && params.hasSourceBoundsHint() ? params.getSourceRectHint() : null; if (sourceHintRect != null && sourceBounds.contains(sourceHintRect)) { return sourceHintRect; } return null; } public float getDefaultAspectRatio() { return mDefaultAspectRatio; } /** * * Give the aspect ratio if the supplied PiP params have one, or else return default. */ public float getAspectRatioOrDefault( @android.annotation.Nullable PictureInPictureParams params) { return params != null && params.hasSetAspectRatio() ? params.getAspectRatio() : getDefaultAspectRatio(); } /** * @return whether the given {@param aspectRatio} is valid. */ Loading libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsState.java +10 −1 Original line number Diff line number Diff line Loading @@ -25,7 +25,6 @@ import android.graphics.Point; import android.graphics.Rect; import android.util.Size; import android.view.Display; import android.view.DisplayInfo; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.function.TriConsumer; Loading Loading @@ -344,6 +343,16 @@ public final class PipBoundsState { } } /** * Initialize states when first entering PiP. */ public void setBoundsStateForEntry(ComponentName componentName, float aspectRatio, Size overrideMinSize) { setLastPipComponentName(componentName); setAspectRatio(aspectRatio); setOverrideMinSize(overrideMinSize); } /** Returns whether the shelf is currently showing. */ public boolean isShelfShowing() { return mIsShelfShowing; Loading libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java +37 −102 File changed.Preview size limit exceeded, changes collapsed. Show changes libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java 0 → 100644 +162 −0 Original line number Diff line number Diff line /* * Copyright (C) 2021 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.wm.shell.pip; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static com.android.wm.shell.pip.PipAnimationController.ANIM_TYPE_ALPHA; import static com.android.wm.shell.pip.PipAnimationController.ANIM_TYPE_BOUNDS; import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTION_LEAVE_PIP; import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTION_TO_PIP; import static com.android.wm.shell.pip.PipAnimationController.isInPipDirection; import static com.android.wm.shell.pip.PipAnimationController.isOutPipDirection; import android.app.TaskInfo; import android.content.Context; import android.graphics.Rect; import android.os.IBinder; import android.view.SurfaceControl; import android.window.TransitionInfo; import android.window.TransitionRequestInfo; import android.window.WindowContainerTransaction; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import com.android.wm.shell.R; import com.android.wm.shell.ShellTaskOrganizer; import com.android.wm.shell.transition.Transitions; /** * Implementation of transitions for PiP on phone. Responsible for enter (alpha, bounds) and * exit animation. */ public class PipTransition extends PipTransitionController { private final int mEnterExitAnimationDuration; private @PipAnimationController.AnimationType int mOneShotAnimationType = ANIM_TYPE_BOUNDS; private Transitions.TransitionFinishCallback mFinishCallback; public PipTransition(Context context, PipBoundsState pipBoundsState, PipMenuController pipMenuController, PipBoundsAlgorithm pipBoundsAlgorithm, PipAnimationController pipAnimationController, Transitions transitions, @NonNull ShellTaskOrganizer shellTaskOrganizer) { super(pipBoundsState, pipMenuController, pipBoundsAlgorithm, pipAnimationController, transitions, shellTaskOrganizer); mEnterExitAnimationDuration = context.getResources() .getInteger(R.integer.config_pipResizeAnimationDuration); } @Override public boolean startAnimation(@android.annotation.NonNull IBinder transition, @android.annotation.NonNull TransitionInfo info, @android.annotation.NonNull SurfaceControl.Transaction t, @android.annotation.NonNull Transitions.TransitionFinishCallback finishCallback) { for (int i = info.getChanges().size() - 1; i >= 0; --i) { final TransitionInfo.Change change = info.getChanges().get(i); if (change.getTaskInfo() != null && change.getTaskInfo().configuration.windowConfiguration.getWindowingMode() == WINDOWING_MODE_PINNED) { mFinishCallback = finishCallback; return startEnterAnimation(change.getTaskInfo(), change.getLeash(), t); } } return false; } @Nullable @Override public WindowContainerTransaction handleRequest(@NonNull IBinder transition, @NonNull TransitionRequestInfo request) { return null; } @Override public void onFinishResize(TaskInfo taskInfo, Rect destinationBounds, @PipAnimationController.TransitionDirection int direction, SurfaceControl.Transaction tx) { WindowContainerTransaction wct = new WindowContainerTransaction(); prepareFinishResizeTransaction(taskInfo, destinationBounds, direction, tx, wct); mFinishCallback.onTransitionFinished(wct, null); finishResizeForMenu(destinationBounds); } private boolean startEnterAnimation(final TaskInfo taskInfo, final SurfaceControl leash, final SurfaceControl.Transaction t) { setBoundsStateForEntry(taskInfo.topActivity, taskInfo.pictureInPictureParams, taskInfo.topActivityInfo); final Rect destinationBounds = mPipBoundsAlgorithm.getEntryDestinationBounds(); final Rect currentBounds = taskInfo.configuration.windowConfiguration.getBounds(); PipAnimationController.PipTransitionAnimator animator; if (mOneShotAnimationType == ANIM_TYPE_BOUNDS) { final Rect sourceHintRect = PipBoundsAlgorithm.getValidSourceHintRect( taskInfo.pictureInPictureParams, currentBounds); animator = mPipAnimationController.getAnimator(taskInfo, leash, currentBounds, currentBounds, destinationBounds, sourceHintRect, TRANSITION_DIRECTION_TO_PIP, 0 /* startingAngle */); } else if (mOneShotAnimationType == ANIM_TYPE_ALPHA) { t.setAlpha(leash, 0f); t.apply(); animator = mPipAnimationController.getAnimator(taskInfo, leash, destinationBounds, 0f, 1f); mOneShotAnimationType = ANIM_TYPE_BOUNDS; } else { throw new RuntimeException("Unrecognized animation type: " + mOneShotAnimationType); } animator.setTransitionDirection(TRANSITION_DIRECTION_TO_PIP) .setPipAnimationCallback(mPipAnimationCallback) .setDuration(mEnterExitAnimationDuration) .start(); return true; } private void finishResizeForMenu(Rect destinationBounds) { mPipMenuController.movePipMenu(null, null, destinationBounds); mPipMenuController.updateMenuBounds(destinationBounds); } private void prepareFinishResizeTransaction(TaskInfo taskInfo, Rect destinationBounds, @PipAnimationController.TransitionDirection int direction, SurfaceControl.Transaction tx, WindowContainerTransaction wct) { Rect taskBounds = null; if (isInPipDirection(direction)) { // If we are animating from fullscreen using a bounds animation, then reset the // activity windowing mode set by WM, and set the task bounds to the final bounds taskBounds = destinationBounds; wct.setActivityWindowingMode(taskInfo.token, WINDOWING_MODE_UNDEFINED); wct.scheduleFinishEnterPip(taskInfo.token, destinationBounds); } else if (isOutPipDirection(direction)) { // If we are animating to fullscreen, then we need to reset the override bounds // on the task to ensure that the task "matches" the parent's bounds. taskBounds = (direction == TRANSITION_DIRECTION_LEAVE_PIP) ? null : destinationBounds; wct.setWindowingMode(taskInfo.token, getOutPipWindowingMode()); // Simply reset the activity mode set prior to the animation running. wct.setActivityWindowingMode(taskInfo.token, WINDOWING_MODE_UNDEFINED); } wct.setBounds(taskInfo.token, taskBounds); wct.setBoundsChangeTransaction(taskInfo.token, tx); } } Loading
libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java +27 −22 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ import android.animation.Animator; import android.animation.RectEvaluator; import android.animation.ValueAnimator; import android.annotation.IntDef; import android.app.TaskInfo; import android.graphics.Rect; import android.view.Choreographer; import android.view.SurfaceControl; Loading Loading @@ -99,18 +100,20 @@ public class PipAnimationController { @SuppressWarnings("unchecked") @VisibleForTesting public PipTransitionAnimator getAnimator(SurfaceControl leash, public PipTransitionAnimator getAnimator(TaskInfo taskInfo, SurfaceControl leash, Rect destinationBounds, float alphaStart, float alphaEnd) { if (mCurrentAnimator == null) { mCurrentAnimator = setupPipTransitionAnimator( PipTransitionAnimator.ofAlpha(leash, destinationBounds, alphaStart, alphaEnd)); PipTransitionAnimator.ofAlpha(taskInfo, leash, destinationBounds, alphaStart, alphaEnd)); } else if (mCurrentAnimator.getAnimationType() == ANIM_TYPE_ALPHA && mCurrentAnimator.isRunning()) { mCurrentAnimator.updateEndValue(alphaEnd); } else { mCurrentAnimator.cancel(); mCurrentAnimator = setupPipTransitionAnimator( PipTransitionAnimator.ofAlpha(leash, destinationBounds, alphaStart, alphaEnd)); PipTransitionAnimator.ofAlpha(taskInfo, leash, destinationBounds, alphaStart, alphaEnd)); } return mCurrentAnimator; } Loading @@ -131,13 +134,13 @@ public class PipAnimationController { * the PiP original bounds, rather than the {@param startBounds}, which is post-transformed. */ @VisibleForTesting public PipTransitionAnimator getAnimator(SurfaceControl leash, Rect baseBounds, Rect startBounds, Rect endBounds, Rect sourceHintRect, public PipTransitionAnimator getAnimator(TaskInfo taskInfo, SurfaceControl leash, Rect baseBounds, Rect startBounds, Rect endBounds, Rect sourceHintRect, @PipAnimationController.TransitionDirection int direction, float startingAngle) { if (mCurrentAnimator == null) { mCurrentAnimator = setupPipTransitionAnimator( PipTransitionAnimator.ofBounds(leash, startBounds, startBounds, endBounds, sourceHintRect, direction, 0 /* startingAngle */)); PipTransitionAnimator.ofBounds(taskInfo, leash, startBounds, startBounds, endBounds, sourceHintRect, direction, 0 /* startingAngle */)); } else if (mCurrentAnimator.getAnimationType() == ANIM_TYPE_ALPHA && mCurrentAnimator.isRunning()) { // If we are still animating the fade into pip, then just move the surface and ensure Loading @@ -152,8 +155,8 @@ public class PipAnimationController { } else { mCurrentAnimator.cancel(); mCurrentAnimator = setupPipTransitionAnimator( PipTransitionAnimator.ofBounds(leash, baseBounds, startBounds, endBounds, sourceHintRect, direction, startingAngle)); PipTransitionAnimator.ofBounds(taskInfo, leash, baseBounds, startBounds, endBounds, sourceHintRect, direction, startingAngle)); } return mCurrentAnimator; } Loading @@ -177,18 +180,18 @@ public class PipAnimationController { /** * Called when PiP animation is started. */ public void onPipAnimationStart(PipTransitionAnimator animator) {} public void onPipAnimationStart(TaskInfo taskInfo, PipTransitionAnimator animator) {} /** * Called when PiP animation is ended. */ public void onPipAnimationEnd(SurfaceControl.Transaction tx, public void onPipAnimationEnd(TaskInfo taskInfo, SurfaceControl.Transaction tx, PipTransitionAnimator animator) {} /** * Called when PiP animation is cancelled. */ public void onPipAnimationCancel(PipTransitionAnimator animator) {} public void onPipAnimationCancel(TaskInfo taskInfo, PipTransitionAnimator animator) {} } /** Loading @@ -198,6 +201,7 @@ public class PipAnimationController { public abstract static class PipTransitionAnimator<T> extends ValueAnimator implements ValueAnimator.AnimatorUpdateListener, ValueAnimator.AnimatorListener { private final TaskInfo mTaskInfo; private final SurfaceControl mLeash; private final @AnimationType int mAnimationType; private final Rect mDestinationBounds = new Rect(); Loading @@ -213,9 +217,10 @@ public class PipAnimationController { private PipSurfaceTransactionHelper mSurfaceTransactionHelper; private @TransitionDirection int mTransitionDirection; private PipTransitionAnimator(SurfaceControl leash, @AnimationType int animationType, Rect destinationBounds, T baseValue, T startValue, T endValue, float startingAngle) { private PipTransitionAnimator(TaskInfo taskInfo, SurfaceControl leash, @AnimationType int animationType, Rect destinationBounds, T baseValue, T startValue, T endValue, float startingAngle) { mTaskInfo = taskInfo; mLeash = leash; mAnimationType = animationType; mDestinationBounds.set(destinationBounds); Loading @@ -234,7 +239,7 @@ public class PipAnimationController { mCurrentValue = mStartValue; onStartTransaction(mLeash, newSurfaceControlTransaction()); if (mPipAnimationCallback != null) { mPipAnimationCallback.onPipAnimationStart(this); mPipAnimationCallback.onPipAnimationStart(mTaskInfo, this); } } Loading @@ -250,14 +255,14 @@ public class PipAnimationController { final SurfaceControl.Transaction tx = newSurfaceControlTransaction(); onEndTransaction(mLeash, tx, mTransitionDirection); if (mPipAnimationCallback != null) { mPipAnimationCallback.onPipAnimationEnd(tx, this); mPipAnimationCallback.onPipAnimationEnd(mTaskInfo, tx, this); } } @Override public void onAnimationCancel(Animator animation) { if (mPipAnimationCallback != null) { mPipAnimationCallback.onPipAnimationCancel(this); mPipAnimationCallback.onPipAnimationCancel(mTaskInfo, this); } } Loading Loading @@ -368,9 +373,9 @@ public class PipAnimationController { abstract void applySurfaceControlTransaction(SurfaceControl leash, SurfaceControl.Transaction tx, float fraction); static PipTransitionAnimator<Float> ofAlpha(SurfaceControl leash, static PipTransitionAnimator<Float> ofAlpha(TaskInfo taskInfo, SurfaceControl leash, Rect destinationBounds, float startValue, float endValue) { return new PipTransitionAnimator<Float>(leash, ANIM_TYPE_ALPHA, return new PipTransitionAnimator<Float>(taskInfo, leash, ANIM_TYPE_ALPHA, destinationBounds, startValue, startValue, endValue, 0) { @Override void applySurfaceControlTransaction(SurfaceControl leash, Loading Loading @@ -403,7 +408,7 @@ public class PipAnimationController { }; } static PipTransitionAnimator<Rect> ofBounds(SurfaceControl leash, static PipTransitionAnimator<Rect> ofBounds(TaskInfo taskInfo, SurfaceControl leash, Rect baseValue, Rect startValue, Rect endValue, Rect sourceHintRect, @PipAnimationController.TransitionDirection int direction, float startingAngle) { // Just for simplicity we'll interpolate between the source rect hint insets and empty Loading @@ -427,7 +432,7 @@ public class PipAnimationController { final Rect sourceInsets = new Rect(0, 0, 0, 0); // construct new Rect instances in case they are recycled return new PipTransitionAnimator<Rect>(leash, ANIM_TYPE_BOUNDS, return new PipTransitionAnimator<Rect>(taskInfo, leash, ANIM_TYPE_BOUNDS, endValue, new Rect(baseValue), new Rect(startValue), new Rect(endValue), startingAngle) { private final RectEvaluator mRectEvaluator = new RectEvaluator(new Rect()); Loading
libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsAlgorithm.java +44 −1 Original line number Diff line number Diff line Loading @@ -19,7 +19,9 @@ package com.android.wm.shell.pip; import static android.util.TypedValue.COMPLEX_UNIT_DIP; import android.annotation.NonNull; import android.app.PictureInPictureParams; import android.content.Context; import android.content.pm.ActivityInfo; import android.content.res.Resources; import android.graphics.Point; import android.graphics.PointF; Loading @@ -27,7 +29,6 @@ import android.graphics.Rect; import android.util.DisplayMetrics; import android.util.Size; import android.util.TypedValue; import android.view.DisplayInfo; import android.view.Gravity; import com.android.wm.shell.common.DisplayLayout; Loading Loading @@ -142,10 +143,52 @@ public class PipBoundsAlgorithm { true /* useCurrentMinEdgeSize */, false /* useCurrentSize */); } /** * * Get the smallest/most minimal size allowed. */ public Size getMinimalSize(ActivityInfo activityInfo) { if (activityInfo == null || activityInfo.windowLayout == null) { return null; } final ActivityInfo.WindowLayout windowLayout = activityInfo.windowLayout; // -1 will be populated if an activity specifies defaultWidth/defaultHeight in <layout> // without minWidth/minHeight if (windowLayout.minWidth > 0 && windowLayout.minHeight > 0) { return new Size(windowLayout.minWidth, windowLayout.minHeight); } return null; } /** * Returns the source hint rect if it is valid (if provided and is contained by the current * task bounds). */ public static Rect getValidSourceHintRect(PictureInPictureParams params, Rect sourceBounds) { final Rect sourceHintRect = params != null && params.hasSourceBoundsHint() ? params.getSourceRectHint() : null; if (sourceHintRect != null && sourceBounds.contains(sourceHintRect)) { return sourceHintRect; } return null; } public float getDefaultAspectRatio() { return mDefaultAspectRatio; } /** * * Give the aspect ratio if the supplied PiP params have one, or else return default. */ public float getAspectRatioOrDefault( @android.annotation.Nullable PictureInPictureParams params) { return params != null && params.hasSetAspectRatio() ? params.getAspectRatio() : getDefaultAspectRatio(); } /** * @return whether the given {@param aspectRatio} is valid. */ Loading
libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsState.java +10 −1 Original line number Diff line number Diff line Loading @@ -25,7 +25,6 @@ import android.graphics.Point; import android.graphics.Rect; import android.util.Size; import android.view.Display; import android.view.DisplayInfo; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.function.TriConsumer; Loading Loading @@ -344,6 +343,16 @@ public final class PipBoundsState { } } /** * Initialize states when first entering PiP. */ public void setBoundsStateForEntry(ComponentName componentName, float aspectRatio, Size overrideMinSize) { setLastPipComponentName(componentName); setAspectRatio(aspectRatio); setOverrideMinSize(overrideMinSize); } /** Returns whether the shelf is currently showing. */ public boolean isShelfShowing() { return mIsShelfShowing; Loading
libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java +37 −102 File changed.Preview size limit exceeded, changes collapsed. Show changes
libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java 0 → 100644 +162 −0 Original line number Diff line number Diff line /* * Copyright (C) 2021 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.wm.shell.pip; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static com.android.wm.shell.pip.PipAnimationController.ANIM_TYPE_ALPHA; import static com.android.wm.shell.pip.PipAnimationController.ANIM_TYPE_BOUNDS; import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTION_LEAVE_PIP; import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTION_TO_PIP; import static com.android.wm.shell.pip.PipAnimationController.isInPipDirection; import static com.android.wm.shell.pip.PipAnimationController.isOutPipDirection; import android.app.TaskInfo; import android.content.Context; import android.graphics.Rect; import android.os.IBinder; import android.view.SurfaceControl; import android.window.TransitionInfo; import android.window.TransitionRequestInfo; import android.window.WindowContainerTransaction; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import com.android.wm.shell.R; import com.android.wm.shell.ShellTaskOrganizer; import com.android.wm.shell.transition.Transitions; /** * Implementation of transitions for PiP on phone. Responsible for enter (alpha, bounds) and * exit animation. */ public class PipTransition extends PipTransitionController { private final int mEnterExitAnimationDuration; private @PipAnimationController.AnimationType int mOneShotAnimationType = ANIM_TYPE_BOUNDS; private Transitions.TransitionFinishCallback mFinishCallback; public PipTransition(Context context, PipBoundsState pipBoundsState, PipMenuController pipMenuController, PipBoundsAlgorithm pipBoundsAlgorithm, PipAnimationController pipAnimationController, Transitions transitions, @NonNull ShellTaskOrganizer shellTaskOrganizer) { super(pipBoundsState, pipMenuController, pipBoundsAlgorithm, pipAnimationController, transitions, shellTaskOrganizer); mEnterExitAnimationDuration = context.getResources() .getInteger(R.integer.config_pipResizeAnimationDuration); } @Override public boolean startAnimation(@android.annotation.NonNull IBinder transition, @android.annotation.NonNull TransitionInfo info, @android.annotation.NonNull SurfaceControl.Transaction t, @android.annotation.NonNull Transitions.TransitionFinishCallback finishCallback) { for (int i = info.getChanges().size() - 1; i >= 0; --i) { final TransitionInfo.Change change = info.getChanges().get(i); if (change.getTaskInfo() != null && change.getTaskInfo().configuration.windowConfiguration.getWindowingMode() == WINDOWING_MODE_PINNED) { mFinishCallback = finishCallback; return startEnterAnimation(change.getTaskInfo(), change.getLeash(), t); } } return false; } @Nullable @Override public WindowContainerTransaction handleRequest(@NonNull IBinder transition, @NonNull TransitionRequestInfo request) { return null; } @Override public void onFinishResize(TaskInfo taskInfo, Rect destinationBounds, @PipAnimationController.TransitionDirection int direction, SurfaceControl.Transaction tx) { WindowContainerTransaction wct = new WindowContainerTransaction(); prepareFinishResizeTransaction(taskInfo, destinationBounds, direction, tx, wct); mFinishCallback.onTransitionFinished(wct, null); finishResizeForMenu(destinationBounds); } private boolean startEnterAnimation(final TaskInfo taskInfo, final SurfaceControl leash, final SurfaceControl.Transaction t) { setBoundsStateForEntry(taskInfo.topActivity, taskInfo.pictureInPictureParams, taskInfo.topActivityInfo); final Rect destinationBounds = mPipBoundsAlgorithm.getEntryDestinationBounds(); final Rect currentBounds = taskInfo.configuration.windowConfiguration.getBounds(); PipAnimationController.PipTransitionAnimator animator; if (mOneShotAnimationType == ANIM_TYPE_BOUNDS) { final Rect sourceHintRect = PipBoundsAlgorithm.getValidSourceHintRect( taskInfo.pictureInPictureParams, currentBounds); animator = mPipAnimationController.getAnimator(taskInfo, leash, currentBounds, currentBounds, destinationBounds, sourceHintRect, TRANSITION_DIRECTION_TO_PIP, 0 /* startingAngle */); } else if (mOneShotAnimationType == ANIM_TYPE_ALPHA) { t.setAlpha(leash, 0f); t.apply(); animator = mPipAnimationController.getAnimator(taskInfo, leash, destinationBounds, 0f, 1f); mOneShotAnimationType = ANIM_TYPE_BOUNDS; } else { throw new RuntimeException("Unrecognized animation type: " + mOneShotAnimationType); } animator.setTransitionDirection(TRANSITION_DIRECTION_TO_PIP) .setPipAnimationCallback(mPipAnimationCallback) .setDuration(mEnterExitAnimationDuration) .start(); return true; } private void finishResizeForMenu(Rect destinationBounds) { mPipMenuController.movePipMenu(null, null, destinationBounds); mPipMenuController.updateMenuBounds(destinationBounds); } private void prepareFinishResizeTransaction(TaskInfo taskInfo, Rect destinationBounds, @PipAnimationController.TransitionDirection int direction, SurfaceControl.Transaction tx, WindowContainerTransaction wct) { Rect taskBounds = null; if (isInPipDirection(direction)) { // If we are animating from fullscreen using a bounds animation, then reset the // activity windowing mode set by WM, and set the task bounds to the final bounds taskBounds = destinationBounds; wct.setActivityWindowingMode(taskInfo.token, WINDOWING_MODE_UNDEFINED); wct.scheduleFinishEnterPip(taskInfo.token, destinationBounds); } else if (isOutPipDirection(direction)) { // If we are animating to fullscreen, then we need to reset the override bounds // on the task to ensure that the task "matches" the parent's bounds. taskBounds = (direction == TRANSITION_DIRECTION_LEAVE_PIP) ? null : destinationBounds; wct.setWindowingMode(taskInfo.token, getOutPipWindowingMode()); // Simply reset the activity mode set prior to the animation running. wct.setActivityWindowingMode(taskInfo.token, WINDOWING_MODE_UNDEFINED); } wct.setBounds(taskInfo.token, taskBounds); wct.setBoundsChangeTransaction(taskInfo.token, tx); } }