Merge "Ensure that task org updates all happen off the main thread" into rvc-dev am: e85727200d

Change-Id: Id5d7458b564b50c1afe0bd67f18fe380819dd80e
This commit is contained in:
Automerger Merge Worker
2020-03-06 17:00:14 +00:00
7 changed files with 298 additions and 281 deletions

View File

@@ -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

View File

@@ -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();

View File

@@ -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()

View File

@@ -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);

View File

@@ -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;
} }

View File

@@ -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);
} }
/** /**

View File

@@ -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));
} }
/** /**