Merge "Ensure that task org updates all happen off the main thread" into rvc-dev
This commit is contained in:
@@ -64,7 +64,7 @@ public class InputConsumerController {
|
|||||||
private final class InputEventReceiver extends BatchedInputEventReceiver {
|
private final class InputEventReceiver extends BatchedInputEventReceiver {
|
||||||
|
|
||||||
public InputEventReceiver(InputChannel inputChannel, Looper looper) {
|
public InputEventReceiver(InputChannel inputChannel, Looper looper) {
|
||||||
super(inputChannel, looper, Choreographer.getSfInstance());
|
super(inputChannel, looper, Choreographer.getInstance());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -19,11 +19,8 @@ package com.android.systemui.pip;
|
|||||||
import android.animation.Animator;
|
import android.animation.Animator;
|
||||||
import android.animation.ValueAnimator;
|
import android.animation.ValueAnimator;
|
||||||
import android.annotation.IntDef;
|
import android.annotation.IntDef;
|
||||||
import android.annotation.MainThread;
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
import android.os.RemoteException;
|
|
||||||
import android.view.IWindowContainer;
|
|
||||||
import android.view.SurfaceControl;
|
import android.view.SurfaceControl;
|
||||||
import android.view.animation.AnimationUtils;
|
import android.view.animation.AnimationUtils;
|
||||||
import android.view.animation.Interpolator;
|
import android.view.animation.Interpolator;
|
||||||
@@ -61,31 +58,30 @@ public class PipAnimationController {
|
|||||||
com.android.internal.R.interpolator.fast_out_slow_in);
|
com.android.internal.R.interpolator.fast_out_slow_in);
|
||||||
}
|
}
|
||||||
|
|
||||||
@MainThread
|
PipTransitionAnimator getAnimator(SurfaceControl leash, boolean scheduleFinishPip,
|
||||||
PipTransitionAnimator getAnimator(IWindowContainer wc, boolean scheduleFinishPip,
|
|
||||||
Rect destinationBounds, float alphaStart, float alphaEnd) {
|
Rect destinationBounds, float alphaStart, float alphaEnd) {
|
||||||
if (mCurrentAnimator == null) {
|
if (mCurrentAnimator == null) {
|
||||||
mCurrentAnimator = setupPipTransitionAnimator(
|
mCurrentAnimator = setupPipTransitionAnimator(
|
||||||
PipTransitionAnimator.ofAlpha(wc, scheduleFinishPip,
|
PipTransitionAnimator.ofAlpha(leash, scheduleFinishPip, destinationBounds,
|
||||||
destinationBounds, alphaStart, alphaEnd));
|
alphaStart, alphaEnd));
|
||||||
} else if (mCurrentAnimator.getAnimationType() == ANIM_TYPE_ALPHA
|
} else if (mCurrentAnimator.getAnimationType() == ANIM_TYPE_ALPHA
|
||||||
&& mCurrentAnimator.isRunning()) {
|
&& mCurrentAnimator.isRunning()) {
|
||||||
mCurrentAnimator.updateEndValue(alphaEnd);
|
mCurrentAnimator.updateEndValue(alphaEnd);
|
||||||
} else {
|
} else {
|
||||||
mCurrentAnimator.cancel();
|
mCurrentAnimator.cancel();
|
||||||
mCurrentAnimator = setupPipTransitionAnimator(
|
mCurrentAnimator = setupPipTransitionAnimator(
|
||||||
PipTransitionAnimator.ofAlpha(wc, scheduleFinishPip,
|
PipTransitionAnimator.ofAlpha(leash, scheduleFinishPip, destinationBounds,
|
||||||
destinationBounds, alphaStart, alphaEnd));
|
alphaStart, alphaEnd));
|
||||||
}
|
}
|
||||||
return mCurrentAnimator;
|
return mCurrentAnimator;
|
||||||
}
|
}
|
||||||
|
|
||||||
@MainThread
|
PipTransitionAnimator getAnimator(SurfaceControl leash, boolean scheduleFinishPip,
|
||||||
PipTransitionAnimator getAnimator(IWindowContainer wc, boolean scheduleFinishPip,
|
|
||||||
Rect startBounds, Rect endBounds) {
|
Rect startBounds, Rect endBounds) {
|
||||||
if (mCurrentAnimator == null) {
|
if (mCurrentAnimator == null) {
|
||||||
mCurrentAnimator = setupPipTransitionAnimator(
|
mCurrentAnimator = setupPipTransitionAnimator(
|
||||||
PipTransitionAnimator.ofBounds(wc, scheduleFinishPip, startBounds, endBounds));
|
PipTransitionAnimator.ofBounds(leash, scheduleFinishPip,
|
||||||
|
startBounds, endBounds));
|
||||||
} else if (mCurrentAnimator.getAnimationType() == ANIM_TYPE_BOUNDS
|
} else if (mCurrentAnimator.getAnimationType() == ANIM_TYPE_BOUNDS
|
||||||
&& mCurrentAnimator.isRunning()) {
|
&& mCurrentAnimator.isRunning()) {
|
||||||
mCurrentAnimator.setDestinationBounds(endBounds);
|
mCurrentAnimator.setDestinationBounds(endBounds);
|
||||||
@@ -94,7 +90,8 @@ public class PipAnimationController {
|
|||||||
} else {
|
} else {
|
||||||
mCurrentAnimator.cancel();
|
mCurrentAnimator.cancel();
|
||||||
mCurrentAnimator = setupPipTransitionAnimator(
|
mCurrentAnimator = setupPipTransitionAnimator(
|
||||||
PipTransitionAnimator.ofBounds(wc, scheduleFinishPip, startBounds, endBounds));
|
PipTransitionAnimator.ofBounds(leash, scheduleFinishPip,
|
||||||
|
startBounds, endBounds));
|
||||||
}
|
}
|
||||||
return mCurrentAnimator;
|
return mCurrentAnimator;
|
||||||
}
|
}
|
||||||
@@ -116,18 +113,18 @@ public class PipAnimationController {
|
|||||||
/**
|
/**
|
||||||
* Called when PiP animation is started.
|
* Called when PiP animation is started.
|
||||||
*/
|
*/
|
||||||
public void onPipAnimationStart(IWindowContainer wc, PipTransitionAnimator animator) {}
|
public void onPipAnimationStart(PipTransitionAnimator animator) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when PiP animation is ended.
|
* Called when PiP animation is ended.
|
||||||
*/
|
*/
|
||||||
public void onPipAnimationEnd(IWindowContainer wc, SurfaceControl.Transaction tx,
|
public void onPipAnimationEnd(SurfaceControl.Transaction tx,
|
||||||
PipTransitionAnimator animator) {}
|
PipTransitionAnimator animator) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when PiP animation is cancelled.
|
* Called when PiP animation is cancelled.
|
||||||
*/
|
*/
|
||||||
public void onPipAnimationCancel(IWindowContainer wc, PipTransitionAnimator animator) {}
|
public void onPipAnimationCancel(PipTransitionAnimator animator) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -137,7 +134,6 @@ public class PipAnimationController {
|
|||||||
public abstract static class PipTransitionAnimator<T> extends ValueAnimator implements
|
public abstract static class PipTransitionAnimator<T> extends ValueAnimator implements
|
||||||
ValueAnimator.AnimatorUpdateListener,
|
ValueAnimator.AnimatorUpdateListener,
|
||||||
ValueAnimator.AnimatorListener {
|
ValueAnimator.AnimatorListener {
|
||||||
private final IWindowContainer mWindowContainer;
|
|
||||||
private final boolean mScheduleFinishPip;
|
private final boolean mScheduleFinishPip;
|
||||||
private final SurfaceControl mLeash;
|
private final SurfaceControl mLeash;
|
||||||
private final @AnimationType int mAnimationType;
|
private final @AnimationType int mAnimationType;
|
||||||
@@ -149,23 +145,18 @@ public class PipAnimationController {
|
|||||||
private PipAnimationCallback mPipAnimationCallback;
|
private PipAnimationCallback mPipAnimationCallback;
|
||||||
private SurfaceControlTransactionFactory mSurfaceControlTransactionFactory;
|
private SurfaceControlTransactionFactory mSurfaceControlTransactionFactory;
|
||||||
|
|
||||||
private PipTransitionAnimator(IWindowContainer wc, boolean scheduleFinishPip,
|
private PipTransitionAnimator(SurfaceControl leash, boolean scheduleFinishPip,
|
||||||
@AnimationType int animationType, Rect destinationBounds,
|
@AnimationType int animationType, Rect destinationBounds,
|
||||||
T startValue, T endValue) {
|
T startValue, T endValue) {
|
||||||
mWindowContainer = wc;
|
|
||||||
mScheduleFinishPip = scheduleFinishPip;
|
mScheduleFinishPip = scheduleFinishPip;
|
||||||
try {
|
mLeash = leash;
|
||||||
mLeash = wc.getLeash();
|
mAnimationType = animationType;
|
||||||
mAnimationType = animationType;
|
mDestinationBounds.set(destinationBounds);
|
||||||
mDestinationBounds.set(destinationBounds);
|
mStartValue = startValue;
|
||||||
mStartValue = startValue;
|
mEndValue = endValue;
|
||||||
mEndValue = endValue;
|
addListener(this);
|
||||||
addListener(this);
|
addUpdateListener(this);
|
||||||
addUpdateListener(this);
|
mSurfaceControlTransactionFactory = SurfaceControl.Transaction::new;
|
||||||
mSurfaceControlTransactionFactory = SurfaceControl.Transaction::new;
|
|
||||||
} catch (RemoteException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -173,7 +164,7 @@ public class PipAnimationController {
|
|||||||
mCurrentValue = mStartValue;
|
mCurrentValue = mStartValue;
|
||||||
applySurfaceControlTransaction(mLeash, newSurfaceControlTransaction(), FRACTION_START);
|
applySurfaceControlTransaction(mLeash, newSurfaceControlTransaction(), FRACTION_START);
|
||||||
if (mPipAnimationCallback != null) {
|
if (mPipAnimationCallback != null) {
|
||||||
mPipAnimationCallback.onPipAnimationStart(mWindowContainer, this);
|
mPipAnimationCallback.onPipAnimationStart(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -189,14 +180,14 @@ public class PipAnimationController {
|
|||||||
final SurfaceControl.Transaction tx = newSurfaceControlTransaction();
|
final SurfaceControl.Transaction tx = newSurfaceControlTransaction();
|
||||||
applySurfaceControlTransaction(mLeash, tx, FRACTION_END);
|
applySurfaceControlTransaction(mLeash, tx, FRACTION_END);
|
||||||
if (mPipAnimationCallback != null) {
|
if (mPipAnimationCallback != null) {
|
||||||
mPipAnimationCallback.onPipAnimationEnd(mWindowContainer, tx, this);
|
mPipAnimationCallback.onPipAnimationEnd(tx, this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onAnimationCancel(Animator animation) {
|
public void onAnimationCancel(Animator animation) {
|
||||||
if (mPipAnimationCallback != null) {
|
if (mPipAnimationCallback != null) {
|
||||||
mPipAnimationCallback.onPipAnimationCancel(mWindowContainer, this);
|
mPipAnimationCallback.onPipAnimationCancel(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -260,9 +251,9 @@ public class PipAnimationController {
|
|||||||
abstract void applySurfaceControlTransaction(SurfaceControl leash,
|
abstract void applySurfaceControlTransaction(SurfaceControl leash,
|
||||||
SurfaceControl.Transaction tx, float fraction);
|
SurfaceControl.Transaction tx, float fraction);
|
||||||
|
|
||||||
static PipTransitionAnimator<Float> ofAlpha(IWindowContainer wc, boolean scheduleFinishPip,
|
static PipTransitionAnimator<Float> ofAlpha(SurfaceControl leash, boolean scheduleFinishPip,
|
||||||
Rect destinationBounds, float startValue, float endValue) {
|
Rect destinationBounds, float startValue, float endValue) {
|
||||||
return new PipTransitionAnimator<Float>(wc, scheduleFinishPip, ANIM_TYPE_ALPHA,
|
return new PipTransitionAnimator<Float>(leash, scheduleFinishPip, ANIM_TYPE_ALPHA,
|
||||||
destinationBounds, startValue, endValue) {
|
destinationBounds, startValue, endValue) {
|
||||||
@Override
|
@Override
|
||||||
void applySurfaceControlTransaction(SurfaceControl leash,
|
void applySurfaceControlTransaction(SurfaceControl leash,
|
||||||
@@ -281,10 +272,10 @@ public class PipAnimationController {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
static PipTransitionAnimator<Rect> ofBounds(IWindowContainer wc, boolean scheduleFinishPip,
|
static PipTransitionAnimator<Rect> ofBounds(SurfaceControl leash, boolean scheduleFinishPip,
|
||||||
Rect startValue, Rect endValue) {
|
Rect startValue, Rect endValue) {
|
||||||
// construct new Rect instances in case they are recycled
|
// construct new Rect instances in case they are recycled
|
||||||
return new PipTransitionAnimator<Rect>(wc, scheduleFinishPip, ANIM_TYPE_BOUNDS,
|
return new PipTransitionAnimator<Rect>(leash, scheduleFinishPip, ANIM_TYPE_BOUNDS,
|
||||||
endValue, new Rect(startValue), new Rect(endValue)) {
|
endValue, new Rect(startValue), new Rect(endValue)) {
|
||||||
private final Rect mTmpRect = new Rect();
|
private final Rect mTmpRect = new Rect();
|
||||||
|
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ import android.content.Context;
|
|||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
|
import android.os.Message;
|
||||||
import android.os.RemoteException;
|
import android.os.RemoteException;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.DisplayInfo;
|
import android.view.DisplayInfo;
|
||||||
@@ -38,9 +39,13 @@ import android.view.IWindowContainer;
|
|||||||
import android.view.SurfaceControl;
|
import android.view.SurfaceControl;
|
||||||
import android.view.WindowContainerTransaction;
|
import android.view.WindowContainerTransaction;
|
||||||
|
|
||||||
|
import com.android.internal.os.SomeArgs;
|
||||||
|
import com.android.systemui.pip.phone.PipUpdateThread;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Manages PiP tasks such as resize and offset.
|
* Manages PiP tasks such as resize and offset.
|
||||||
@@ -56,7 +61,13 @@ import java.util.Objects;
|
|||||||
public class PipTaskOrganizer extends ITaskOrganizer.Stub {
|
public class PipTaskOrganizer extends ITaskOrganizer.Stub {
|
||||||
private static final String TAG = PipTaskOrganizer.class.getSimpleName();
|
private static final String TAG = PipTaskOrganizer.class.getSimpleName();
|
||||||
|
|
||||||
|
private static final int MSG_RESIZE_IMMEDIATE = 1;
|
||||||
|
private static final int MSG_RESIZE_ANIMATE = 2;
|
||||||
|
private static final int MSG_OFFSET_ANIMATE = 3;
|
||||||
|
private static final int MSG_FINISH_RESIZE = 4;
|
||||||
|
|
||||||
private final Handler mMainHandler;
|
private final Handler mMainHandler;
|
||||||
|
private final Handler mUpdateHandler;
|
||||||
private final ITaskOrganizerController mTaskOrganizerController;
|
private final ITaskOrganizerController mTaskOrganizerController;
|
||||||
private final PipBoundsHandler mPipBoundsHandler;
|
private final PipBoundsHandler mPipBoundsHandler;
|
||||||
private final PipAnimationController mPipAnimationController;
|
private final PipAnimationController mPipAnimationController;
|
||||||
@@ -64,11 +75,11 @@ public class PipTaskOrganizer extends ITaskOrganizer.Stub {
|
|||||||
private final Rect mDisplayBounds = new Rect();
|
private final Rect mDisplayBounds = new Rect();
|
||||||
private final Rect mLastReportedBounds = new Rect();
|
private final Rect mLastReportedBounds = new Rect();
|
||||||
|
|
||||||
|
// These callbacks are called on the update thread
|
||||||
private final PipAnimationController.PipAnimationCallback mPipAnimationCallback =
|
private final PipAnimationController.PipAnimationCallback mPipAnimationCallback =
|
||||||
new PipAnimationController.PipAnimationCallback() {
|
new PipAnimationController.PipAnimationCallback() {
|
||||||
@Override
|
@Override
|
||||||
public void onPipAnimationStart(IWindowContainer wc,
|
public void onPipAnimationStart(PipAnimationController.PipTransitionAnimator animator) {
|
||||||
PipAnimationController.PipTransitionAnimator animator) {
|
|
||||||
mMainHandler.post(() -> {
|
mMainHandler.post(() -> {
|
||||||
for (int i = mPipTransitionCallbacks.size() - 1; i >= 0; i--) {
|
for (int i = mPipTransitionCallbacks.size() - 1; i >= 0; i--) {
|
||||||
final PipTransitionCallback callback = mPipTransitionCallbacks.get(i);
|
final PipTransitionCallback callback = mPipTransitionCallbacks.get(i);
|
||||||
@@ -78,7 +89,7 @@ public class PipTaskOrganizer extends ITaskOrganizer.Stub {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPipAnimationEnd(IWindowContainer wc, SurfaceControl.Transaction tx,
|
public void onPipAnimationEnd(SurfaceControl.Transaction tx,
|
||||||
PipAnimationController.PipTransitionAnimator animator) {
|
PipAnimationController.PipTransitionAnimator animator) {
|
||||||
mMainHandler.post(() -> {
|
mMainHandler.post(() -> {
|
||||||
for (int i = mPipTransitionCallbacks.size() - 1; i >= 0; i--) {
|
for (int i = mPipTransitionCallbacks.size() - 1; i >= 0; i--) {
|
||||||
@@ -86,13 +97,11 @@ public class PipTaskOrganizer extends ITaskOrganizer.Stub {
|
|||||||
callback.onPipTransitionFinished();
|
callback.onPipTransitionFinished();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
final Rect destinationBounds = animator.getDestinationBounds();
|
finishResize(animator.getDestinationBounds(), tx, animator.shouldScheduleFinishPip());
|
||||||
finishResizeInternal(destinationBounds, wc, tx, animator.shouldScheduleFinishPip());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPipAnimationCancel(IWindowContainer wc,
|
public void onPipAnimationCancel(PipAnimationController.PipTransitionAnimator animator) {
|
||||||
PipAnimationController.PipTransitionAnimator animator) {
|
|
||||||
mMainHandler.post(() -> {
|
mMainHandler.post(() -> {
|
||||||
for (int i = mPipTransitionCallbacks.size() - 1; i >= 0; i--) {
|
for (int i = mPipTransitionCallbacks.size() - 1; i >= 0; i--) {
|
||||||
final PipTransitionCallback callback = mPipTransitionCallbacks.get(i);
|
final PipTransitionCallback callback = mPipTransitionCallbacks.get(i);
|
||||||
@@ -102,28 +111,75 @@ public class PipTaskOrganizer extends ITaskOrganizer.Stub {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private Handler.Callback mUpdateCallbacks = new Handler.Callback() {
|
||||||
|
@Override
|
||||||
|
public boolean handleMessage(Message msg) {
|
||||||
|
SomeArgs args = (SomeArgs) msg.obj;
|
||||||
|
Consumer<Rect> updateBoundsCallback = (Consumer<Rect>) args.arg1;
|
||||||
|
switch (msg.what) {
|
||||||
|
case MSG_RESIZE_IMMEDIATE: {
|
||||||
|
Rect toBounds = (Rect) args.arg2;
|
||||||
|
resizePip(toBounds);
|
||||||
|
if (updateBoundsCallback != null) {
|
||||||
|
updateBoundsCallback.accept(toBounds);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case MSG_RESIZE_ANIMATE: {
|
||||||
|
Rect currentBounds = (Rect) args.arg2;
|
||||||
|
Rect toBounds = (Rect) args.arg3;
|
||||||
|
boolean scheduleFinishPip = args.argi1 != 0;
|
||||||
|
int duration = args.argi2;
|
||||||
|
animateResizePip(scheduleFinishPip, currentBounds, toBounds, duration);
|
||||||
|
if (updateBoundsCallback != null) {
|
||||||
|
updateBoundsCallback.accept(toBounds);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case MSG_OFFSET_ANIMATE: {
|
||||||
|
Rect originalBounds = (Rect) args.arg2;
|
||||||
|
final int offset = args.argi1;
|
||||||
|
final int duration = args.argi2;
|
||||||
|
offsetPip(originalBounds, 0 /* xOffset */, offset, duration);
|
||||||
|
Rect toBounds = new Rect(originalBounds);
|
||||||
|
toBounds.offset(0, offset);
|
||||||
|
if (updateBoundsCallback != null) {
|
||||||
|
updateBoundsCallback.accept(toBounds);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case MSG_FINISH_RESIZE: {
|
||||||
|
SurfaceControl.Transaction tx = (SurfaceControl.Transaction) args.arg2;
|
||||||
|
Rect toBounds = (Rect) args.arg3;
|
||||||
|
boolean scheduleFinishPip = args.argi1 != 0;
|
||||||
|
finishResize(toBounds, tx, scheduleFinishPip);
|
||||||
|
if (updateBoundsCallback != null) {
|
||||||
|
updateBoundsCallback.accept(toBounds);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
args.recycle();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
private ActivityManager.RunningTaskInfo mTaskInfo;
|
private ActivityManager.RunningTaskInfo mTaskInfo;
|
||||||
|
private IWindowContainer mToken;
|
||||||
|
private SurfaceControl mLeash;
|
||||||
|
private boolean mInPip;
|
||||||
private @PipAnimationController.AnimationType int mOneShotAnimationType = ANIM_TYPE_BOUNDS;
|
private @PipAnimationController.AnimationType int mOneShotAnimationType = ANIM_TYPE_BOUNDS;
|
||||||
|
|
||||||
public PipTaskOrganizer(Context context, @NonNull PipBoundsHandler boundsHandler) {
|
public PipTaskOrganizer(Context context, @NonNull PipBoundsHandler boundsHandler) {
|
||||||
mMainHandler = new Handler(Looper.getMainLooper());
|
mMainHandler = new Handler(Looper.getMainLooper());
|
||||||
|
mUpdateHandler = new Handler(PipUpdateThread.get().getLooper(), mUpdateCallbacks);
|
||||||
mTaskOrganizerController = ActivityTaskManager.getTaskOrganizerController();
|
mTaskOrganizerController = ActivityTaskManager.getTaskOrganizerController();
|
||||||
mPipBoundsHandler = boundsHandler;
|
mPipBoundsHandler = boundsHandler;
|
||||||
mPipAnimationController = new PipAnimationController(context);
|
mPipAnimationController = new PipAnimationController(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public Handler getUpdateHandler() {
|
||||||
* Offset the PiP window, animate if the given duration is not {@link #DURATION_NONE}
|
return mUpdateHandler;
|
||||||
*/
|
|
||||||
public void offsetPinnedStack(Rect originalBounds, int xOffset, int yOffset, int durationMs) {
|
|
||||||
if (mTaskInfo == null) {
|
|
||||||
Log.w(TAG, "mTaskInfo is not set");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
final Rect destinationBounds = new Rect(originalBounds);
|
|
||||||
destinationBounds.offset(xOffset, yOffset);
|
|
||||||
animateResizePipInternal(mTaskInfo.token, false /* scheduleFinishPip*/,
|
|
||||||
originalBounds, destinationBounds, durationMs);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -171,7 +227,7 @@ public class PipTaskOrganizer extends ITaskOrganizer.Stub {
|
|||||||
try {
|
try {
|
||||||
mLastReportedBounds.set(destinationBounds);
|
mLastReportedBounds.set(destinationBounds);
|
||||||
final WindowContainerTransaction wct = new WindowContainerTransaction();
|
final WindowContainerTransaction wct = new WindowContainerTransaction();
|
||||||
wct.setBounds(mTaskInfo.token, destinationBounds);
|
wct.setBounds(mToken, destinationBounds);
|
||||||
mTaskOrganizerController.applyContainerTransaction(wct, null /* ITaskOrganizer */);
|
mTaskOrganizerController.applyContainerTransaction(wct, null /* ITaskOrganizer */);
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
Log.w(TAG, "Failed to apply window container transaction", e);
|
Log.w(TAG, "Failed to apply window container transaction", e);
|
||||||
@@ -185,13 +241,20 @@ public class PipTaskOrganizer extends ITaskOrganizer.Stub {
|
|||||||
getAspectRatioOrDefault(info.pictureInPictureParams), null /* bounds */);
|
getAspectRatioOrDefault(info.pictureInPictureParams), null /* bounds */);
|
||||||
Objects.requireNonNull(destinationBounds, "Missing destination bounds");
|
Objects.requireNonNull(destinationBounds, "Missing destination bounds");
|
||||||
mTaskInfo = info;
|
mTaskInfo = info;
|
||||||
|
mToken = mTaskInfo.token;
|
||||||
|
mInPip = true;
|
||||||
|
try {
|
||||||
|
mLeash = mToken.getLeash();
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
throw new RuntimeException("Unable to get leash", e);
|
||||||
|
}
|
||||||
if (mOneShotAnimationType == ANIM_TYPE_BOUNDS) {
|
if (mOneShotAnimationType == ANIM_TYPE_BOUNDS) {
|
||||||
final Rect currentBounds = mTaskInfo.configuration.windowConfiguration.getBounds();
|
final Rect currentBounds = mTaskInfo.configuration.windowConfiguration.getBounds();
|
||||||
animateResizePipInternal(mTaskInfo.token, true /* scheduleFinishPip */,
|
scheduleAnimateResizePip(true /* scheduleFinishPip */,
|
||||||
currentBounds, destinationBounds, DURATION_DEFAULT_MS);
|
currentBounds, destinationBounds, DURATION_DEFAULT_MS, null);
|
||||||
} else if (mOneShotAnimationType == ANIM_TYPE_ALPHA) {
|
} else if (mOneShotAnimationType == ANIM_TYPE_ALPHA) {
|
||||||
mMainHandler.post(() -> mPipAnimationController
|
mUpdateHandler.post(() -> mPipAnimationController
|
||||||
.getAnimator(mTaskInfo.token, true /* scheduleFinishPip */,
|
.getAnimator(mLeash, true /* scheduleFinishPip */,
|
||||||
destinationBounds, 0f, 1f)
|
destinationBounds, 0f, 1f)
|
||||||
.setPipAnimationCallback(mPipAnimationCallback)
|
.setPipAnimationCallback(mPipAnimationCallback)
|
||||||
.setDuration(DURATION_DEFAULT_MS)
|
.setDuration(DURATION_DEFAULT_MS)
|
||||||
@@ -205,12 +268,12 @@ public class PipTaskOrganizer extends ITaskOrganizer.Stub {
|
|||||||
@Override
|
@Override
|
||||||
public void taskVanished(IWindowContainer token) {
|
public void taskVanished(IWindowContainer token) {
|
||||||
Objects.requireNonNull(token, "Requires valid IWindowContainer");
|
Objects.requireNonNull(token, "Requires valid IWindowContainer");
|
||||||
if (token.asBinder() != mTaskInfo.token.asBinder()) {
|
if (token.asBinder() != mToken.asBinder()) {
|
||||||
Log.wtf(TAG, "Unrecognized token: " + token);
|
Log.wtf(TAG, "Unrecognized token: " + token);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
animateResizePipInternal(token, false /* scheduleFinishPip */,
|
scheduleAnimateResizePip(mDisplayBounds, DURATION_DEFAULT_MS, null);
|
||||||
mLastReportedBounds, mDisplayBounds, DURATION_DEFAULT_MS);
|
mInPip = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -227,7 +290,7 @@ public class PipTaskOrganizer extends ITaskOrganizer.Stub {
|
|||||||
final Rect destinationBounds = mPipBoundsHandler.getDestinationBounds(
|
final Rect destinationBounds = mPipBoundsHandler.getDestinationBounds(
|
||||||
getAspectRatioOrDefault(newParams), null /* bounds */);
|
getAspectRatioOrDefault(newParams), null /* bounds */);
|
||||||
Objects.requireNonNull(destinationBounds, "Missing destination bounds");
|
Objects.requireNonNull(destinationBounds, "Missing destination bounds");
|
||||||
animateResizePip(destinationBounds, DURATION_DEFAULT_MS);
|
scheduleAnimateResizePip(destinationBounds, DURATION_DEFAULT_MS, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -243,102 +306,158 @@ public class PipTaskOrganizer extends ITaskOrganizer.Stub {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Directly perform manipulation/resize on the leash. This will not perform any
|
* Animates resizing of the pinned stack given the duration.
|
||||||
* {@link WindowContainerTransaction} until {@link #finishResize} is called.
|
|
||||||
*/
|
*/
|
||||||
public void resizePip(Rect destinationBounds) {
|
public void scheduleAnimateResizePip(Rect toBounds, int duration,
|
||||||
Objects.requireNonNull(mTaskInfo, "Requires valid IWindowContainer");
|
Consumer<Rect> updateBoundsCallback) {
|
||||||
resizePipInternal(mTaskInfo.token, destinationBounds);
|
scheduleAnimateResizePip(false /* scheduleFinishPip */,
|
||||||
|
mLastReportedBounds, toBounds, duration, updateBoundsCallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void resizePipInternal(IWindowContainer wc,
|
private void scheduleAnimateResizePip(boolean scheduleFinishPip,
|
||||||
Rect destinationBounds) {
|
Rect currentBounds, Rect destinationBounds, int durationMs,
|
||||||
Objects.requireNonNull(mTaskInfo, "Requires valid IWindowContainer");
|
Consumer<Rect> updateBoundsCallback) {
|
||||||
try {
|
Objects.requireNonNull(mToken, "Requires valid IWindowContainer");
|
||||||
// Could happen when dismissPip
|
if (!mInPip) {
|
||||||
if (wc == null || wc.getLeash() == null) {
|
// Ignore animation when we are no longer in PIP
|
||||||
Log.w(TAG, "Abort animation, invalid leash");
|
return;
|
||||||
return;
|
|
||||||
}
|
|
||||||
final SurfaceControl leash = wc.getLeash();
|
|
||||||
new SurfaceControl.Transaction()
|
|
||||||
.setPosition(leash, destinationBounds.left, destinationBounds.top)
|
|
||||||
.setWindowCrop(leash, destinationBounds.width(), destinationBounds.height())
|
|
||||||
.apply();
|
|
||||||
} catch (RemoteException e) {
|
|
||||||
Log.w(TAG, "Abort animation, invalid window container", e);
|
|
||||||
} catch (Exception e) {
|
|
||||||
Log.e(TAG, "Should not reach here, terrible thing happened", e);
|
|
||||||
}
|
}
|
||||||
|
SomeArgs args = SomeArgs.obtain();
|
||||||
|
args.arg1 = updateBoundsCallback;
|
||||||
|
args.arg2 = currentBounds;
|
||||||
|
args.arg3 = destinationBounds;
|
||||||
|
args.argi1 = scheduleFinishPip ? 1 : 0;
|
||||||
|
args.argi2 = durationMs;
|
||||||
|
mUpdateHandler.sendMessage(mUpdateHandler.obtainMessage(MSG_RESIZE_ANIMATE, args));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Directly perform manipulation/resize on the leash. This will not perform any
|
||||||
|
* {@link WindowContainerTransaction} until {@link #scheduleFinishResizePip} is called.
|
||||||
|
*/
|
||||||
|
public void scheduleResizePip(Rect toBounds, Consumer<Rect> updateBoundsCallback) {
|
||||||
|
Objects.requireNonNull(mToken, "Requires valid IWindowContainer");
|
||||||
|
SomeArgs args = SomeArgs.obtain();
|
||||||
|
args.arg1 = updateBoundsCallback;
|
||||||
|
args.arg2 = toBounds;
|
||||||
|
mUpdateHandler.sendMessage(mUpdateHandler.obtainMessage(MSG_RESIZE_IMMEDIATE, args));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Finish a intermediate resize operation. This is expected to be called after
|
* Finish a intermediate resize operation. This is expected to be called after
|
||||||
* {@link #resizePip}.
|
* {@link #scheduleResizePip}.
|
||||||
*/
|
*/
|
||||||
public void finishResize(Rect destinationBounds) {
|
public void scheduleFinishResizePip(Rect destinationBounds) {
|
||||||
try {
|
Objects.requireNonNull(mToken, "Requires valid IWindowContainer");
|
||||||
final IWindowContainer wc = mTaskInfo.token;
|
SurfaceControl.Transaction tx = new SurfaceControl.Transaction()
|
||||||
SurfaceControl.Transaction tx = new SurfaceControl.Transaction()
|
.setPosition(mLeash, destinationBounds.left, destinationBounds.top)
|
||||||
.setPosition(wc.getLeash(), destinationBounds.left,
|
.setWindowCrop(mLeash, destinationBounds.width(), destinationBounds.height());
|
||||||
destinationBounds.top)
|
scheduleFinishResizePip(tx, destinationBounds, false /* scheduleFinishPip */,
|
||||||
.setWindowCrop(wc.getLeash(), destinationBounds.width(),
|
null);
|
||||||
destinationBounds.height());
|
|
||||||
finishResizeInternal(destinationBounds, wc, tx, false);
|
|
||||||
} catch (RemoteException e) {
|
|
||||||
Log.e(TAG, "Failed to obtain leash");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void finishResizeInternal(Rect destinationBounds, IWindowContainer wc,
|
private void scheduleFinishResizePip(SurfaceControl.Transaction tx,
|
||||||
SurfaceControl.Transaction tx, boolean shouldScheduleFinishPip) {
|
Rect destinationBounds, boolean scheduleFinishPip,
|
||||||
|
Consumer<Rect> updateBoundsCallback) {
|
||||||
|
Objects.requireNonNull(mToken, "Requires valid IWindowContainer");
|
||||||
|
SomeArgs args = SomeArgs.obtain();
|
||||||
|
args.arg1 = updateBoundsCallback;
|
||||||
|
args.arg2 = tx;
|
||||||
|
args.arg3 = destinationBounds;
|
||||||
|
args.argi1 = scheduleFinishPip ? 1 : 0;
|
||||||
|
mUpdateHandler.sendMessage(mUpdateHandler.obtainMessage(MSG_FINISH_RESIZE, args));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Offset the PiP window, animate if the given duration is not {@link #DURATION_NONE}
|
||||||
|
*/
|
||||||
|
public void scheduleOffsetPip(Rect originalBounds, int offset, int duration,
|
||||||
|
Consumer<Rect> updateBoundsCallback) {
|
||||||
|
if (!mInPip) {
|
||||||
|
// Ignore offsets when we are no longer in PIP
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Objects.requireNonNull(mToken, "Requires valid IWindowContainer");
|
||||||
|
SomeArgs args = SomeArgs.obtain();
|
||||||
|
args.arg1 = updateBoundsCallback;
|
||||||
|
args.arg2 = originalBounds;
|
||||||
|
// offset would be zero if triggered from screen rotation.
|
||||||
|
args.argi1 = offset;
|
||||||
|
args.argi2 = duration;
|
||||||
|
mUpdateHandler.sendMessage(mUpdateHandler.obtainMessage(MSG_OFFSET_ANIMATE, args));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void offsetPip(Rect originalBounds, int xOffset, int yOffset, int durationMs) {
|
||||||
|
if (Looper.myLooper() != mUpdateHandler.getLooper()) {
|
||||||
|
throw new RuntimeException("Callers should call scheduleOffsetPip() instead of this "
|
||||||
|
+ "directly");
|
||||||
|
}
|
||||||
|
if (mTaskInfo == null) {
|
||||||
|
Log.w(TAG, "mTaskInfo is not set");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final Rect destinationBounds = new Rect(originalBounds);
|
||||||
|
destinationBounds.offset(xOffset, yOffset);
|
||||||
|
animateResizePip(false /* scheduleFinishPip*/, originalBounds, destinationBounds,
|
||||||
|
durationMs);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void resizePip(Rect destinationBounds) {
|
||||||
|
if (Looper.myLooper() != mUpdateHandler.getLooper()) {
|
||||||
|
throw new RuntimeException("Callers should call scheduleResizePip() instead of this "
|
||||||
|
+ "directly");
|
||||||
|
}
|
||||||
|
Objects.requireNonNull(mToken, "Requires valid IWindowContainer");
|
||||||
|
// Could happen when dismissPip
|
||||||
|
if (mToken == null || mLeash == null) {
|
||||||
|
Log.w(TAG, "Abort animation, invalid leash");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
new SurfaceControl.Transaction()
|
||||||
|
.setPosition(mLeash, destinationBounds.left, destinationBounds.top)
|
||||||
|
.setWindowCrop(mLeash, destinationBounds.width(), destinationBounds.height())
|
||||||
|
.apply();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void finishResize(Rect destinationBounds, SurfaceControl.Transaction tx,
|
||||||
|
boolean shouldScheduleFinishPip) {
|
||||||
|
if (Looper.myLooper() != mUpdateHandler.getLooper()) {
|
||||||
|
throw new RuntimeException("Callers should call scheduleResizePip() instead of this "
|
||||||
|
+ "directly");
|
||||||
|
}
|
||||||
mLastReportedBounds.set(destinationBounds);
|
mLastReportedBounds.set(destinationBounds);
|
||||||
try {
|
try {
|
||||||
final WindowContainerTransaction wct = new WindowContainerTransaction();
|
final WindowContainerTransaction wct = new WindowContainerTransaction();
|
||||||
if (shouldScheduleFinishPip) {
|
if (shouldScheduleFinishPip) {
|
||||||
wct.scheduleFinishEnterPip(wc, destinationBounds);
|
wct.scheduleFinishEnterPip(mToken, destinationBounds);
|
||||||
} else {
|
} else {
|
||||||
wct.setBounds(wc, destinationBounds);
|
wct.setBounds(mToken, destinationBounds);
|
||||||
}
|
}
|
||||||
wct.setBoundsChangeTransaction(mTaskInfo.token, tx);
|
wct.setBoundsChangeTransaction(mToken, tx);
|
||||||
mTaskOrganizerController.applyContainerTransaction(wct, null /* ITaskOrganizer */);
|
mTaskOrganizerController.applyContainerTransaction(wct, null /* ITaskOrganizer */);
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
Log.e(TAG, "Failed to apply container transaction", e);
|
Log.e(TAG, "Failed to apply container transaction", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private void animateResizePip(boolean scheduleFinishPip, Rect currentBounds,
|
||||||
* Animates resizing of the pinned stack given the duration.
|
Rect destinationBounds, int durationMs) {
|
||||||
*/
|
if (Looper.myLooper() != mUpdateHandler.getLooper()) {
|
||||||
public void animateResizePip(Rect destinationBounds, int durationMs) {
|
throw new RuntimeException("Callers should call scheduleAnimateResizePip() instead of "
|
||||||
Objects.requireNonNull(mTaskInfo, "Requires valid IWindowContainer");
|
+ "this directly");
|
||||||
animateResizePipInternal(mTaskInfo.token, false, mLastReportedBounds,
|
|
||||||
destinationBounds, durationMs);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void animateResizePipInternal(IWindowContainer wc, boolean scheduleFinishPip,
|
|
||||||
Rect currentBounds, Rect destinationBounds, int durationMs) {
|
|
||||||
try {
|
|
||||||
// Could happen when dismissPip
|
|
||||||
if (wc == null || wc.getLeash() == null) {
|
|
||||||
Log.w(TAG, "Abort animation, invalid leash");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
final SurfaceControl leash = wc.getLeash();
|
|
||||||
|
|
||||||
mMainHandler.post(() -> mPipAnimationController
|
|
||||||
.getAnimator(wc, scheduleFinishPip, currentBounds, destinationBounds)
|
|
||||||
.setPipAnimationCallback(mPipAnimationCallback)
|
|
||||||
.setDuration(durationMs)
|
|
||||||
.start());
|
|
||||||
} catch (RemoteException e) {
|
|
||||||
Log.w(TAG, "Abort animation, invalid window container", e);
|
|
||||||
} catch (Exception e) {
|
|
||||||
Log.e(TAG, "Should not reach here, terrible thing happened", e);
|
|
||||||
}
|
}
|
||||||
|
// Could happen when dismissPip
|
||||||
|
if (mToken == null || mLeash == null) {
|
||||||
|
Log.w(TAG, "Abort animation, invalid leash");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mUpdateHandler.post(() -> mPipAnimationController
|
||||||
|
.getAnimator(mLeash, scheduleFinishPip, currentBounds, destinationBounds)
|
||||||
|
.setPipAnimationCallback(mPipAnimationCallback)
|
||||||
|
.setDuration(durationMs)
|
||||||
|
.start());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private float getAspectRatioOrDefault(@Nullable PictureInPictureParams params) {
|
private float getAspectRatioOrDefault(@Nullable PictureInPictureParams params) {
|
||||||
return params == null
|
return params == null
|
||||||
? mPipBoundsHandler.getDefaultAspectRatio()
|
? mPipBoundsHandler.getDefaultAspectRatio()
|
||||||
|
|||||||
@@ -28,16 +28,11 @@ import android.graphics.Point;
|
|||||||
import android.graphics.PointF;
|
import android.graphics.PointF;
|
||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
import android.os.Debug;
|
import android.os.Debug;
|
||||||
import android.os.Handler;
|
|
||||||
import android.os.Message;
|
|
||||||
import android.os.RemoteException;
|
import android.os.RemoteException;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.Choreographer;
|
|
||||||
|
|
||||||
import androidx.dynamicanimation.animation.SpringForce;
|
import androidx.dynamicanimation.animation.SpringForce;
|
||||||
|
|
||||||
import com.android.internal.graphics.SfVsyncFrameCallbackProvider;
|
|
||||||
import com.android.internal.os.SomeArgs;
|
|
||||||
import com.android.systemui.pip.PipSnapAlgorithm;
|
import com.android.systemui.pip.PipSnapAlgorithm;
|
||||||
import com.android.systemui.pip.PipTaskOrganizer;
|
import com.android.systemui.pip.PipTaskOrganizer;
|
||||||
import com.android.systemui.shared.system.WindowManagerWrapper;
|
import com.android.systemui.shared.system.WindowManagerWrapper;
|
||||||
@@ -47,11 +42,12 @@ import com.android.systemui.util.animation.FloatProperties;
|
|||||||
import com.android.systemui.util.animation.PhysicsAnimator;
|
import com.android.systemui.util.animation.PhysicsAnimator;
|
||||||
|
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A helper to animate and manipulate the PiP.
|
* A helper to animate and manipulate the PiP.
|
||||||
*/
|
*/
|
||||||
public class PipMotionHelper implements Handler.Callback, PipAppOpsListener.Callback,
|
public class PipMotionHelper implements PipAppOpsListener.Callback,
|
||||||
FloatingContentCoordinator.FloatingContent {
|
FloatingContentCoordinator.FloatingContent {
|
||||||
|
|
||||||
private static final String TAG = "PipMotionHelper";
|
private static final String TAG = "PipMotionHelper";
|
||||||
@@ -68,14 +64,9 @@ public class PipMotionHelper implements Handler.Callback, PipAppOpsListener.Call
|
|||||||
// The fraction of the stack height that the user has to drag offscreen to dismiss the PiP
|
// The fraction of the stack height that the user has to drag offscreen to dismiss the PiP
|
||||||
private static final float DISMISS_OFFSCREEN_FRACTION = 0.3f;
|
private static final float DISMISS_OFFSCREEN_FRACTION = 0.3f;
|
||||||
|
|
||||||
private static final int MSG_RESIZE_IMMEDIATE = 1;
|
|
||||||
private static final int MSG_RESIZE_ANIMATE = 2;
|
|
||||||
private static final int MSG_OFFSET_ANIMATE = 3;
|
|
||||||
|
|
||||||
private final Context mContext;
|
private final Context mContext;
|
||||||
private final IActivityTaskManager mActivityTaskManager;
|
private final IActivityTaskManager mActivityTaskManager;
|
||||||
private final PipTaskOrganizer mPipTaskOrganizer;
|
private final PipTaskOrganizer mPipTaskOrganizer;
|
||||||
private final Handler mHandler;
|
|
||||||
|
|
||||||
private PipMenuActivityController mMenuController;
|
private PipMenuActivityController mMenuController;
|
||||||
private PipSnapAlgorithm mSnapAlgorithm;
|
private PipSnapAlgorithm mSnapAlgorithm;
|
||||||
@@ -92,9 +83,6 @@ public class PipMotionHelper implements Handler.Callback, PipAppOpsListener.Call
|
|||||||
/** The region that all of PIP must stay within. */
|
/** The region that all of PIP must stay within. */
|
||||||
private Rect mFloatingAllowedArea = new Rect();
|
private Rect mFloatingAllowedArea = new Rect();
|
||||||
|
|
||||||
private final SfVsyncFrameCallbackProvider mSfVsyncFrameProvider =
|
|
||||||
new SfVsyncFrameCallbackProvider();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bounds that are animated using the physics animator.
|
* Bounds that are animated using the physics animator.
|
||||||
*/
|
*/
|
||||||
@@ -112,16 +100,11 @@ public class PipMotionHelper implements Handler.Callback, PipAppOpsListener.Call
|
|||||||
private PhysicsAnimator<Rect> mAnimatedBoundsPhysicsAnimator = PhysicsAnimator.getInstance(
|
private PhysicsAnimator<Rect> mAnimatedBoundsPhysicsAnimator = PhysicsAnimator.getInstance(
|
||||||
mAnimatedBounds);
|
mAnimatedBounds);
|
||||||
|
|
||||||
/** Callback that re-sizes PIP to the animated bounds. */
|
|
||||||
private final Choreographer.FrameCallback mResizePipVsyncCallback =
|
|
||||||
l -> resizePipUnchecked(mAnimatedBounds);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update listener that posts a vsync frame callback to resize PIP to {@link #mAnimatedBounds}.
|
* Update listener that resizes the PIP to {@link #mAnimatedBounds}.
|
||||||
*/
|
*/
|
||||||
private final PhysicsAnimator.UpdateListener<Rect> mResizePipVsyncUpdateListener =
|
private final PhysicsAnimator.UpdateListener<Rect> mResizePipUpdateListener =
|
||||||
(target, values) ->
|
(target, values) -> resizePipUnchecked(mAnimatedBounds);
|
||||||
mSfVsyncFrameProvider.postFrameCallback(mResizePipVsyncCallback);
|
|
||||||
|
|
||||||
/** FlingConfig instances provided to PhysicsAnimator for fling gestures. */
|
/** FlingConfig instances provided to PhysicsAnimator for fling gestures. */
|
||||||
private PhysicsAnimator.FlingConfig mFlingConfigX;
|
private PhysicsAnimator.FlingConfig mFlingConfigX;
|
||||||
@@ -137,12 +120,13 @@ public class PipMotionHelper implements Handler.Callback, PipAppOpsListener.Call
|
|||||||
new PhysicsAnimator.SpringConfig(
|
new PhysicsAnimator.SpringConfig(
|
||||||
SpringForce.STIFFNESS_LOW, SpringForce.DAMPING_RATIO_LOW_BOUNCY);
|
SpringForce.STIFFNESS_LOW, SpringForce.DAMPING_RATIO_LOW_BOUNCY);
|
||||||
|
|
||||||
|
private final Consumer<Rect> mUpdateBoundsCallback = (toBounds) -> mBounds.set(toBounds);
|
||||||
|
|
||||||
public PipMotionHelper(Context context, IActivityTaskManager activityTaskManager,
|
public PipMotionHelper(Context context, IActivityTaskManager activityTaskManager,
|
||||||
PipTaskOrganizer pipTaskOrganizer, PipMenuActivityController menuController,
|
PipTaskOrganizer pipTaskOrganizer, PipMenuActivityController menuController,
|
||||||
PipSnapAlgorithm snapAlgorithm, FlingAnimationUtils flingAnimationUtils,
|
PipSnapAlgorithm snapAlgorithm, FlingAnimationUtils flingAnimationUtils,
|
||||||
FloatingContentCoordinator floatingContentCoordinator) {
|
FloatingContentCoordinator floatingContentCoordinator) {
|
||||||
mContext = context;
|
mContext = context;
|
||||||
mHandler = new Handler(ForegroundThread.get().getLooper(), this);
|
|
||||||
mActivityTaskManager = activityTaskManager;
|
mActivityTaskManager = activityTaskManager;
|
||||||
mPipTaskOrganizer = pipTaskOrganizer;
|
mPipTaskOrganizer = pipTaskOrganizer;
|
||||||
mMenuController = menuController;
|
mMenuController = menuController;
|
||||||
@@ -234,7 +218,7 @@ public class PipMotionHelper implements Handler.Callback, PipAppOpsListener.Call
|
|||||||
}
|
}
|
||||||
cancelAnimations();
|
cancelAnimations();
|
||||||
mMenuController.hideMenuWithoutResize();
|
mMenuController.hideMenuWithoutResize();
|
||||||
mHandler.post(() -> {
|
mPipTaskOrganizer.getUpdateHandler().post(() -> {
|
||||||
try {
|
try {
|
||||||
mActivityTaskManager.dismissPip(!skipAnimation, EXPAND_STACK_TO_FULLSCREEN_DURATION);
|
mActivityTaskManager.dismissPip(!skipAnimation, EXPAND_STACK_TO_FULLSCREEN_DURATION);
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
@@ -253,7 +237,7 @@ public class PipMotionHelper implements Handler.Callback, PipAppOpsListener.Call
|
|||||||
}
|
}
|
||||||
cancelAnimations();
|
cancelAnimations();
|
||||||
mMenuController.hideMenuWithoutResize();
|
mMenuController.hideMenuWithoutResize();
|
||||||
mHandler.post(() -> {
|
mPipTaskOrganizer.getUpdateHandler().post(() -> {
|
||||||
try {
|
try {
|
||||||
mActivityTaskManager.removeStacksInWindowingModes(
|
mActivityTaskManager.removeStacksInWindowingModes(
|
||||||
new int[]{ WINDOWING_MODE_PINNED });
|
new int[]{ WINDOWING_MODE_PINNED });
|
||||||
@@ -406,17 +390,13 @@ public class PipMotionHelper implements Handler.Callback, PipAppOpsListener.Call
|
|||||||
* Animates the PiP to offset it from the IME or shelf.
|
* Animates the PiP to offset it from the IME or shelf.
|
||||||
*/
|
*/
|
||||||
void animateToOffset(Rect originalBounds, int offset) {
|
void animateToOffset(Rect originalBounds, int offset) {
|
||||||
|
if (DEBUG) {
|
||||||
|
Log.d(TAG, "animateToOffset: originalBounds=" + originalBounds + " offset=" + offset
|
||||||
|
+ " callers=\n" + Debug.getCallers(5, " "));
|
||||||
|
}
|
||||||
cancelAnimations();
|
cancelAnimations();
|
||||||
adjustAndAnimatePipOffset(originalBounds, offset, SHIFT_DURATION);
|
mPipTaskOrganizer.scheduleOffsetPip(originalBounds, offset, SHIFT_DURATION,
|
||||||
}
|
mUpdateBoundsCallback);
|
||||||
|
|
||||||
private void adjustAndAnimatePipOffset(Rect originalBounds, int offset, int duration) {
|
|
||||||
SomeArgs args = SomeArgs.obtain();
|
|
||||||
args.arg1 = originalBounds;
|
|
||||||
// offset would be zero if triggered from screen rotation.
|
|
||||||
args.argi1 = offset;
|
|
||||||
args.argi2 = duration;
|
|
||||||
mHandler.sendMessage(mHandler.obtainMessage(MSG_OFFSET_ANIMATE, args));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -437,8 +417,7 @@ public class PipMotionHelper implements Handler.Callback, PipAppOpsListener.Call
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Starts the physics animator which will update the animated PIP bounds using physics
|
* Starts the physics animator which will update the animated PIP bounds using physics
|
||||||
* animations, as well as the TimeAnimator which will apply those bounds to PIP at intervals
|
* animations, as well as the TimeAnimator which will apply those bounds to PIP.
|
||||||
* synchronized with the SurfaceFlinger vsync frame provider.
|
|
||||||
*
|
*
|
||||||
* This will also add end actions to the bounds animator that cancel the TimeAnimator and update
|
* This will also add end actions to the bounds animator that cancel the TimeAnimator and update
|
||||||
* the 'real' bounds to equal the final animated bounds.
|
* the 'real' bounds to equal the final animated bounds.
|
||||||
@@ -448,7 +427,7 @@ public class PipMotionHelper implements Handler.Callback, PipAppOpsListener.Call
|
|||||||
|
|
||||||
mAnimatedBoundsPhysicsAnimator
|
mAnimatedBoundsPhysicsAnimator
|
||||||
.withEndActions(() -> mPipTaskOrganizer.onMotionMovementEnd(mAnimatedBounds))
|
.withEndActions(() -> mPipTaskOrganizer.onMotionMovementEnd(mAnimatedBounds))
|
||||||
.addUpdateListener(mResizePipVsyncUpdateListener)
|
.addUpdateListener(mResizePipUpdateListener)
|
||||||
.start();
|
.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -471,9 +450,7 @@ public class PipMotionHelper implements Handler.Callback, PipAppOpsListener.Call
|
|||||||
+ " callers=\n" + Debug.getCallers(5, " "));
|
+ " callers=\n" + Debug.getCallers(5, " "));
|
||||||
}
|
}
|
||||||
if (!toBounds.equals(mBounds)) {
|
if (!toBounds.equals(mBounds)) {
|
||||||
SomeArgs args = SomeArgs.obtain();
|
mPipTaskOrganizer.scheduleResizePip(toBounds, mUpdateBoundsCallback);
|
||||||
args.arg1 = toBounds;
|
|
||||||
mHandler.sendMessage(mHandler.obtainMessage(MSG_RESIZE_IMMEDIATE, args));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -486,10 +463,7 @@ public class PipMotionHelper implements Handler.Callback, PipAppOpsListener.Call
|
|||||||
+ " duration=" + duration + " callers=\n" + Debug.getCallers(5, " "));
|
+ " duration=" + duration + " callers=\n" + Debug.getCallers(5, " "));
|
||||||
}
|
}
|
||||||
if (!toBounds.equals(mBounds)) {
|
if (!toBounds.equals(mBounds)) {
|
||||||
SomeArgs args = SomeArgs.obtain();
|
mPipTaskOrganizer.scheduleAnimateResizePip(toBounds, duration, mUpdateBoundsCallback);
|
||||||
args.arg1 = toBounds;
|
|
||||||
args.argi1 = duration;
|
|
||||||
mHandler.sendMessage(mHandler.obtainMessage(MSG_RESIZE_ANIMATE, args));
|
|
||||||
setAnimatingToBounds(toBounds);
|
setAnimatingToBounds(toBounds);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -538,70 +512,6 @@ public class PipMotionHelper implements Handler.Callback, PipAppOpsListener.Call
|
|||||||
return dismissArea.contains(endpoint.x, endpoint.y);
|
return dismissArea.contains(endpoint.x, endpoint.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Handles messages to be processed on the background thread.
|
|
||||||
*/
|
|
||||||
public boolean handleMessage(Message msg) {
|
|
||||||
switch (msg.what) {
|
|
||||||
case MSG_RESIZE_IMMEDIATE: {
|
|
||||||
SomeArgs args = (SomeArgs) msg.obj;
|
|
||||||
Rect toBounds = (Rect) args.arg1;
|
|
||||||
mPipTaskOrganizer.resizePip(toBounds);
|
|
||||||
mBounds.set(toBounds);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
case MSG_RESIZE_ANIMATE: {
|
|
||||||
SomeArgs args = (SomeArgs) msg.obj;
|
|
||||||
Rect toBounds = (Rect) args.arg1;
|
|
||||||
int duration = args.argi1;
|
|
||||||
try {
|
|
||||||
StackInfo stackInfo = mActivityTaskManager.getStackInfo(
|
|
||||||
WINDOWING_MODE_PINNED, ACTIVITY_TYPE_UNDEFINED);
|
|
||||||
if (stackInfo == null) {
|
|
||||||
// In the case where we've already re-expanded or dismissed the PiP, then
|
|
||||||
// just skip the resize
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
mPipTaskOrganizer.animateResizePip(toBounds, duration);
|
|
||||||
mBounds.set(toBounds);
|
|
||||||
} catch (RemoteException e) {
|
|
||||||
Log.e(TAG, "Could not animate resize pinned stack to bounds: " + toBounds, e);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
case MSG_OFFSET_ANIMATE: {
|
|
||||||
SomeArgs args = (SomeArgs) msg.obj;
|
|
||||||
Rect originalBounds = (Rect) args.arg1;
|
|
||||||
final int offset = args.argi1;
|
|
||||||
final int duration = args.argi2;
|
|
||||||
try {
|
|
||||||
StackInfo stackInfo = mActivityTaskManager.getStackInfo(
|
|
||||||
WINDOWING_MODE_PINNED, ACTIVITY_TYPE_UNDEFINED);
|
|
||||||
if (stackInfo == null) {
|
|
||||||
// In the case where we've already re-expanded or dismissed the PiP, then
|
|
||||||
// just skip the resize
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
mPipTaskOrganizer.offsetPinnedStack(originalBounds,
|
|
||||||
0 /* xOffset */, offset, duration);
|
|
||||||
Rect toBounds = new Rect(originalBounds);
|
|
||||||
toBounds.offset(0, offset);
|
|
||||||
mBounds.set(toBounds);
|
|
||||||
} catch (RemoteException e) {
|
|
||||||
Log.e(TAG, "Could not animate offset pinned stack with offset: " + offset, e);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void dump(PrintWriter pw, String prefix) {
|
public void dump(PrintWriter pw, String prefix) {
|
||||||
final String innerPrefix = prefix + " ";
|
final String innerPrefix = prefix + " ";
|
||||||
pw.println(prefix + TAG);
|
pw.println(prefix + TAG);
|
||||||
|
|||||||
@@ -21,33 +21,38 @@ import android.os.HandlerThread;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Similar to {@link com.android.internal.os.BackgroundThread}, this is a shared singleton
|
* Similar to {@link com.android.internal.os.BackgroundThread}, this is a shared singleton
|
||||||
* foreground thread for each process.
|
* foreground thread for each process for updating PIP.
|
||||||
*/
|
*/
|
||||||
public final class ForegroundThread extends HandlerThread {
|
public final class PipUpdateThread extends HandlerThread {
|
||||||
private static ForegroundThread sInstance;
|
private static PipUpdateThread sInstance;
|
||||||
private static Handler sHandler;
|
private static Handler sHandler;
|
||||||
|
|
||||||
private ForegroundThread() {
|
private PipUpdateThread() {
|
||||||
super("recents.fg");
|
super("pip");
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void ensureThreadLocked() {
|
private static void ensureThreadLocked() {
|
||||||
if (sInstance == null) {
|
if (sInstance == null) {
|
||||||
sInstance = new ForegroundThread();
|
sInstance = new PipUpdateThread();
|
||||||
sInstance.start();
|
sInstance.start();
|
||||||
sHandler = new Handler(sInstance.getLooper());
|
sHandler = new Handler(sInstance.getLooper());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ForegroundThread get() {
|
/**
|
||||||
synchronized (ForegroundThread.class) {
|
* @return the static update thread instance
|
||||||
|
*/
|
||||||
|
public static PipUpdateThread get() {
|
||||||
|
synchronized (PipUpdateThread.class) {
|
||||||
ensureThreadLocked();
|
ensureThreadLocked();
|
||||||
return sInstance;
|
return sInstance;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* @return the static update thread handler instance
|
||||||
|
*/
|
||||||
public static Handler getHandler() {
|
public static Handler getHandler() {
|
||||||
synchronized (ForegroundThread.class) {
|
synchronized (PipUpdateThread.class) {
|
||||||
ensureThreadLocked();
|
ensureThreadLocked();
|
||||||
return sHandler;
|
return sHandler;
|
||||||
}
|
}
|
||||||
@@ -20,6 +20,8 @@ import static android.app.ActivityTaskManager.INVALID_STACK_ID;
|
|||||||
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
|
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
|
||||||
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
|
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
|
||||||
|
|
||||||
|
import static com.android.systemui.pip.PipAnimationController.DURATION_DEFAULT_MS;
|
||||||
|
|
||||||
import android.app.ActivityManager.RunningTaskInfo;
|
import android.app.ActivityManager.RunningTaskInfo;
|
||||||
import android.app.ActivityManager.StackInfo;
|
import android.app.ActivityManager.StackInfo;
|
||||||
import android.app.ActivityTaskManager;
|
import android.app.ActivityTaskManager;
|
||||||
@@ -50,7 +52,6 @@ import com.android.systemui.R;
|
|||||||
import com.android.systemui.UiOffloadThread;
|
import com.android.systemui.UiOffloadThread;
|
||||||
import com.android.systemui.broadcast.BroadcastDispatcher;
|
import com.android.systemui.broadcast.BroadcastDispatcher;
|
||||||
import com.android.systemui.pip.BasePipManager;
|
import com.android.systemui.pip.BasePipManager;
|
||||||
import com.android.systemui.pip.PipAnimationController;
|
|
||||||
import com.android.systemui.pip.PipBoundsHandler;
|
import com.android.systemui.pip.PipBoundsHandler;
|
||||||
import com.android.systemui.pip.PipTaskOrganizer;
|
import com.android.systemui.pip.PipTaskOrganizer;
|
||||||
import com.android.systemui.shared.system.ActivityManagerWrapper;
|
import com.android.systemui.shared.system.ActivityManagerWrapper;
|
||||||
@@ -233,6 +234,7 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio
|
|||||||
if (mInitialized) {
|
if (mInitialized) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
mInitialized = true;
|
mInitialized = true;
|
||||||
mContext = context;
|
mContext = context;
|
||||||
mPipBoundsHandler = pipBoundsHandler;
|
mPipBoundsHandler = pipBoundsHandler;
|
||||||
@@ -434,8 +436,7 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio
|
|||||||
mCurrentPipBounds = mPipBounds;
|
mCurrentPipBounds = mPipBounds;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
mPipTaskOrganizer.animateResizePip(mCurrentPipBounds,
|
mPipTaskOrganizer.scheduleAnimateResizePip(mCurrentPipBounds, DURATION_DEFAULT_MS, null);
|
||||||
PipAnimationController.DURATION_DEFAULT_MS);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -26,7 +26,6 @@ import static org.mockito.Mockito.verify;
|
|||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
import android.testing.AndroidTestingRunner;
|
import android.testing.AndroidTestingRunner;
|
||||||
import android.testing.TestableLooper;
|
import android.testing.TestableLooper;
|
||||||
import android.view.IWindowContainer;
|
|
||||||
import android.view.SurfaceControl;
|
import android.view.SurfaceControl;
|
||||||
|
|
||||||
import androidx.test.filters.SmallTest;
|
import androidx.test.filters.SmallTest;
|
||||||
@@ -51,7 +50,7 @@ public class PipAnimationControllerTest extends SysuiTestCase {
|
|||||||
private PipAnimationController mPipAnimationController;
|
private PipAnimationController mPipAnimationController;
|
||||||
|
|
||||||
@Mock
|
@Mock
|
||||||
private IWindowContainer mWindowContainer;
|
private SurfaceControl mLeash;
|
||||||
|
|
||||||
@Mock
|
@Mock
|
||||||
private PipAnimationController.PipAnimationCallback mPipAnimationCallback;
|
private PipAnimationController.PipAnimationCallback mPipAnimationCallback;
|
||||||
@@ -65,8 +64,7 @@ public class PipAnimationControllerTest extends SysuiTestCase {
|
|||||||
@Test
|
@Test
|
||||||
public void getAnimator_withAlpha_returnFloatAnimator() {
|
public void getAnimator_withAlpha_returnFloatAnimator() {
|
||||||
final PipAnimationController.PipTransitionAnimator animator = mPipAnimationController
|
final PipAnimationController.PipTransitionAnimator animator = mPipAnimationController
|
||||||
.getAnimator(mWindowContainer, true /* scheduleFinishPip */,
|
.getAnimator(mLeash, true /* scheduleFinishPip */, new Rect(), 0f, 1f);
|
||||||
new Rect(), 0f, 1f);
|
|
||||||
|
|
||||||
assertEquals("Expect ANIM_TYPE_ALPHA animation",
|
assertEquals("Expect ANIM_TYPE_ALPHA animation",
|
||||||
animator.getAnimationType(), PipAnimationController.ANIM_TYPE_ALPHA);
|
animator.getAnimationType(), PipAnimationController.ANIM_TYPE_ALPHA);
|
||||||
@@ -75,8 +73,7 @@ public class PipAnimationControllerTest extends SysuiTestCase {
|
|||||||
@Test
|
@Test
|
||||||
public void getAnimator_withBounds_returnBoundsAnimator() {
|
public void getAnimator_withBounds_returnBoundsAnimator() {
|
||||||
final PipAnimationController.PipTransitionAnimator animator = mPipAnimationController
|
final PipAnimationController.PipTransitionAnimator animator = mPipAnimationController
|
||||||
.getAnimator(mWindowContainer, true /* scheduleFinishPip */,
|
.getAnimator(mLeash, true /* scheduleFinishPip */, new Rect(), new Rect());
|
||||||
new Rect(), new Rect());
|
|
||||||
|
|
||||||
assertEquals("Expect ANIM_TYPE_BOUNDS animation",
|
assertEquals("Expect ANIM_TYPE_BOUNDS animation",
|
||||||
animator.getAnimationType(), PipAnimationController.ANIM_TYPE_BOUNDS);
|
animator.getAnimationType(), PipAnimationController.ANIM_TYPE_BOUNDS);
|
||||||
@@ -88,14 +85,12 @@ public class PipAnimationControllerTest extends SysuiTestCase {
|
|||||||
final Rect endValue1 = new Rect(100, 100, 200, 200);
|
final Rect endValue1 = new Rect(100, 100, 200, 200);
|
||||||
final Rect endValue2 = new Rect(200, 200, 300, 300);
|
final Rect endValue2 = new Rect(200, 200, 300, 300);
|
||||||
final PipAnimationController.PipTransitionAnimator oldAnimator = mPipAnimationController
|
final PipAnimationController.PipTransitionAnimator oldAnimator = mPipAnimationController
|
||||||
.getAnimator(mWindowContainer, true /* scheduleFinishPip */,
|
.getAnimator(mLeash, true /* scheduleFinishPip */, startValue, endValue1);
|
||||||
startValue, endValue1);
|
|
||||||
oldAnimator.setSurfaceControlTransactionFactory(DummySurfaceControlTx::new);
|
oldAnimator.setSurfaceControlTransactionFactory(DummySurfaceControlTx::new);
|
||||||
oldAnimator.start();
|
oldAnimator.start();
|
||||||
|
|
||||||
final PipAnimationController.PipTransitionAnimator newAnimator = mPipAnimationController
|
final PipAnimationController.PipTransitionAnimator newAnimator = mPipAnimationController
|
||||||
.getAnimator(mWindowContainer, true /* scheduleFinishPip */,
|
.getAnimator(mLeash, true /* scheduleFinishPip */, startValue, endValue2);
|
||||||
startValue, endValue2);
|
|
||||||
|
|
||||||
assertEquals("getAnimator with same type returns same animator",
|
assertEquals("getAnimator with same type returns same animator",
|
||||||
oldAnimator, newAnimator);
|
oldAnimator, newAnimator);
|
||||||
@@ -106,13 +101,11 @@ public class PipAnimationControllerTest extends SysuiTestCase {
|
|||||||
@Test
|
@Test
|
||||||
public void getAnimator_scheduleFinishPip() {
|
public void getAnimator_scheduleFinishPip() {
|
||||||
PipAnimationController.PipTransitionAnimator animator = mPipAnimationController
|
PipAnimationController.PipTransitionAnimator animator = mPipAnimationController
|
||||||
.getAnimator(mWindowContainer, true /* scheduleFinishPip */,
|
.getAnimator(mLeash, true /* scheduleFinishPip */, new Rect(), 0f, 1f);
|
||||||
new Rect(), 0f, 1f);
|
|
||||||
assertTrue("scheduleFinishPip is true", animator.shouldScheduleFinishPip());
|
assertTrue("scheduleFinishPip is true", animator.shouldScheduleFinishPip());
|
||||||
|
|
||||||
animator = mPipAnimationController
|
animator = mPipAnimationController
|
||||||
.getAnimator(mWindowContainer, false /* scheduleFinishPip */,
|
.getAnimator(mLeash, false /* scheduleFinishPip */, new Rect(), 0f, 1f);
|
||||||
new Rect(), 0f, 1f);
|
|
||||||
assertFalse("scheduleFinishPip is false", animator.shouldScheduleFinishPip());
|
assertFalse("scheduleFinishPip is false", animator.shouldScheduleFinishPip());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -122,8 +115,7 @@ public class PipAnimationControllerTest extends SysuiTestCase {
|
|||||||
final Rect endValue1 = new Rect(100, 100, 200, 200);
|
final Rect endValue1 = new Rect(100, 100, 200, 200);
|
||||||
final Rect endValue2 = new Rect(200, 200, 300, 300);
|
final Rect endValue2 = new Rect(200, 200, 300, 300);
|
||||||
final PipAnimationController.PipTransitionAnimator animator = mPipAnimationController
|
final PipAnimationController.PipTransitionAnimator animator = mPipAnimationController
|
||||||
.getAnimator(mWindowContainer, true /* scheduleFinishPip */,
|
.getAnimator(mLeash, true /* scheduleFinishPip */, startValue, endValue1);
|
||||||
startValue, endValue1);
|
|
||||||
|
|
||||||
animator.updateEndValue(endValue2);
|
animator.updateEndValue(endValue2);
|
||||||
|
|
||||||
@@ -135,24 +127,23 @@ public class PipAnimationControllerTest extends SysuiTestCase {
|
|||||||
final Rect startValue = new Rect(0, 0, 100, 100);
|
final Rect startValue = new Rect(0, 0, 100, 100);
|
||||||
final Rect endValue = new Rect(100, 100, 200, 200);
|
final Rect endValue = new Rect(100, 100, 200, 200);
|
||||||
final PipAnimationController.PipTransitionAnimator animator = mPipAnimationController
|
final PipAnimationController.PipTransitionAnimator animator = mPipAnimationController
|
||||||
.getAnimator(mWindowContainer, true /* scheduleFinishPip */,
|
.getAnimator(mLeash, true /* scheduleFinishPip */, startValue, endValue);
|
||||||
startValue, endValue);
|
|
||||||
animator.setSurfaceControlTransactionFactory(DummySurfaceControlTx::new);
|
animator.setSurfaceControlTransactionFactory(DummySurfaceControlTx::new);
|
||||||
|
|
||||||
animator.setPipAnimationCallback(mPipAnimationCallback);
|
animator.setPipAnimationCallback(mPipAnimationCallback);
|
||||||
|
|
||||||
// onAnimationStart triggers onPipAnimationStart
|
// onAnimationStart triggers onPipAnimationStart
|
||||||
animator.onAnimationStart(animator);
|
animator.onAnimationStart(animator);
|
||||||
verify(mPipAnimationCallback).onPipAnimationStart(mWindowContainer, animator);
|
verify(mPipAnimationCallback).onPipAnimationStart(animator);
|
||||||
|
|
||||||
// onAnimationCancel triggers onPipAnimationCancel
|
// onAnimationCancel triggers onPipAnimationCancel
|
||||||
animator.onAnimationCancel(animator);
|
animator.onAnimationCancel(animator);
|
||||||
verify(mPipAnimationCallback).onPipAnimationCancel(mWindowContainer, animator);
|
verify(mPipAnimationCallback).onPipAnimationCancel(animator);
|
||||||
|
|
||||||
// onAnimationEnd triggers onPipAnimationEnd
|
// onAnimationEnd triggers onPipAnimationEnd
|
||||||
animator.onAnimationEnd(animator);
|
animator.onAnimationEnd(animator);
|
||||||
verify(mPipAnimationCallback).onPipAnimationEnd(eq(mWindowContainer),
|
verify(mPipAnimationCallback).onPipAnimationEnd(any(SurfaceControl.Transaction.class),
|
||||||
any(SurfaceControl.Transaction.class), eq(animator));
|
eq(animator));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user