Add basic PiP Transition foundation.
This adds the proper hook for framework to request PiP transition from Shell and run the animation as needed. Currently only Enter using 3-finger navigation is supported, along with a KI that the PiP bounds are not finalized at the end of the animation. Bug: 165793917 Test: Enter PiP with ENABLE_SHELL_TRANSITIONS flag on Change-Id: I0b992840ddcf8ddfcec9759a5cb06b630f1899a8
This commit is contained in:
@@ -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;
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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) {}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -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();
|
||||
@@ -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);
|
||||
@@ -234,7 +239,7 @@ public class PipAnimationController {
|
||||
mCurrentValue = mStartValue;
|
||||
onStartTransaction(mLeash, newSurfaceControlTransaction());
|
||||
if (mPipAnimationCallback != null) {
|
||||
mPipAnimationCallback.onPipAnimationStart(this);
|
||||
mPipAnimationCallback.onPipAnimationStart(mTaskInfo, this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
@@ -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
|
||||
@@ -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());
|
||||
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
|
||||
@@ -41,10 +41,10 @@ import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
import android.animation.ValueAnimator;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.app.ActivityManager;
|
||||
import android.app.ActivityTaskManager;
|
||||
import android.app.PictureInPictureParams;
|
||||
import android.app.TaskInfo;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.pm.ActivityInfo;
|
||||
@@ -54,7 +54,6 @@ import android.os.IBinder;
|
||||
import android.os.RemoteException;
|
||||
import android.util.Log;
|
||||
import android.util.Rational;
|
||||
import android.util.Size;
|
||||
import android.view.Display;
|
||||
import android.view.SurfaceControl;
|
||||
import android.window.TaskOrganizer;
|
||||
@@ -63,7 +62,6 @@ import android.window.WindowContainerTransaction;
|
||||
import android.window.WindowContainerTransactionCallback;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.internal.jank.InteractionJankMonitor;
|
||||
import com.android.wm.shell.R;
|
||||
import com.android.wm.shell.ShellTaskOrganizer;
|
||||
import com.android.wm.shell.common.DisplayController;
|
||||
@@ -71,10 +69,10 @@ import com.android.wm.shell.common.ShellExecutor;
|
||||
import com.android.wm.shell.common.annotations.ShellMainThread;
|
||||
import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
|
||||
import com.android.wm.shell.pip.phone.PipMotionHelper;
|
||||
import com.android.wm.shell.transition.Transitions;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
@@ -132,8 +130,8 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
|
||||
private final PipBoundsAlgorithm mPipBoundsAlgorithm;
|
||||
private final @NonNull PipMenuController mPipMenuController;
|
||||
private final PipAnimationController mPipAnimationController;
|
||||
private final PipTransitionController mPipTransitionController;
|
||||
private final PipUiEventLogger mPipUiEventLoggerLogger;
|
||||
private final List<PipTransitionCallback> mPipTransitionCallbacks = new ArrayList<>();
|
||||
private final int mEnterExitAnimationDuration;
|
||||
private final PipSurfaceTransactionHelper mSurfaceTransactionHelper;
|
||||
private final Map<IBinder, Configuration> mInitialState = new HashMap<>();
|
||||
@@ -145,7 +143,8 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
|
||||
private final PipAnimationController.PipAnimationCallback mPipAnimationCallback =
|
||||
new PipAnimationController.PipAnimationCallback() {
|
||||
@Override
|
||||
public void onPipAnimationStart(PipAnimationController.PipTransitionAnimator animator) {
|
||||
public void onPipAnimationStart(TaskInfo taskInfo,
|
||||
PipAnimationController.PipTransitionAnimator animator) {
|
||||
final int direction = animator.getTransitionDirection();
|
||||
if (direction == TRANSITION_DIRECTION_TO_PIP) {
|
||||
// TODO (b//169221267): Add jank listener for transactions without buffer updates.
|
||||
@@ -156,7 +155,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPipAnimationEnd(SurfaceControl.Transaction tx,
|
||||
public void onPipAnimationEnd(TaskInfo taskInfo, SurfaceControl.Transaction tx,
|
||||
PipAnimationController.PipTransitionAnimator animator) {
|
||||
final int direction = animator.getTransitionDirection();
|
||||
finishResize(tx, animator.getDestinationBounds(), direction,
|
||||
@@ -170,7 +169,8 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPipAnimationCancel(PipAnimationController.PipTransitionAnimator animator) {
|
||||
public void onPipAnimationCancel(TaskInfo taskInfo,
|
||||
PipAnimationController.PipTransitionAnimator animator) {
|
||||
sendOnPipTransitionCancelled(animator.getTransitionDirection());
|
||||
}
|
||||
};
|
||||
@@ -202,7 +202,9 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
|
||||
public PipTaskOrganizer(Context context, @NonNull PipBoundsState pipBoundsState,
|
||||
@NonNull PipBoundsAlgorithm boundsHandler,
|
||||
@NonNull PipMenuController pipMenuController,
|
||||
@NonNull PipAnimationController pipAnimationController,
|
||||
@NonNull PipSurfaceTransactionHelper surfaceTransactionHelper,
|
||||
@NonNull PipTransitionController pipTransitionController,
|
||||
Optional<LegacySplitScreen> splitScreenOptional,
|
||||
@NonNull DisplayController displayController,
|
||||
@NonNull PipUiEventLogger pipUiEventLogger,
|
||||
@@ -211,10 +213,11 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
|
||||
mPipBoundsState = pipBoundsState;
|
||||
mPipBoundsAlgorithm = boundsHandler;
|
||||
mPipMenuController = pipMenuController;
|
||||
mPipTransitionController = pipTransitionController;
|
||||
mEnterExitAnimationDuration = context.getResources()
|
||||
.getInteger(R.integer.config_pipResizeAnimationDuration);
|
||||
mSurfaceTransactionHelper = surfaceTransactionHelper;
|
||||
mPipAnimationController = new PipAnimationController(mSurfaceTransactionHelper);
|
||||
mPipAnimationController = pipAnimationController;
|
||||
mPipUiEventLoggerLogger = pipUiEventLogger;
|
||||
mSurfaceControlTransactionFactory = SurfaceControl.Transaction::new;
|
||||
mSplitScreenOptional = splitScreenOptional;
|
||||
@@ -245,13 +248,6 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
|
||||
return mState.isInPip() && mWaitForFixedRotation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers {@link PipTransitionCallback} to receive transition callbacks.
|
||||
*/
|
||||
public void registerPipTransitionCallback(PipTransitionCallback callback) {
|
||||
mPipTransitionCallbacks.add(callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a callback when a display change has been detected when we enter PiP.
|
||||
*/
|
||||
@@ -275,7 +271,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
|
||||
public Rect startSwipePipToHome(ComponentName componentName, ActivityInfo activityInfo,
|
||||
PictureInPictureParams pictureInPictureParams) {
|
||||
mInSwipePipToHomeTransition = true;
|
||||
sendOnPipTransitionStarted(componentName, TRANSITION_DIRECTION_TO_PIP);
|
||||
sendOnPipTransitionStarted(TRANSITION_DIRECTION_TO_PIP);
|
||||
setBoundsStateForEntry(componentName, pictureInPictureParams, activityInfo);
|
||||
// disable the conflicting transaction from fixed rotation, see also
|
||||
// onFixedRotationStarted and onFixedRotationFinished
|
||||
@@ -296,9 +292,9 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
|
||||
|
||||
private void setBoundsStateForEntry(ComponentName componentName, PictureInPictureParams params,
|
||||
ActivityInfo activityInfo) {
|
||||
mPipBoundsState.setLastPipComponentName(componentName);
|
||||
mPipBoundsState.setAspectRatio(getAspectRatioOrDefault(params));
|
||||
mPipBoundsState.setOverrideMinSize(getMinimalSize(activityInfo));
|
||||
mPipBoundsState.setBoundsStateForEntry(componentName,
|
||||
mPipBoundsAlgorithm.getAspectRatioOrDefault(params),
|
||||
mPipBoundsAlgorithm.getMinimalSize(activityInfo));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -362,8 +358,8 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
|
||||
t.apply();
|
||||
// Make sure to grab the latest source hint rect as it could have been
|
||||
// updated right after applying the windowing mode change.
|
||||
final Rect sourceHintRect = getValidSourceHintRect(mPictureInPictureParams,
|
||||
destinationBounds);
|
||||
final Rect sourceHintRect = PipBoundsAlgorithm.getValidSourceHintRect(
|
||||
mPictureInPictureParams, destinationBounds);
|
||||
scheduleAnimateResizePip(mPipBoundsState.getBounds(), destinationBounds,
|
||||
0 /* startingAngle */, sourceHintRect, direction,
|
||||
animationDurationMs, null /* updateBoundsCallback */);
|
||||
@@ -398,7 +394,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
|
||||
|
||||
// removePipImmediately is expected when the following animation finishes.
|
||||
mPipAnimationController
|
||||
.getAnimator(mLeash, mPipBoundsState.getBounds(), 1f, 0f)
|
||||
.getAnimator(mTaskInfo, mLeash, mPipBoundsState.getBounds(), 1f, 0f)
|
||||
.setTransitionDirection(TRANSITION_DIRECTION_REMOVE_STACK)
|
||||
.setPipAnimationCallback(mPipAnimationCallback)
|
||||
.setDuration(mEnterExitAnimationDuration)
|
||||
@@ -470,10 +466,17 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
|
||||
Objects.requireNonNull(destinationBounds, "Missing destination bounds");
|
||||
final Rect currentBounds = mTaskInfo.configuration.windowConfiguration.getBounds();
|
||||
|
||||
if (Transitions.ENABLE_SHELL_TRANSITIONS) {
|
||||
if (mOneShotAnimationType == ANIM_TYPE_BOUNDS) {
|
||||
mPipMenuController.attach(mLeash);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (mOneShotAnimationType == ANIM_TYPE_BOUNDS) {
|
||||
mPipMenuController.attach(mLeash);
|
||||
final Rect sourceHintRect = getValidSourceHintRect(info.pictureInPictureParams,
|
||||
currentBounds);
|
||||
final Rect sourceHintRect = PipBoundsAlgorithm.getValidSourceHintRect(
|
||||
info.pictureInPictureParams, currentBounds);
|
||||
scheduleAnimateResizePip(currentBounds, destinationBounds, 0 /* startingAngle */,
|
||||
sourceHintRect, TRANSITION_DIRECTION_TO_PIP, mEnterExitAnimationDuration,
|
||||
null /* updateBoundsCallback */);
|
||||
@@ -486,21 +489,6 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the source hint rect if it is valid (if provided and is contained by the current
|
||||
* task bounds).
|
||||
*/
|
||||
private 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;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
void enterPipWithAlphaAnimation(Rect destinationBounds, long durationMs) {
|
||||
// If we are fading the PIP in, then we should move the pip to the final location as
|
||||
@@ -512,7 +500,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
|
||||
tx.apply();
|
||||
applyEnterPipSyncTransaction(destinationBounds, () -> {
|
||||
mPipAnimationController
|
||||
.getAnimator(mLeash, destinationBounds, 0f, 1f)
|
||||
.getAnimator(mTaskInfo, mLeash, destinationBounds, 0f, 1f)
|
||||
.setTransitionDirection(TRANSITION_DIRECTION_TO_PIP)
|
||||
.setPipAnimationCallback(mPipAnimationCallback)
|
||||
.setDuration(durationMs)
|
||||
@@ -547,19 +535,10 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
|
||||
|
||||
private void sendOnPipTransitionStarted(
|
||||
@PipAnimationController.TransitionDirection int direction) {
|
||||
sendOnPipTransitionStarted(mTaskInfo.baseActivity, direction);
|
||||
}
|
||||
|
||||
private void sendOnPipTransitionStarted(ComponentName componentName,
|
||||
@PipAnimationController.TransitionDirection int direction) {
|
||||
if (direction == TRANSITION_DIRECTION_TO_PIP) {
|
||||
mState = State.ENTERING_PIP;
|
||||
}
|
||||
final Rect pipBounds = mPipBoundsState.getBounds();
|
||||
for (int i = mPipTransitionCallbacks.size() - 1; i >= 0; i--) {
|
||||
final PipTransitionCallback callback = mPipTransitionCallbacks.get(i);
|
||||
callback.onPipTransitionStarted(componentName, direction, pipBounds);
|
||||
}
|
||||
mPipTransitionController.sendOnPipTransitionStarted(direction);
|
||||
}
|
||||
|
||||
private void sendOnPipTransitionFinished(
|
||||
@@ -567,18 +546,12 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
|
||||
if (direction == TRANSITION_DIRECTION_TO_PIP) {
|
||||
mState = State.ENTERED_PIP;
|
||||
}
|
||||
for (int i = mPipTransitionCallbacks.size() - 1; i >= 0; i--) {
|
||||
final PipTransitionCallback callback = mPipTransitionCallbacks.get(i);
|
||||
callback.onPipTransitionFinished(mTaskInfo.baseActivity, direction);
|
||||
}
|
||||
mPipTransitionController.sendOnPipTransitionFinished(direction);
|
||||
}
|
||||
|
||||
private void sendOnPipTransitionCancelled(
|
||||
@PipAnimationController.TransitionDirection int direction) {
|
||||
for (int i = mPipTransitionCallbacks.size() - 1; i >= 0; i--) {
|
||||
final PipTransitionCallback callback = mPipTransitionCallbacks.get(i);
|
||||
callback.onPipTransitionCanceled(mTaskInfo.baseActivity, direction);
|
||||
}
|
||||
mPipTransitionController.sendOnPipTransitionCancelled(direction);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -616,7 +589,8 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
|
||||
public void onTaskInfoChanged(ActivityManager.RunningTaskInfo info) {
|
||||
Objects.requireNonNull(mToken, "onTaskInfoChanged requires valid existing mToken");
|
||||
mPipBoundsState.setLastPipComponentName(info.topActivity);
|
||||
mPipBoundsState.setOverrideMinSize(getMinimalSize(info.topActivityInfo));
|
||||
mPipBoundsState.setOverrideMinSize(
|
||||
mPipBoundsAlgorithm.getMinimalSize(info.topActivityInfo));
|
||||
final PictureInPictureParams newParams = info.pictureInPictureParams;
|
||||
if (newParams == null || !applyPictureInPictureParams(newParams)) {
|
||||
Log.d(TAG, "Ignored onTaskInfoChanged with PiP param: " + newParams);
|
||||
@@ -1081,33 +1055,14 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
|
||||
Rect baseBounds = direction == TRANSITION_DIRECTION_SNAP_AFTER_RESIZE
|
||||
? mPipBoundsState.getBounds() : currentBounds;
|
||||
mPipAnimationController
|
||||
.getAnimator(mLeash, baseBounds, currentBounds, destinationBounds, sourceHintRect,
|
||||
direction, startingAngle)
|
||||
.getAnimator(mTaskInfo, mLeash, baseBounds, currentBounds, destinationBounds,
|
||||
sourceHintRect, direction, startingAngle)
|
||||
.setTransitionDirection(direction)
|
||||
.setPipAnimationCallback(mPipAnimationCallback)
|
||||
.setDuration(durationMs)
|
||||
.start();
|
||||
}
|
||||
|
||||
private 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;
|
||||
}
|
||||
|
||||
private float getAspectRatioOrDefault(@Nullable PictureInPictureParams params) {
|
||||
return params == null || !params.hasSetAspectRatio()
|
||||
? mPipBoundsAlgorithm.getDefaultAspectRatio()
|
||||
: params.getAspectRatio();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sync with {@link LegacySplitScreen} on destination bounds if PiP is going to split screen.
|
||||
*
|
||||
@@ -1157,24 +1112,4 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
|
||||
public String toString() {
|
||||
return TAG + ":" + taskListenerTypeToString(TASK_LISTENER_TYPE_PIP);
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback interface for PiP transitions (both from and to PiP mode)
|
||||
*/
|
||||
public interface PipTransitionCallback {
|
||||
/**
|
||||
* Callback when the pip transition is started.
|
||||
*/
|
||||
void onPipTransitionStarted(ComponentName activity, int direction, Rect pipBounds);
|
||||
|
||||
/**
|
||||
* Callback when the pip transition is finished.
|
||||
*/
|
||||
void onPipTransitionFinished(ComponentName activity, int direction);
|
||||
|
||||
/**
|
||||
* Callback when the pip transition is cancelled.
|
||||
*/
|
||||
void onPipTransitionCanceled(ComponentName activity, int direction);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,162 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,184 @@
|
||||
/*
|
||||
* 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_UNDEFINED;
|
||||
|
||||
import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTION_REMOVE_STACK;
|
||||
import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTION_TO_PIP;
|
||||
|
||||
import android.app.PictureInPictureParams;
|
||||
import android.app.TaskInfo;
|
||||
import android.content.ComponentName;
|
||||
import android.content.pm.ActivityInfo;
|
||||
import android.graphics.Rect;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.view.SurfaceControl;
|
||||
|
||||
import com.android.wm.shell.ShellTaskOrganizer;
|
||||
import com.android.wm.shell.transition.Transitions;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Responsible supplying PiP Transitions.
|
||||
*/
|
||||
public abstract class PipTransitionController implements Transitions.TransitionHandler {
|
||||
|
||||
protected final PipAnimationController mPipAnimationController;
|
||||
protected final PipBoundsAlgorithm mPipBoundsAlgorithm;
|
||||
protected final PipBoundsState mPipBoundsState;
|
||||
protected final ShellTaskOrganizer mShellTaskOrganizer;
|
||||
protected final PipMenuController mPipMenuController;
|
||||
private final Handler mMainHandler;
|
||||
private final List<PipTransitionCallback> mPipTransitionCallbacks = new ArrayList<>();
|
||||
|
||||
protected final PipAnimationController.PipAnimationCallback mPipAnimationCallback =
|
||||
new PipAnimationController.PipAnimationCallback() {
|
||||
@Override
|
||||
public void onPipAnimationStart(TaskInfo taskInfo,
|
||||
PipAnimationController.PipTransitionAnimator animator) {
|
||||
final int direction = animator.getTransitionDirection();
|
||||
if (direction == TRANSITION_DIRECTION_TO_PIP) {
|
||||
// TODO (b//169221267): Add jank listener for transactions without buffer
|
||||
// updates.
|
||||
//InteractionJankMonitor.getInstance().begin(
|
||||
// InteractionJankMonitor.CUJ_LAUNCHER_APP_CLOSE_TO_PIP, 2000);
|
||||
}
|
||||
sendOnPipTransitionStarted(direction);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPipAnimationEnd(TaskInfo taskInfo, SurfaceControl.Transaction tx,
|
||||
PipAnimationController.PipTransitionAnimator animator) {
|
||||
final int direction = animator.getTransitionDirection();
|
||||
mPipBoundsState.setBounds(animator.getDestinationBounds());
|
||||
if (direction == TRANSITION_DIRECTION_REMOVE_STACK) {
|
||||
return;
|
||||
}
|
||||
onFinishResize(taskInfo, animator.getDestinationBounds(), direction, tx);
|
||||
sendOnPipTransitionFinished(direction);
|
||||
if (direction == TRANSITION_DIRECTION_TO_PIP) {
|
||||
// TODO (b//169221267): Add jank listener for transactions without buffer
|
||||
// updates.
|
||||
//InteractionJankMonitor.getInstance().end(
|
||||
// InteractionJankMonitor.CUJ_LAUNCHER_APP_CLOSE_TO_PIP);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPipAnimationCancel(TaskInfo taskInfo,
|
||||
PipAnimationController.PipTransitionAnimator animator) {
|
||||
sendOnPipTransitionCancelled(animator.getTransitionDirection());
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Called when transition is about to finish. This is usually for performing tasks such as
|
||||
* applying WindowContainerTransaction to finalize the PiP bounds and send to the framework.
|
||||
*/
|
||||
public void onFinishResize(TaskInfo taskInfo, Rect destinationBounds,
|
||||
@PipAnimationController.TransitionDirection int direction,
|
||||
SurfaceControl.Transaction tx) {
|
||||
}
|
||||
|
||||
public PipTransitionController(PipBoundsState pipBoundsState,
|
||||
PipMenuController pipMenuController, PipBoundsAlgorithm pipBoundsAlgorithm,
|
||||
PipAnimationController pipAnimationController, Transitions transitions,
|
||||
@android.annotation.NonNull ShellTaskOrganizer shellTaskOrganizer) {
|
||||
mPipBoundsState = pipBoundsState;
|
||||
mPipMenuController = pipMenuController;
|
||||
mShellTaskOrganizer = shellTaskOrganizer;
|
||||
mPipBoundsAlgorithm = pipBoundsAlgorithm;
|
||||
mPipAnimationController = pipAnimationController;
|
||||
mMainHandler = new Handler(Looper.getMainLooper());
|
||||
if (Transitions.ENABLE_SHELL_TRANSITIONS) {
|
||||
transitions.addHandler(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers {@link PipTransitionCallback} to receive transition callbacks.
|
||||
*/
|
||||
public void registerPipTransitionCallback(PipTransitionCallback callback) {
|
||||
mPipTransitionCallbacks.add(callback);
|
||||
}
|
||||
|
||||
protected void sendOnPipTransitionStarted(
|
||||
@PipAnimationController.TransitionDirection int direction) {
|
||||
final Rect pipBounds = mPipBoundsState.getBounds();
|
||||
for (int i = mPipTransitionCallbacks.size() - 1; i >= 0; i--) {
|
||||
final PipTransitionCallback callback = mPipTransitionCallbacks.get(i);
|
||||
callback.onPipTransitionStarted(direction, pipBounds);
|
||||
}
|
||||
}
|
||||
|
||||
protected void sendOnPipTransitionFinished(
|
||||
@PipAnimationController.TransitionDirection int direction) {
|
||||
for (int i = mPipTransitionCallbacks.size() - 1; i >= 0; i--) {
|
||||
final PipTransitionCallback callback = mPipTransitionCallbacks.get(i);
|
||||
callback.onPipTransitionFinished(direction);
|
||||
}
|
||||
}
|
||||
|
||||
protected void sendOnPipTransitionCancelled(
|
||||
@PipAnimationController.TransitionDirection int direction) {
|
||||
for (int i = mPipTransitionCallbacks.size() - 1; i >= 0; i--) {
|
||||
final PipTransitionCallback callback = mPipTransitionCallbacks.get(i);
|
||||
callback.onPipTransitionCanceled(direction);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The windowing mode to restore to when resizing out of PIP direction. Defaults to undefined
|
||||
* and can be overridden to restore to an alternate windowing mode.
|
||||
*/
|
||||
public int getOutPipWindowingMode() {
|
||||
// By default, simply reset the windowing mode to undefined.
|
||||
return WINDOWING_MODE_UNDEFINED;
|
||||
}
|
||||
|
||||
protected void setBoundsStateForEntry(ComponentName componentName,
|
||||
PictureInPictureParams params,
|
||||
ActivityInfo activityInfo) {
|
||||
mPipBoundsState.setBoundsStateForEntry(componentName,
|
||||
mPipBoundsAlgorithm.getAspectRatioOrDefault(params),
|
||||
mPipBoundsAlgorithm.getMinimalSize(activityInfo));
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback interface for PiP transitions (both from and to PiP mode)
|
||||
*/
|
||||
public interface PipTransitionCallback {
|
||||
/**
|
||||
* Callback when the pip transition is started.
|
||||
*/
|
||||
void onPipTransitionStarted(int direction, Rect pipBounds);
|
||||
|
||||
/**
|
||||
* Callback when the pip transition is finished.
|
||||
*/
|
||||
void onPipTransitionFinished(int direction);
|
||||
|
||||
/**
|
||||
* Callback when the pip transition is cancelled.
|
||||
*/
|
||||
void onPipTransitionCanceled(int direction);
|
||||
}
|
||||
}
|
||||
@@ -61,6 +61,7 @@ import com.android.wm.shell.pip.PipBoundsState;
|
||||
import com.android.wm.shell.pip.PipMediaController;
|
||||
import com.android.wm.shell.pip.PipSnapAlgorithm;
|
||||
import com.android.wm.shell.pip.PipTaskOrganizer;
|
||||
import com.android.wm.shell.pip.PipTransitionController;
|
||||
import com.android.wm.shell.pip.PipUtils;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
@@ -69,7 +70,7 @@ import java.util.function.Consumer;
|
||||
/**
|
||||
* Manages the picture-in-picture (PIP) UI and states for Phones.
|
||||
*/
|
||||
public class PipController implements PipTaskOrganizer.PipTransitionCallback {
|
||||
public class PipController implements PipTransitionController.PipTransitionCallback {
|
||||
private static final String TAG = "PipController";
|
||||
|
||||
private Context mContext;
|
||||
@@ -82,6 +83,7 @@ public class PipController implements PipTaskOrganizer.PipTransitionCallback {
|
||||
private PipBoundsAlgorithm mPipBoundsAlgorithm;
|
||||
private PipBoundsState mPipBoundsState;
|
||||
private PipTouchHandler mTouchHandler;
|
||||
private PipTransitionController mPipTransitionController;
|
||||
protected final PipImpl mImpl = new PipImpl();
|
||||
|
||||
private final Rect mTmpInsetBounds = new Rect();
|
||||
@@ -214,7 +216,6 @@ public class PipController implements PipTaskOrganizer.PipTransitionCallback {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Instantiates {@link PipController}, returns {@code null} if the feature not supported.
|
||||
*/
|
||||
@@ -223,7 +224,8 @@ public class PipController implements PipTaskOrganizer.PipTransitionCallback {
|
||||
PipAppOpsListener pipAppOpsListener, PipBoundsAlgorithm pipBoundsAlgorithm,
|
||||
PipBoundsState pipBoundsState, PipMediaController pipMediaController,
|
||||
PhonePipMenuController phonePipMenuController, PipTaskOrganizer pipTaskOrganizer,
|
||||
PipTouchHandler pipTouchHandler, WindowManagerShellWrapper windowManagerShellWrapper,
|
||||
PipTouchHandler pipTouchHandler, PipTransitionController pipTransitionController,
|
||||
WindowManagerShellWrapper windowManagerShellWrapper,
|
||||
TaskStackListenerImpl taskStackListener, ShellExecutor mainExecutor) {
|
||||
if (!context.getPackageManager().hasSystemFeature(FEATURE_PICTURE_IN_PICTURE)) {
|
||||
Slog.w(TAG, "Device doesn't support Pip feature");
|
||||
@@ -232,7 +234,8 @@ public class PipController implements PipTaskOrganizer.PipTransitionCallback {
|
||||
|
||||
return new PipController(context, displayController, pipAppOpsListener, pipBoundsAlgorithm,
|
||||
pipBoundsState, pipMediaController, phonePipMenuController, pipTaskOrganizer,
|
||||
pipTouchHandler, windowManagerShellWrapper, taskStackListener, mainExecutor)
|
||||
pipTouchHandler, pipTransitionController, windowManagerShellWrapper,
|
||||
taskStackListener, mainExecutor)
|
||||
.mImpl;
|
||||
}
|
||||
|
||||
@@ -245,6 +248,7 @@ public class PipController implements PipTaskOrganizer.PipTransitionCallback {
|
||||
PhonePipMenuController phonePipMenuController,
|
||||
PipTaskOrganizer pipTaskOrganizer,
|
||||
PipTouchHandler pipTouchHandler,
|
||||
PipTransitionController pipTransitionController,
|
||||
WindowManagerShellWrapper windowManagerShellWrapper,
|
||||
TaskStackListenerImpl taskStackListener,
|
||||
ShellExecutor mainExecutor
|
||||
@@ -266,9 +270,10 @@ public class PipController implements PipTaskOrganizer.PipTransitionCallback {
|
||||
mMenuController = phonePipMenuController;
|
||||
mTouchHandler = pipTouchHandler;
|
||||
mAppOpsListener = pipAppOpsListener;
|
||||
mPipTransitionController = pipTransitionController;
|
||||
mPipInputConsumer = new PipInputConsumer(WindowManagerGlobal.getWindowManagerService(),
|
||||
INPUT_CONSUMER_PIP, mainExecutor);
|
||||
mPipTaskOrganizer.registerPipTransitionCallback(this);
|
||||
mPipTransitionController.registerPipTransitionCallback(this);
|
||||
mPipTaskOrganizer.registerOnDisplayIdChangeCallback((int displayId) -> {
|
||||
mPipBoundsState.setDisplayId(displayId);
|
||||
onDisplayChanged(displayController.getDisplayLayout(displayId),
|
||||
@@ -489,7 +494,7 @@ public class PipController implements PipTaskOrganizer.PipTransitionCallback {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPipTransitionStarted(ComponentName activity, int direction, Rect pipBounds) {
|
||||
public void onPipTransitionStarted(int direction, Rect pipBounds) {
|
||||
if (isOutPipDirection(direction)) {
|
||||
// Exiting PIP, save the reentry state to restore to when re-entering.
|
||||
saveReentryState(pipBounds);
|
||||
@@ -514,12 +519,12 @@ public class PipController implements PipTaskOrganizer.PipTransitionCallback {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPipTransitionFinished(ComponentName activity, int direction) {
|
||||
public void onPipTransitionFinished(int direction) {
|
||||
onPipTransitionFinishedOrCanceled(direction);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPipTransitionCanceled(ComponentName activity, int direction) {
|
||||
public void onPipTransitionCanceled(int direction) {
|
||||
onPipTransitionFinishedOrCanceled(direction);
|
||||
}
|
||||
|
||||
|
||||
@@ -22,7 +22,6 @@ import static com.android.wm.shell.pip.PipBoundsState.STASH_TYPE_RIGHT;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.graphics.PointF;
|
||||
import android.graphics.Rect;
|
||||
@@ -44,6 +43,7 @@ import com.android.wm.shell.common.magnetictarget.MagnetizedObject;
|
||||
import com.android.wm.shell.pip.PipBoundsState;
|
||||
import com.android.wm.shell.pip.PipSnapAlgorithm;
|
||||
import com.android.wm.shell.pip.PipTaskOrganizer;
|
||||
import com.android.wm.shell.pip.PipTransitionController;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
@@ -152,13 +152,13 @@ public class PipMotionHelper implements PipAppOpsListener.Callback,
|
||||
*/
|
||||
private Runnable mPostPipTransitionCallback;
|
||||
|
||||
private final PipTaskOrganizer.PipTransitionCallback mPipTransitionCallback =
|
||||
new PipTaskOrganizer.PipTransitionCallback() {
|
||||
private final PipTransitionController.PipTransitionCallback mPipTransitionCallback =
|
||||
new PipTransitionController.PipTransitionCallback() {
|
||||
@Override
|
||||
public void onPipTransitionStarted(ComponentName activity, int direction, Rect pipBounds) {}
|
||||
public void onPipTransitionStarted(int direction, Rect pipBounds) {}
|
||||
|
||||
@Override
|
||||
public void onPipTransitionFinished(ComponentName activity, int direction) {
|
||||
public void onPipTransitionFinished(int direction) {
|
||||
if (mPostPipTransitionCallback != null) {
|
||||
mPostPipTransitionCallback.run();
|
||||
mPostPipTransitionCallback = null;
|
||||
@@ -166,20 +166,20 @@ public class PipMotionHelper implements PipAppOpsListener.Callback,
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPipTransitionCanceled(ComponentName activity, int direction) {}
|
||||
public void onPipTransitionCanceled(int direction) {}
|
||||
};
|
||||
|
||||
public PipMotionHelper(Context context, @NonNull PipBoundsState pipBoundsState,
|
||||
PipTaskOrganizer pipTaskOrganizer, PhonePipMenuController menuController,
|
||||
PipSnapAlgorithm snapAlgorithm, FloatingContentCoordinator floatingContentCoordinator,
|
||||
ShellExecutor mainExecutor) {
|
||||
PipSnapAlgorithm snapAlgorithm, PipTransitionController pipTransitionController,
|
||||
FloatingContentCoordinator floatingContentCoordinator, ShellExecutor mainExecutor) {
|
||||
mContext = context;
|
||||
mPipTaskOrganizer = pipTaskOrganizer;
|
||||
mPipBoundsState = pipBoundsState;
|
||||
mMenuController = menuController;
|
||||
mSnapAlgorithm = snapAlgorithm;
|
||||
mFloatingContentCoordinator = floatingContentCoordinator;
|
||||
mPipTaskOrganizer.registerPipTransitionCallback(mPipTransitionCallback);
|
||||
pipTransitionController.registerPipTransitionCallback(mPipTransitionCallback);
|
||||
mTemporaryBoundsPhysicsAnimator = PhysicsAnimator.getInstance(
|
||||
mPipBoundsState.getMotionBoundsState().getBoundsInMotion());
|
||||
|
||||
|
||||
@@ -51,6 +51,7 @@ import com.android.wm.shell.pip.PipAnimationController;
|
||||
import com.android.wm.shell.pip.PipBoundsAlgorithm;
|
||||
import com.android.wm.shell.pip.PipBoundsState;
|
||||
import com.android.wm.shell.pip.PipTaskOrganizer;
|
||||
import com.android.wm.shell.pip.PipTransitionController;
|
||||
import com.android.wm.shell.pip.PipUiEventLogger;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
@@ -156,6 +157,7 @@ public class PipTouchHandler {
|
||||
PipBoundsAlgorithm pipBoundsAlgorithm,
|
||||
@NonNull PipBoundsState pipBoundsState,
|
||||
PipTaskOrganizer pipTaskOrganizer,
|
||||
PipTransitionController pipTransitionController,
|
||||
FloatingContentCoordinator floatingContentCoordinator,
|
||||
PipUiEventLogger pipUiEventLogger,
|
||||
ShellExecutor mainExecutor) {
|
||||
@@ -168,7 +170,7 @@ public class PipTouchHandler {
|
||||
mMenuController.addListener(new PipMenuListener());
|
||||
mGesture = new DefaultPipTouchGesture();
|
||||
mMotionHelper = new PipMotionHelper(mContext, pipBoundsState, pipTaskOrganizer,
|
||||
mMenuController, mPipBoundsAlgorithm.getSnapAlgorithm(),
|
||||
mMenuController, mPipBoundsAlgorithm.getSnapAlgorithm(), pipTransitionController,
|
||||
floatingContentCoordinator, mainExecutor);
|
||||
mPipResizeGestureHandler =
|
||||
new PipResizeGestureHandler(context, pipBoundsAlgorithm, pipBoundsState,
|
||||
|
||||
@@ -46,6 +46,7 @@ import com.android.wm.shell.pip.PipBoundsAlgorithm;
|
||||
import com.android.wm.shell.pip.PipBoundsState;
|
||||
import com.android.wm.shell.pip.PipMediaController;
|
||||
import com.android.wm.shell.pip.PipTaskOrganizer;
|
||||
import com.android.wm.shell.pip.PipTransitionController;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
@@ -53,7 +54,7 @@ import java.lang.annotation.RetentionPolicy;
|
||||
/**
|
||||
* Manages the picture-in-picture (PIP) UI and states.
|
||||
*/
|
||||
public class TvPipController implements PipTaskOrganizer.PipTransitionCallback,
|
||||
public class TvPipController implements PipTransitionController.PipTransitionCallback,
|
||||
TvPipMenuController.Delegate, TvPipNotificationController.Delegate {
|
||||
private static final String TAG = "TvPipController";
|
||||
static final boolean DEBUG = true;
|
||||
@@ -105,6 +106,7 @@ public class TvPipController implements PipTaskOrganizer.PipTransitionCallback,
|
||||
PipBoundsState pipBoundsState,
|
||||
PipBoundsAlgorithm pipBoundsAlgorithm,
|
||||
PipTaskOrganizer pipTaskOrganizer,
|
||||
PipTransitionController pipTransitionController,
|
||||
TvPipMenuController tvPipMenuController,
|
||||
PipMediaController pipMediaController,
|
||||
TvPipNotificationController pipNotificationController,
|
||||
@@ -116,6 +118,7 @@ public class TvPipController implements PipTaskOrganizer.PipTransitionCallback,
|
||||
pipBoundsState,
|
||||
pipBoundsAlgorithm,
|
||||
pipTaskOrganizer,
|
||||
pipTransitionController,
|
||||
tvPipMenuController,
|
||||
pipMediaController,
|
||||
pipNotificationController,
|
||||
@@ -129,6 +132,7 @@ public class TvPipController implements PipTaskOrganizer.PipTransitionCallback,
|
||||
PipBoundsState pipBoundsState,
|
||||
PipBoundsAlgorithm pipBoundsAlgorithm,
|
||||
PipTaskOrganizer pipTaskOrganizer,
|
||||
PipTransitionController pipTransitionController,
|
||||
TvPipMenuController tvPipMenuController,
|
||||
PipMediaController pipMediaController,
|
||||
TvPipNotificationController pipNotificationController,
|
||||
@@ -152,7 +156,7 @@ public class TvPipController implements PipTaskOrganizer.PipTransitionCallback,
|
||||
mTvPipMenuController.setDelegate(this);
|
||||
|
||||
mPipTaskOrganizer = pipTaskOrganizer;
|
||||
mPipTaskOrganizer.registerPipTransitionCallback(this);
|
||||
pipTransitionController.registerPipTransitionCallback(this);
|
||||
|
||||
loadConfigurations();
|
||||
|
||||
@@ -302,17 +306,17 @@ public class TvPipController implements PipTaskOrganizer.PipTransitionCallback,
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPipTransitionStarted(ComponentName activity, int direction, Rect pipBounds) {
|
||||
public void onPipTransitionStarted(int direction, Rect pipBounds) {
|
||||
if (DEBUG) Log.d(TAG, "onPipTransition_Started(), state=" + stateToName(mState));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPipTransitionCanceled(ComponentName activity, int direction) {
|
||||
public void onPipTransitionCanceled(int direction) {
|
||||
if (DEBUG) Log.d(TAG, "onPipTransition_Canceled(), state=" + stateToName(mState));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPipTransitionFinished(ComponentName activity, int direction) {
|
||||
public void onPipTransitionFinished(int direction) {
|
||||
if (DEBUG) Log.d(TAG, "onPipTransition_Finished(), state=" + stateToName(mState));
|
||||
|
||||
if (mState == STATE_PIP_MENU) {
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* 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.tv;
|
||||
|
||||
import android.app.TaskInfo;
|
||||
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.ShellTaskOrganizer;
|
||||
import com.android.wm.shell.pip.PipAnimationController;
|
||||
import com.android.wm.shell.pip.PipBoundsAlgorithm;
|
||||
import com.android.wm.shell.pip.PipBoundsState;
|
||||
import com.android.wm.shell.pip.PipMenuController;
|
||||
import com.android.wm.shell.pip.PipTransitionController;
|
||||
import com.android.wm.shell.transition.Transitions;
|
||||
|
||||
/**
|
||||
* PiP Transition for TV.
|
||||
* TODO: Implement animation once TV is using Transitions.
|
||||
*/
|
||||
public class TvPipTransition extends PipTransitionController {
|
||||
public TvPipTransition(PipBoundsState pipBoundsState,
|
||||
PipMenuController pipMenuController,
|
||||
PipBoundsAlgorithm pipBoundsAlgorithm,
|
||||
PipAnimationController pipAnimationController,
|
||||
Transitions transitions,
|
||||
@NonNull ShellTaskOrganizer shellTaskOrganizer) {
|
||||
super(pipBoundsState, pipMenuController, pipBoundsAlgorithm, pipAnimationController,
|
||||
transitions, shellTaskOrganizer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFinishResize(TaskInfo taskInfo, Rect destinationBounds, int direction,
|
||||
SurfaceControl.Transaction tx) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean startAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info,
|
||||
@NonNull SurfaceControl.Transaction t,
|
||||
@NonNull Transitions.TransitionFinishCallback finishCallback) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public WindowContainerTransaction handleRequest(@NonNull IBinder transition,
|
||||
@NonNull TransitionRequestInfo request) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -24,6 +24,7 @@ import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import android.app.TaskInfo;
|
||||
import android.graphics.Matrix;
|
||||
import android.graphics.Rect;
|
||||
import android.testing.AndroidTestingRunner;
|
||||
@@ -53,6 +54,9 @@ public class PipAnimationControllerTest extends ShellTestCase {
|
||||
|
||||
private SurfaceControl mLeash;
|
||||
|
||||
@Mock
|
||||
private TaskInfo mTaskInfo;
|
||||
|
||||
@Mock
|
||||
private PipAnimationController.PipAnimationCallback mPipAnimationCallback;
|
||||
|
||||
@@ -70,7 +74,7 @@ public class PipAnimationControllerTest extends ShellTestCase {
|
||||
@Test
|
||||
public void getAnimator_withAlpha_returnFloatAnimator() {
|
||||
final PipAnimationController.PipTransitionAnimator animator = mPipAnimationController
|
||||
.getAnimator(mLeash, new Rect(), 0f, 1f);
|
||||
.getAnimator(mTaskInfo, mLeash, new Rect(), 0f, 1f);
|
||||
|
||||
assertEquals("Expect ANIM_TYPE_ALPHA animation",
|
||||
animator.getAnimationType(), PipAnimationController.ANIM_TYPE_ALPHA);
|
||||
@@ -79,7 +83,7 @@ public class PipAnimationControllerTest extends ShellTestCase {
|
||||
@Test
|
||||
public void getAnimator_withBounds_returnBoundsAnimator() {
|
||||
final PipAnimationController.PipTransitionAnimator animator = mPipAnimationController
|
||||
.getAnimator(mLeash, new Rect(), new Rect(), new Rect(), null,
|
||||
.getAnimator(mTaskInfo, mLeash, new Rect(), new Rect(), new Rect(), null,
|
||||
TRANSITION_DIRECTION_TO_PIP, 0);
|
||||
|
||||
assertEquals("Expect ANIM_TYPE_BOUNDS animation",
|
||||
@@ -93,13 +97,13 @@ public class PipAnimationControllerTest extends ShellTestCase {
|
||||
final Rect endValue1 = new Rect(100, 100, 200, 200);
|
||||
final Rect endValue2 = new Rect(200, 200, 300, 300);
|
||||
final PipAnimationController.PipTransitionAnimator oldAnimator = mPipAnimationController
|
||||
.getAnimator(mLeash, baseValue, startValue, endValue1, null,
|
||||
.getAnimator(mTaskInfo, mLeash, baseValue, startValue, endValue1, null,
|
||||
TRANSITION_DIRECTION_TO_PIP, 0);
|
||||
oldAnimator.setSurfaceControlTransactionFactory(DummySurfaceControlTx::new);
|
||||
oldAnimator.start();
|
||||
|
||||
final PipAnimationController.PipTransitionAnimator newAnimator = mPipAnimationController
|
||||
.getAnimator(mLeash, baseValue, startValue, endValue2, null,
|
||||
.getAnimator(mTaskInfo, mLeash, baseValue, startValue, endValue2, null,
|
||||
TRANSITION_DIRECTION_TO_PIP, 0);
|
||||
|
||||
assertEquals("getAnimator with same type returns same animator",
|
||||
@@ -111,13 +115,13 @@ public class PipAnimationControllerTest extends ShellTestCase {
|
||||
@Test
|
||||
public void getAnimator_setTransitionDirection() {
|
||||
PipAnimationController.PipTransitionAnimator animator = mPipAnimationController
|
||||
.getAnimator(mLeash, new Rect(), 0f, 1f)
|
||||
.getAnimator(mTaskInfo, mLeash, new Rect(), 0f, 1f)
|
||||
.setTransitionDirection(TRANSITION_DIRECTION_TO_PIP);
|
||||
assertEquals("Transition to PiP mode",
|
||||
animator.getTransitionDirection(), TRANSITION_DIRECTION_TO_PIP);
|
||||
|
||||
animator = mPipAnimationController
|
||||
.getAnimator(mLeash, new Rect(), 0f, 1f)
|
||||
.getAnimator(mTaskInfo, mLeash, new Rect(), 0f, 1f)
|
||||
.setTransitionDirection(TRANSITION_DIRECTION_LEAVE_PIP);
|
||||
assertEquals("Transition to fullscreen mode",
|
||||
animator.getTransitionDirection(), TRANSITION_DIRECTION_LEAVE_PIP);
|
||||
@@ -131,7 +135,7 @@ public class PipAnimationControllerTest extends ShellTestCase {
|
||||
final Rect endValue1 = new Rect(100, 100, 200, 200);
|
||||
final Rect endValue2 = new Rect(200, 200, 300, 300);
|
||||
final PipAnimationController.PipTransitionAnimator animator = mPipAnimationController
|
||||
.getAnimator(mLeash, baseValue, startValue, endValue1, null,
|
||||
.getAnimator(mTaskInfo, mLeash, baseValue, startValue, endValue1, null,
|
||||
TRANSITION_DIRECTION_TO_PIP, 0);
|
||||
|
||||
animator.updateEndValue(endValue2);
|
||||
@@ -145,7 +149,7 @@ public class PipAnimationControllerTest extends ShellTestCase {
|
||||
final Rect startValue = new Rect(0, 0, 100, 100);
|
||||
final Rect endValue = new Rect(100, 100, 200, 200);
|
||||
final PipAnimationController.PipTransitionAnimator animator = mPipAnimationController
|
||||
.getAnimator(mLeash, baseValue, startValue, endValue, null,
|
||||
.getAnimator(mTaskInfo, mLeash, baseValue, startValue, endValue, null,
|
||||
TRANSITION_DIRECTION_TO_PIP, 0);
|
||||
animator.setSurfaceControlTransactionFactory(DummySurfaceControlTx::new);
|
||||
|
||||
@@ -153,16 +157,16 @@ public class PipAnimationControllerTest extends ShellTestCase {
|
||||
|
||||
// onAnimationStart triggers onPipAnimationStart
|
||||
animator.onAnimationStart(animator);
|
||||
verify(mPipAnimationCallback).onPipAnimationStart(animator);
|
||||
verify(mPipAnimationCallback).onPipAnimationStart(mTaskInfo, animator);
|
||||
|
||||
// onAnimationCancel triggers onPipAnimationCancel
|
||||
animator.onAnimationCancel(animator);
|
||||
verify(mPipAnimationCallback).onPipAnimationCancel(animator);
|
||||
verify(mPipAnimationCallback).onPipAnimationCancel(mTaskInfo, animator);
|
||||
|
||||
// onAnimationEnd triggers onPipAnimationEnd
|
||||
animator.onAnimationEnd(animator);
|
||||
verify(mPipAnimationCallback).onPipAnimationEnd(any(SurfaceControl.Transaction.class),
|
||||
eq(animator));
|
||||
verify(mPipAnimationCallback).onPipAnimationEnd(eq(mTaskInfo),
|
||||
any(SurfaceControl.Transaction.class), eq(animator));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -18,27 +18,23 @@ package com.android.wm.shell.pip;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyFloat;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.ArgumentMatchers.anyLong;
|
||||
import static org.mockito.Mockito.doNothing;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.app.ActivityManager;
|
||||
import android.app.PictureInPictureParams;
|
||||
import android.content.ComponentName;
|
||||
import android.content.pm.ActivityInfo;
|
||||
import android.graphics.Rect;
|
||||
import android.os.RemoteException;
|
||||
import android.test.suitebuilder.annotation.SmallTest;
|
||||
import android.testing.AndroidTestingRunner;
|
||||
import android.testing.TestableLooper;
|
||||
import android.util.Rational;
|
||||
import android.util.Size;
|
||||
import android.view.Display;
|
||||
import android.view.DisplayInfo;
|
||||
import android.window.WindowContainerToken;
|
||||
|
||||
@@ -47,9 +43,8 @@ import com.android.wm.shell.ShellTestCase;
|
||||
import com.android.wm.shell.TestShellExecutor;
|
||||
import com.android.wm.shell.common.DisplayController;
|
||||
import com.android.wm.shell.common.DisplayLayout;
|
||||
import com.android.wm.shell.common.ShellExecutor;
|
||||
import com.android.wm.shell.pip.phone.PhonePipMenuController;
|
||||
import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
|
||||
import com.android.wm.shell.pip.phone.PhonePipMenuController;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
@@ -69,14 +64,17 @@ public class PipTaskOrganizerTest extends ShellTestCase {
|
||||
private PipTaskOrganizer mSpiedPipTaskOrganizer;
|
||||
|
||||
@Mock private DisplayController mMockdDisplayController;
|
||||
@Mock private PipBoundsAlgorithm mMockPipBoundsAlgorithm;
|
||||
|
||||
@Mock private PhonePipMenuController mMockPhonePipMenuController;
|
||||
@Mock private PipAnimationController mMockPipAnimationController;
|
||||
@Mock private PipTransitionController mMockPipTransitionController;
|
||||
@Mock private PipSurfaceTransactionHelper mMockPipSurfaceTransactionHelper;
|
||||
@Mock private PipUiEventLogger mMockPipUiEventLogger;
|
||||
@Mock private Optional<LegacySplitScreen> mMockOptionalSplitScreen;
|
||||
@Mock private ShellTaskOrganizer mMockShellTaskOrganizer;
|
||||
private TestShellExecutor mMainExecutor;
|
||||
private PipBoundsState mPipBoundsState;
|
||||
private PipBoundsAlgorithm mPipBoundsAlgorithm;
|
||||
|
||||
private ComponentName mComponent1;
|
||||
private ComponentName mComponent2;
|
||||
@@ -87,10 +85,12 @@ public class PipTaskOrganizerTest extends ShellTestCase {
|
||||
mComponent1 = new ComponentName(mContext, "component1");
|
||||
mComponent2 = new ComponentName(mContext, "component2");
|
||||
mPipBoundsState = new PipBoundsState(mContext);
|
||||
mPipBoundsAlgorithm = new PipBoundsAlgorithm(mContext, mPipBoundsState);
|
||||
mMainExecutor = new TestShellExecutor();
|
||||
mSpiedPipTaskOrganizer = spy(new PipTaskOrganizer(mContext, mPipBoundsState,
|
||||
mMockPipBoundsAlgorithm, mMockPhonePipMenuController,
|
||||
mMockPipSurfaceTransactionHelper, mMockOptionalSplitScreen, mMockdDisplayController,
|
||||
mPipBoundsAlgorithm, mMockPhonePipMenuController,
|
||||
mMockPipAnimationController, mMockPipSurfaceTransactionHelper,
|
||||
mMockPipTransitionController, mMockOptionalSplitScreen, mMockdDisplayController,
|
||||
mMockPipUiEventLogger, mMockShellTaskOrganizer, mMainExecutor));
|
||||
mMainExecutor.flushAll();
|
||||
preparePipTaskOrg();
|
||||
@@ -117,7 +117,7 @@ public class PipTaskOrganizerTest extends ShellTestCase {
|
||||
|
||||
@Test
|
||||
public void startSwipePipToHome_updatesLastPipComponentName() {
|
||||
mSpiedPipTaskOrganizer.startSwipePipToHome(mComponent1, null, null);
|
||||
mSpiedPipTaskOrganizer.startSwipePipToHome(mComponent1, null, createPipParams(null));
|
||||
|
||||
assertEquals(mComponent1, mPipBoundsState.getLastPipComponentName());
|
||||
}
|
||||
@@ -126,7 +126,8 @@ public class PipTaskOrganizerTest extends ShellTestCase {
|
||||
public void startSwipePipToHome_updatesOverrideMinSize() {
|
||||
final Size minSize = new Size(100, 80);
|
||||
|
||||
mSpiedPipTaskOrganizer.startSwipePipToHome(mComponent1, createActivityInfo(minSize), null);
|
||||
mSpiedPipTaskOrganizer.startSwipePipToHome(mComponent1, createActivityInfo(minSize),
|
||||
createPipParams(null));
|
||||
|
||||
assertEquals(minSize, mPipBoundsState.getOverrideMinSize());
|
||||
}
|
||||
@@ -200,9 +201,6 @@ public class PipTaskOrganizerTest extends ShellTestCase {
|
||||
final DisplayInfo info = new DisplayInfo();
|
||||
mPipBoundsState.setDisplayLayout(new DisplayLayout(info,
|
||||
mContext.getResources(), true, true));
|
||||
when(mMockPipBoundsAlgorithm.getEntryDestinationBounds()).thenReturn(new Rect());
|
||||
when(mMockPipBoundsAlgorithm.getAdjustedDestinationBounds(any(), anyFloat()))
|
||||
.thenReturn(new Rect());
|
||||
mSpiedPipTaskOrganizer.setOneShotAnimationType(PipAnimationController.ANIM_TYPE_ALPHA);
|
||||
doNothing().when(mSpiedPipTaskOrganizer).enterPipWithAlphaAnimation(any(), anyLong());
|
||||
doNothing().when(mSpiedPipTaskOrganizer).scheduleAnimateResizePip(any(), anyInt(), any());
|
||||
|
||||
@@ -46,6 +46,7 @@ import com.android.wm.shell.pip.PipBoundsAlgorithm;
|
||||
import com.android.wm.shell.pip.PipBoundsState;
|
||||
import com.android.wm.shell.pip.PipMediaController;
|
||||
import com.android.wm.shell.pip.PipTaskOrganizer;
|
||||
import com.android.wm.shell.pip.PipTransitionController;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
@@ -68,6 +69,7 @@ public class PipControllerTest extends ShellTestCase {
|
||||
@Mock private PipBoundsAlgorithm mMockPipBoundsAlgorithm;
|
||||
@Mock private PipMediaController mMockPipMediaController;
|
||||
@Mock private PipTaskOrganizer mMockPipTaskOrganizer;
|
||||
@Mock private PipTransitionController mMockPipTransitionController;
|
||||
@Mock private PipTouchHandler mMockPipTouchHandler;
|
||||
@Mock private WindowManagerShellWrapper mMockWindowManagerShellWrapper;
|
||||
@Mock private PipBoundsState mMockPipBoundsState;
|
||||
@@ -80,8 +82,8 @@ public class PipControllerTest extends ShellTestCase {
|
||||
mPipController = new PipController(mContext, mMockDisplayController,
|
||||
mMockPipAppOpsListener, mMockPipBoundsAlgorithm, mMockPipBoundsState,
|
||||
mMockPipMediaController, mMockPhonePipMenuController, mMockPipTaskOrganizer,
|
||||
mMockPipTouchHandler, mMockWindowManagerShellWrapper, mMockTaskStackListener,
|
||||
mMockExecutor);
|
||||
mMockPipTouchHandler, mMockPipTransitionController, mMockWindowManagerShellWrapper,
|
||||
mMockTaskStackListener, mMockExecutor);
|
||||
doAnswer(invocation -> {
|
||||
((Runnable) invocation.getArgument(0)).run();
|
||||
return null;
|
||||
@@ -90,7 +92,7 @@ public class PipControllerTest extends ShellTestCase {
|
||||
|
||||
@Test
|
||||
public void instantiatePipController_registersPipTransitionCallback() {
|
||||
verify(mMockPipTaskOrganizer).registerPipTransitionCallback(any());
|
||||
verify(mMockPipTransitionController).registerPipTransitionCallback(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -113,8 +115,8 @@ public class PipControllerTest extends ShellTestCase {
|
||||
assertNull(PipController.create(spyContext, mMockDisplayController,
|
||||
mMockPipAppOpsListener, mMockPipBoundsAlgorithm, mMockPipBoundsState,
|
||||
mMockPipMediaController, mMockPhonePipMenuController, mMockPipTaskOrganizer,
|
||||
mMockPipTouchHandler, mMockWindowManagerShellWrapper, mMockTaskStackListener,
|
||||
mMockExecutor));
|
||||
mMockPipTouchHandler, mMockPipTransitionController, mMockWindowManagerShellWrapper,
|
||||
mMockTaskStackListener, mMockExecutor));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -38,6 +38,7 @@ import com.android.wm.shell.pip.PipBoundsAlgorithm;
|
||||
import com.android.wm.shell.pip.PipBoundsState;
|
||||
import com.android.wm.shell.pip.PipSnapAlgorithm;
|
||||
import com.android.wm.shell.pip.PipTaskOrganizer;
|
||||
import com.android.wm.shell.pip.PipTransitionController;
|
||||
import com.android.wm.shell.pip.PipUiEventLogger;
|
||||
|
||||
import org.junit.Before;
|
||||
@@ -66,6 +67,9 @@ public class PipTouchHandlerTest extends ShellTestCase {
|
||||
@Mock
|
||||
private PipTaskOrganizer mPipTaskOrganizer;
|
||||
|
||||
@Mock
|
||||
private PipTransitionController mMockPipTransitionController;
|
||||
|
||||
@Mock
|
||||
private FloatingContentCoordinator mFloatingContentCoordinator;
|
||||
|
||||
@@ -98,7 +102,8 @@ public class PipTouchHandlerTest extends ShellTestCase {
|
||||
mPipSnapAlgorithm = new PipSnapAlgorithm();
|
||||
mPipTouchHandler = new PipTouchHandler(mContext, mPhonePipMenuController,
|
||||
mPipBoundsAlgorithm, mPipBoundsState, mPipTaskOrganizer,
|
||||
mFloatingContentCoordinator, mPipUiEventLogger, mMainExecutor);
|
||||
mMockPipTransitionController, mFloatingContentCoordinator, mPipUiEventLogger,
|
||||
mMainExecutor);
|
||||
mMotionHelper = Mockito.spy(mPipTouchHandler.getMotionHelper());
|
||||
mPipResizeGestureHandler = Mockito.spy(mPipTouchHandler.getPipResizeGestureHandler());
|
||||
mPipTouchHandler.setPipMotionHelper(mMotionHelper);
|
||||
|
||||
@@ -29,15 +29,19 @@ import com.android.wm.shell.common.TaskStackListenerImpl;
|
||||
import com.android.wm.shell.common.annotations.ShellMainThread;
|
||||
import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
|
||||
import com.android.wm.shell.pip.Pip;
|
||||
import com.android.wm.shell.pip.PipAnimationController;
|
||||
import com.android.wm.shell.pip.PipBoundsAlgorithm;
|
||||
import com.android.wm.shell.pip.PipBoundsState;
|
||||
import com.android.wm.shell.pip.PipMediaController;
|
||||
import com.android.wm.shell.pip.PipSurfaceTransactionHelper;
|
||||
import com.android.wm.shell.pip.PipTaskOrganizer;
|
||||
import com.android.wm.shell.pip.PipTransitionController;
|
||||
import com.android.wm.shell.pip.PipUiEventLogger;
|
||||
import com.android.wm.shell.pip.tv.TvPipController;
|
||||
import com.android.wm.shell.pip.tv.TvPipMenuController;
|
||||
import com.android.wm.shell.pip.tv.TvPipNotificationController;
|
||||
import com.android.wm.shell.pip.tv.TvPipTransition;
|
||||
import com.android.wm.shell.transition.Transitions;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
@@ -58,6 +62,7 @@ public abstract class TvPipModule {
|
||||
PipTaskOrganizer pipTaskOrganizer,
|
||||
TvPipMenuController tvPipMenuController,
|
||||
PipMediaController pipMediaController,
|
||||
PipTransitionController pipTransitionController,
|
||||
TvPipNotificationController tvPipNotificationController,
|
||||
TaskStackListenerImpl taskStackListener,
|
||||
WindowManagerShellWrapper windowManagerShellWrapper,
|
||||
@@ -68,6 +73,7 @@ public abstract class TvPipModule {
|
||||
pipBoundsState,
|
||||
pipBoundsAlgorithm,
|
||||
pipTaskOrganizer,
|
||||
pipTransitionController,
|
||||
tvPipMenuController,
|
||||
pipMediaController,
|
||||
tvPipNotificationController,
|
||||
@@ -90,6 +96,16 @@ public abstract class TvPipModule {
|
||||
}
|
||||
|
||||
// Handler needed for loadDrawableAsync() in PipControlsViewController
|
||||
@WMSingleton
|
||||
@Provides
|
||||
static PipTransitionController provideTvPipTransition(
|
||||
Transitions transitions, ShellTaskOrganizer shellTaskOrganizer,
|
||||
PipAnimationController pipAnimationController, PipBoundsAlgorithm pipBoundsAlgorithm,
|
||||
PipBoundsState pipBoundsState, TvPipMenuController pipMenuController) {
|
||||
return new TvPipTransition(pipBoundsState, pipMenuController,
|
||||
pipBoundsAlgorithm, pipAnimationController, transitions, shellTaskOrganizer);
|
||||
}
|
||||
|
||||
@WMSingleton
|
||||
@Provides
|
||||
static TvPipMenuController providesTvPipMenuController(
|
||||
@@ -111,18 +127,28 @@ public abstract class TvPipModule {
|
||||
return new TvPipNotificationController(context, pipMediaController, mainHandler);
|
||||
}
|
||||
|
||||
@WMSingleton
|
||||
@Provides
|
||||
static PipAnimationController providePipAnimationController(PipSurfaceTransactionHelper
|
||||
pipSurfaceTransactionHelper) {
|
||||
return new PipAnimationController(pipSurfaceTransactionHelper);
|
||||
}
|
||||
|
||||
@WMSingleton
|
||||
@Provides
|
||||
static PipTaskOrganizer providePipTaskOrganizer(Context context,
|
||||
TvPipMenuController tvPipMenuController,
|
||||
PipBoundsState pipBoundsState,
|
||||
PipBoundsAlgorithm pipBoundsAlgorithm,
|
||||
PipAnimationController pipAnimationController,
|
||||
PipTransitionController pipTransitionController,
|
||||
PipSurfaceTransactionHelper pipSurfaceTransactionHelper,
|
||||
Optional<LegacySplitScreen> splitScreenOptional, DisplayController displayController,
|
||||
PipUiEventLogger pipUiEventLogger, ShellTaskOrganizer shellTaskOrganizer,
|
||||
@ShellMainThread ShellExecutor mainExecutor) {
|
||||
return new PipTaskOrganizer(context, pipBoundsState, pipBoundsAlgorithm,
|
||||
tvPipMenuController, pipSurfaceTransactionHelper, splitScreenOptional,
|
||||
displayController, pipUiEventLogger, shellTaskOrganizer, mainExecutor);
|
||||
tvPipMenuController, pipAnimationController, pipSurfaceTransactionHelper,
|
||||
pipTransitionController, splitScreenOptional, displayController, pipUiEventLogger,
|
||||
shellTaskOrganizer, mainExecutor);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,13 +17,11 @@
|
||||
package com.android.systemui.wmshell;
|
||||
|
||||
import android.animation.AnimationHandler;
|
||||
import android.app.ActivityTaskManager;
|
||||
import android.content.Context;
|
||||
import android.os.Handler;
|
||||
import android.view.IWindowManager;
|
||||
|
||||
import com.android.systemui.dagger.WMSingleton;
|
||||
import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
|
||||
import com.android.wm.shell.ShellTaskOrganizer;
|
||||
import com.android.wm.shell.WindowManagerShellWrapper;
|
||||
import com.android.wm.shell.apppairs.AppPairs;
|
||||
@@ -41,18 +39,19 @@ import com.android.wm.shell.common.annotations.ShellMainThread;
|
||||
import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
|
||||
import com.android.wm.shell.legacysplitscreen.LegacySplitScreenController;
|
||||
import com.android.wm.shell.pip.Pip;
|
||||
import com.android.wm.shell.pip.PipAnimationController;
|
||||
import com.android.wm.shell.pip.PipBoundsAlgorithm;
|
||||
import com.android.wm.shell.pip.PipBoundsState;
|
||||
import com.android.wm.shell.pip.PipMediaController;
|
||||
import com.android.wm.shell.pip.PipSurfaceTransactionHelper;
|
||||
import com.android.wm.shell.pip.PipTaskOrganizer;
|
||||
import com.android.wm.shell.pip.PipTransition;
|
||||
import com.android.wm.shell.pip.PipTransitionController;
|
||||
import com.android.wm.shell.pip.PipUiEventLogger;
|
||||
import com.android.wm.shell.pip.phone.PhonePipMenuController;
|
||||
import com.android.wm.shell.pip.phone.PipAppOpsListener;
|
||||
import com.android.wm.shell.pip.phone.PipController;
|
||||
import com.android.wm.shell.pip.phone.PipTouchHandler;
|
||||
import com.android.wm.shell.splitscreen.SplitScreen;
|
||||
import com.android.wm.shell.splitscreen.SplitScreenController;
|
||||
import com.android.wm.shell.transition.Transitions;
|
||||
|
||||
import java.util.Optional;
|
||||
@@ -104,12 +103,13 @@ public class WMShellModule {
|
||||
PipAppOpsListener pipAppOpsListener, PipBoundsAlgorithm pipBoundsAlgorithm,
|
||||
PipBoundsState pipBoundsState, PipMediaController pipMediaController,
|
||||
PhonePipMenuController phonePipMenuController, PipTaskOrganizer pipTaskOrganizer,
|
||||
PipTouchHandler pipTouchHandler, WindowManagerShellWrapper windowManagerShellWrapper,
|
||||
PipTouchHandler pipTouchHandler, PipTransitionController pipTransitionController,
|
||||
WindowManagerShellWrapper windowManagerShellWrapper,
|
||||
TaskStackListenerImpl taskStackListener,
|
||||
@ShellMainThread ShellExecutor mainExecutor) {
|
||||
return Optional.ofNullable(PipController.create(context, displayController,
|
||||
pipAppOpsListener, pipBoundsAlgorithm, pipBoundsState, pipMediaController,
|
||||
phonePipMenuController, pipTaskOrganizer, pipTouchHandler,
|
||||
phonePipMenuController, pipTaskOrganizer, pipTouchHandler, pipTransitionController,
|
||||
windowManagerShellWrapper, taskStackListener, mainExecutor));
|
||||
}
|
||||
|
||||
@@ -143,12 +143,13 @@ public class WMShellModule {
|
||||
PhonePipMenuController menuPhoneController, PipBoundsAlgorithm pipBoundsAlgorithm,
|
||||
PipBoundsState pipBoundsState,
|
||||
PipTaskOrganizer pipTaskOrganizer,
|
||||
PipTransitionController pipTransitionController,
|
||||
FloatingContentCoordinator floatingContentCoordinator,
|
||||
PipUiEventLogger pipUiEventLogger,
|
||||
@ShellMainThread ShellExecutor mainExecutor) {
|
||||
return new PipTouchHandler(context, menuPhoneController, pipBoundsAlgorithm,
|
||||
pipBoundsState, pipTaskOrganizer, floatingContentCoordinator, pipUiEventLogger,
|
||||
mainExecutor);
|
||||
pipBoundsState, pipTaskOrganizer, pipTransitionController,
|
||||
floatingContentCoordinator, pipUiEventLogger, mainExecutor);
|
||||
}
|
||||
|
||||
@WMSingleton
|
||||
@@ -157,12 +158,32 @@ public class WMShellModule {
|
||||
PipBoundsState pipBoundsState,
|
||||
PipBoundsAlgorithm pipBoundsAlgorithm,
|
||||
PhonePipMenuController menuPhoneController,
|
||||
PipAnimationController pipAnimationController,
|
||||
PipSurfaceTransactionHelper pipSurfaceTransactionHelper,
|
||||
PipTransitionController pipTransitionController,
|
||||
Optional<LegacySplitScreen> splitScreenOptional, DisplayController displayController,
|
||||
PipUiEventLogger pipUiEventLogger, ShellTaskOrganizer shellTaskOrganizer,
|
||||
@ShellMainThread ShellExecutor mainExecutor) {
|
||||
return new PipTaskOrganizer(context, pipBoundsState, pipBoundsAlgorithm,
|
||||
menuPhoneController, pipSurfaceTransactionHelper, splitScreenOptional,
|
||||
displayController, pipUiEventLogger, shellTaskOrganizer, mainExecutor);
|
||||
menuPhoneController, pipAnimationController, pipSurfaceTransactionHelper,
|
||||
pipTransitionController, splitScreenOptional, displayController, pipUiEventLogger,
|
||||
shellTaskOrganizer, mainExecutor);
|
||||
}
|
||||
|
||||
@WMSingleton
|
||||
@Provides
|
||||
static PipAnimationController providePipAnimationController(PipSurfaceTransactionHelper
|
||||
pipSurfaceTransactionHelper) {
|
||||
return new PipAnimationController(pipSurfaceTransactionHelper);
|
||||
}
|
||||
|
||||
@WMSingleton
|
||||
@Provides
|
||||
static PipTransitionController providePipTransitionController(Context context,
|
||||
Transitions transitions, ShellTaskOrganizer shellTaskOrganizer,
|
||||
PipAnimationController pipAnimationController, PipBoundsAlgorithm pipBoundsAlgorithm,
|
||||
PipBoundsState pipBoundsState, PhonePipMenuController pipMenuController) {
|
||||
return new PipTransition(context, pipBoundsState, pipMenuController,
|
||||
pipBoundsAlgorithm, pipAnimationController, transitions, shellTaskOrganizer);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,6 +37,7 @@ import static android.view.WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
|
||||
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_SUSTAINED_PERFORMANCE_MODE;
|
||||
import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG;
|
||||
import static android.view.WindowManager.LayoutParams.TYPE_NOTIFICATION_SHADE;
|
||||
import static android.view.WindowManager.TRANSIT_CHANGE;
|
||||
import static android.view.WindowManager.TRANSIT_CLOSE;
|
||||
import static android.view.WindowManager.TRANSIT_FLAG_APP_CRASHED;
|
||||
import static android.view.WindowManager.TRANSIT_NONE;
|
||||
@@ -2180,6 +2181,8 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
|
||||
// display area, so reparent.
|
||||
rootTask.reparent(taskDisplayArea, true /* onTop */);
|
||||
}
|
||||
mService.getTransitionController().requestTransitionIfNeeded(TRANSIT_CHANGE, rootTask);
|
||||
|
||||
// Defer the windowing mode change until after the transition to prevent the activity
|
||||
// from doing work and changing the activity visuals while animating
|
||||
// TODO(task-org): Figure-out more structured way to do this long term.
|
||||
|
||||
Reference in New Issue
Block a user