diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml index 217abbe3778a4..c8b0d99a329fc 100644 --- a/packages/SystemUI/res/values/config.xml +++ b/packages/SystemUI/res/values/config.xml @@ -477,6 +477,9 @@ true + + false + com.android.systemui diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipAnimationController.java b/packages/SystemUI/src/com/android/systemui/pip/PipAnimationController.java index 41bace74bd46c..4bfcf2229e3e1 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/PipAnimationController.java +++ b/packages/SystemUI/src/com/android/systemui/pip/PipAnimationController.java @@ -30,6 +30,8 @@ import com.android.internal.annotations.VisibleForTesting; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import javax.inject.Inject; + /** * Controller class of PiP animations (both from and to PiP mode). */ @@ -62,12 +64,15 @@ public class PipAnimationController { @interface TransitionDirection {} private final Interpolator mFastOutSlowInInterpolator; + private final PipSurfaceTransactionHelper mSurfaceTransactionHelper; private PipTransitionAnimator mCurrentAnimator; - PipAnimationController(Context context) { + @Inject + PipAnimationController(Context context, PipSurfaceTransactionHelper helper) { mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(context, com.android.internal.R.interpolator.fast_out_slow_in); + mSurfaceTransactionHelper = helper; } @SuppressWarnings("unchecked") @@ -110,6 +115,7 @@ public class PipAnimationController { } private PipTransitionAnimator setupPipTransitionAnimator(PipTransitionAnimator animator) { + animator.setSurfaceTransactionHelper(mSurfaceTransactionHelper); animator.setInterpolator(mFastOutSlowInInterpolator); animator.setFloatValues(FRACTION_START, FRACTION_END); return animator; @@ -151,9 +157,10 @@ public class PipAnimationController { private T mEndValue; private T mCurrentValue; private PipAnimationCallback mPipAnimationCallback; - private SurfaceControlTransactionFactory mSurfaceControlTransactionFactory; + private PipSurfaceTransactionHelper.SurfaceControlTransactionFactory + mSurfaceControlTransactionFactory; + private PipSurfaceTransactionHelper mSurfaceTransactionHelper; private @TransitionDirection int mTransitionDirection; - private int mCornerRadius; private PipTransitionAnimator(SurfaceControl leash, @AnimationType int animationType, Rect destinationBounds, T startValue, T endValue) { @@ -242,15 +249,6 @@ public class PipAnimationController { mCurrentValue = value; } - int getCornerRadius() { - return mCornerRadius; - } - - PipTransitionAnimator setCornerRadius(int cornerRadius) { - mCornerRadius = cornerRadius; - return this; - } - boolean shouldApplyCornerRadius() { return mTransitionDirection != TRANSITION_DIRECTION_TO_FULLSCREEN; } @@ -273,10 +271,19 @@ public class PipAnimationController { } @VisibleForTesting - void setSurfaceControlTransactionFactory(SurfaceControlTransactionFactory factory) { + void setSurfaceControlTransactionFactory( + PipSurfaceTransactionHelper.SurfaceControlTransactionFactory factory) { mSurfaceControlTransactionFactory = factory; } + PipSurfaceTransactionHelper getSurfaceTransactionHelper() { + return mSurfaceTransactionHelper; + } + + void setSurfaceTransactionHelper(PipSurfaceTransactionHelper helper) { + mSurfaceTransactionHelper = helper; + } + abstract void applySurfaceControlTransaction(SurfaceControl leash, SurfaceControl.Transaction tx, float fraction); @@ -289,14 +296,11 @@ public class PipAnimationController { SurfaceControl.Transaction tx, float fraction) { final float alpha = getStartValue() * (1 - fraction) + getEndValue() * fraction; setCurrentValue(alpha); - tx.setAlpha(leash, alpha); + getSurfaceTransactionHelper().alpha(tx, leash, alpha); if (Float.compare(fraction, FRACTION_START) == 0) { - // Ensure the start condition - final Rect bounds = getDestinationBounds(); - tx.setPosition(leash, bounds.left, bounds.top) - .setWindowCrop(leash, bounds.width(), bounds.height()); - tx.setCornerRadius(leash, - shouldApplyCornerRadius() ? getCornerRadius() : 0); + getSurfaceTransactionHelper() + .crop(tx, leash, getDestinationBounds()) + .round(tx, leash, shouldApplyCornerRadius()); } tx.apply(); } @@ -325,21 +329,16 @@ public class PipAnimationController { getCastedFractionValue(start.right, end.right, fraction), getCastedFractionValue(start.bottom, end.bottom, fraction)); setCurrentValue(mTmpRect); - tx.setPosition(leash, mTmpRect.left, mTmpRect.top) - .setWindowCrop(leash, mTmpRect.width(), mTmpRect.height()); + getSurfaceTransactionHelper().crop(tx, leash, mTmpRect); if (Float.compare(fraction, FRACTION_START) == 0) { // Ensure the start condition - tx.setAlpha(leash, 1f); - tx.setCornerRadius(leash, - shouldApplyCornerRadius() ? getCornerRadius() : 0); + getSurfaceTransactionHelper() + .alpha(tx, leash, 1f) + .round(tx, leash, shouldApplyCornerRadius()); } tx.apply(); } }; } } - - interface SurfaceControlTransactionFactory { - SurfaceControl.Transaction getTransaction(); - } } diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipSurfaceTransactionHelper.java b/packages/SystemUI/src/com/android/systemui/pip/PipSurfaceTransactionHelper.java new file mode 100644 index 0000000000000..21f9301fe7942 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/pip/PipSurfaceTransactionHelper.java @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.pip; + +import android.content.Context; +import android.content.res.Resources; +import android.graphics.Rect; +import android.view.SurfaceControl; + +import com.android.systemui.R; + +import javax.inject.Inject; +import javax.inject.Singleton; + +/** + * Abstracts the common operations on {@link SurfaceControl.Transaction} for PiP transition. + */ +@Singleton +public class PipSurfaceTransactionHelper { + + private final boolean mEnableCornerRadius; + private final int mCornerRadius; + + @Inject + public PipSurfaceTransactionHelper(Context context) { + final Resources res = context.getResources(); + mEnableCornerRadius = res.getBoolean(R.bool.config_pipEnableRoundCorner); + mCornerRadius = res.getDimensionPixelSize(R.dimen.pip_corner_radius); + } + + /** + * Operates the alpha on a given transaction and leash + * @return same {@link PipSurfaceTransactionHelper} instance for method chaining + */ + PipSurfaceTransactionHelper alpha(SurfaceControl.Transaction tx, SurfaceControl leash, + float alpha) { + tx.setAlpha(leash, alpha); + return this; + } + + /** + * Operates the crop (and position) on a given transaction and leash + * @return same {@link PipSurfaceTransactionHelper} instance for method chaining + */ + PipSurfaceTransactionHelper crop(SurfaceControl.Transaction tx, SurfaceControl leash, + Rect destinationBounds) { + tx.setWindowCrop(leash, destinationBounds.width(), destinationBounds.height()) + .setPosition(leash, destinationBounds.left, destinationBounds.top); + return this; + } + + /** + * Operates the round corner radius on a given transaction and leash + * @return same {@link PipSurfaceTransactionHelper} instance for method chaining + */ + PipSurfaceTransactionHelper round(SurfaceControl.Transaction tx, SurfaceControl leash, + boolean applyCornerRadius) { + if (mEnableCornerRadius) { + tx.setCornerRadius(leash, applyCornerRadius ? mCornerRadius : 0); + } + return this; + } + + interface SurfaceControlTransactionFactory { + SurfaceControl.Transaction getTransaction(); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java b/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java index 90b657077b0d9..4a4a638fa2b19 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java +++ b/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java @@ -32,7 +32,6 @@ import android.app.PictureInPictureParams; import android.content.Context; import android.graphics.Rect; import android.os.Handler; -import android.os.IBinder; import android.os.Looper; import android.os.RemoteException; import android.util.Log; @@ -46,9 +45,7 @@ import com.android.systemui.R; import com.android.systemui.pip.phone.PipUpdateThread; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; -import java.util.Map; import java.util.Objects; import java.util.function.Consumer; @@ -78,9 +75,8 @@ public class PipTaskOrganizer extends ITaskOrganizer.Stub { private final PipAnimationController mPipAnimationController; private final List mPipTransitionCallbacks = new ArrayList<>(); private final Rect mLastReportedBounds = new Rect(); - private final int mCornerRadius; - private final Map mBoundsToRestore = new HashMap<>(); private final int mEnterExitAnimationDuration; + private final PipSurfaceTransactionHelper mSurfaceTransactionHelper; // These callbacks are called on the update thread private final PipAnimationController.PipAnimationCallback mPipAnimationCallback = @@ -172,16 +168,20 @@ public class PipTaskOrganizer extends ITaskOrganizer.Stub { private SurfaceControl mLeash; private boolean mInPip; private @PipAnimationController.AnimationType int mOneShotAnimationType = ANIM_TYPE_BOUNDS; + private PipSurfaceTransactionHelper.SurfaceControlTransactionFactory + mSurfaceControlTransactionFactory; - public PipTaskOrganizer(Context context, @NonNull PipBoundsHandler boundsHandler) { + public PipTaskOrganizer(Context context, @NonNull PipBoundsHandler boundsHandler, + @NonNull PipSurfaceTransactionHelper surfaceTransactionHelper) { mMainHandler = new Handler(Looper.getMainLooper()); mUpdateHandler = new Handler(PipUpdateThread.get().getLooper(), mUpdateCallbacks); mTaskOrganizerController = ActivityTaskManager.getTaskOrganizerController(); mPipBoundsHandler = boundsHandler; - mPipAnimationController = new PipAnimationController(context); - mCornerRadius = context.getResources().getDimensionPixelSize(R.dimen.pip_corner_radius); mEnterExitAnimationDuration = context.getResources() .getInteger(R.integer.config_pipResizeAnimationDuration); + mSurfaceTransactionHelper = surfaceTransactionHelper; + mPipAnimationController = new PipAnimationController(context, surfaceTransactionHelper); + mSurfaceControlTransactionFactory = SurfaceControl.Transaction::new; } public Handler getUpdateHandler() { @@ -234,7 +234,6 @@ public class PipTaskOrganizer extends ITaskOrganizer.Stub { throw new RuntimeException("Unable to get leash", e); } final Rect currentBounds = mTaskInfo.configuration.windowConfiguration.getBounds(); - mBoundsToRestore.put(mToken.asBinder(), currentBounds); if (mOneShotAnimationType == ANIM_TYPE_BOUNDS) { scheduleAnimateResizePip(currentBounds, destinationBounds, TRANSITION_DIRECTION_TO_PIP, mEnterExitAnimationDuration, null); @@ -242,7 +241,6 @@ public class PipTaskOrganizer extends ITaskOrganizer.Stub { mUpdateHandler.post(() -> mPipAnimationController .getAnimator(mLeash, destinationBounds, 0f, 1f) .setTransitionDirection(TRANSITION_DIRECTION_TO_PIP) - .setCornerRadius(mCornerRadius) .setPipAnimationCallback(mPipAnimationCallback) .setDuration(mEnterExitAnimationDuration) .start()); @@ -260,8 +258,8 @@ public class PipTaskOrganizer extends ITaskOrganizer.Stub { Log.wtf(TAG, "Unrecognized token: " + token); return; } - final Rect boundsToRestore = mBoundsToRestore.remove(mToken.asBinder()); - scheduleAnimateResizePip(mLastReportedBounds, boundsToRestore, + scheduleAnimateResizePip(mLastReportedBounds, + info.configuration.windowConfiguration.getBounds(), TRANSITION_DIRECTION_TO_FULLSCREEN, mEnterExitAnimationDuration, null); mInPip = false; } @@ -307,7 +305,6 @@ public class PipTaskOrganizer extends ITaskOrganizer.Stub { private void scheduleAnimateResizePip(Rect currentBounds, Rect destinationBounds, @PipAnimationController.TransitionDirection int direction, int durationMs, Consumer updateBoundsCallback) { - Objects.requireNonNull(mToken, "Requires valid IWindowContainer"); if (!mInPip) { // Ignore animation when we are no longer in PIP return; @@ -326,7 +323,6 @@ public class PipTaskOrganizer extends ITaskOrganizer.Stub { * {@link WindowContainerTransaction} until {@link #scheduleFinishResizePip} is called. */ public void scheduleResizePip(Rect toBounds, Consumer updateBoundsCallback) { - Objects.requireNonNull(mToken, "Requires valid IWindowContainer"); SomeArgs args = SomeArgs.obtain(); args.arg1 = updateBoundsCallback; args.arg2 = toBounds; @@ -334,22 +330,20 @@ public class PipTaskOrganizer extends ITaskOrganizer.Stub { } /** - * Finish a intermediate resize operation. This is expected to be called after + * Finish an intermediate resize operation. This is expected to be called after * {@link #scheduleResizePip}. */ public void scheduleFinishResizePip(Rect destinationBounds) { - Objects.requireNonNull(mToken, "Requires valid IWindowContainer"); - SurfaceControl.Transaction tx = new SurfaceControl.Transaction() - .setPosition(mLeash, destinationBounds.left, destinationBounds.top) - .setWindowCrop(mLeash, destinationBounds.width(), destinationBounds.height()) - .setCornerRadius(mLeash, mInPip ? mCornerRadius : 0); + final SurfaceControl.Transaction tx = mSurfaceControlTransactionFactory.getTransaction(); + mSurfaceTransactionHelper + .crop(tx, mLeash, destinationBounds) + .round(tx, mLeash, mInPip); scheduleFinishResizePip(tx, destinationBounds, TRANSITION_DIRECTION_NONE, null); } private void scheduleFinishResizePip(SurfaceControl.Transaction tx, Rect destinationBounds, @PipAnimationController.TransitionDirection int direction, Consumer updateBoundsCallback) { - Objects.requireNonNull(mToken, "Requires valid IWindowContainer"); SomeArgs args = SomeArgs.obtain(); args.arg1 = updateBoundsCallback; args.arg2 = tx; @@ -367,7 +361,6 @@ public class PipTaskOrganizer extends ITaskOrganizer.Stub { // 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; @@ -396,17 +389,16 @@ public class PipTaskOrganizer extends ITaskOrganizer.Stub { 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()) - .setCornerRadius(mLeash, mInPip ? mCornerRadius : 0) - .apply(); + final SurfaceControl.Transaction tx = mSurfaceControlTransactionFactory.getTransaction(); + mSurfaceTransactionHelper + .crop(tx, mLeash, destinationBounds) + .round(tx, mLeash, mInPip); + tx.apply(); } private void finishResize(SurfaceControl.Transaction tx, Rect destinationBounds, @@ -449,7 +441,6 @@ public class PipTaskOrganizer extends ITaskOrganizer.Stub { mUpdateHandler.post(() -> mPipAnimationController .getAnimator(mLeash, currentBounds, destinationBounds) .setTransitionDirection(direction) - .setCornerRadius(mCornerRadius) .setPipAnimationCallback(mPipAnimationCallback) .setDuration(durationMs) .start()); diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java index 2aac188c130d4..020627a204583 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java @@ -42,6 +42,7 @@ import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.pip.BasePipManager; import com.android.systemui.pip.PipBoundsHandler; import com.android.systemui.pip.PipSnapAlgorithm; +import com.android.systemui.pip.PipSurfaceTransactionHelper; import com.android.systemui.pip.PipTaskOrganizer; import com.android.systemui.shared.recents.IPinnedStackAnimationListener; import com.android.systemui.shared.system.ActivityManagerWrapper; @@ -210,7 +211,8 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio FloatingContentCoordinator floatingContentCoordinator, DeviceConfigProxy deviceConfig, PipBoundsHandler pipBoundsHandler, - PipSnapAlgorithm pipSnapAlgorithm) { + PipSnapAlgorithm pipSnapAlgorithm, + PipSurfaceTransactionHelper surfaceTransactionHelper) { mContext = context; mActivityManager = ActivityManager.getService(); @@ -224,7 +226,8 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio final IActivityTaskManager activityTaskManager = ActivityTaskManager.getService(); mPipBoundsHandler = pipBoundsHandler; - mPipTaskOrganizer = new PipTaskOrganizer(mContext, mPipBoundsHandler); + mPipTaskOrganizer = new PipTaskOrganizer(context, pipBoundsHandler, + surfaceTransactionHelper); mPipTaskOrganizer.registerPipTransitionCallback(this); mInputConsumerController = InputConsumerController.getPipInputConsumer(); mMediaController = new PipMediaController(context, mActivityManager, broadcastDispatcher); diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java index 33760be3f469c..15a008803a522 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java @@ -78,10 +78,10 @@ public class PipMotionHelper implements PipAppOpsListener.Callback, private final Rect mBounds = new Rect(); /** The bounds within which PIP's top-left coordinate is allowed to move. */ - private Rect mMovementBounds = new Rect(); + private final Rect mMovementBounds = new Rect(); /** The region that all of PIP must stay within. */ - private Rect mFloatingAllowedArea = new Rect(); + private final Rect mFloatingAllowedArea = new Rect(); /** * Bounds that are animated using the physics animator. @@ -89,7 +89,7 @@ public class PipMotionHelper implements PipAppOpsListener.Callback, private final Rect mAnimatedBounds = new Rect(); /** The destination bounds to which PIP is animating. */ - private Rect mAnimatingToBounds = new Rect(); + private final Rect mAnimatingToBounds = new Rect(); /** Coordinator instance for resolving conflicts with other floating content. */ private FloatingContentCoordinator mFloatingContentCoordinator; @@ -120,7 +120,7 @@ public class PipMotionHelper implements PipAppOpsListener.Callback, new PhysicsAnimator.SpringConfig( SpringForce.STIFFNESS_LOW, SpringForce.DAMPING_RATIO_LOW_BOUNCY); - private final Consumer mUpdateBoundsCallback = (toBounds) -> mBounds.set(toBounds); + private final Consumer mUpdateBoundsCallback = mBounds::set; public PipMotionHelper(Context context, IActivityTaskManager activityTaskManager, PipTaskOrganizer pipTaskOrganizer, PipMenuActivityController menuController, @@ -437,7 +437,7 @@ public class PipMotionHelper implements PipAppOpsListener.Callback, * {@link FloatingContentCoordinator.FloatingContent#getFloatingBoundsOnScreen()}. */ private void setAnimatingToBounds(Rect bounds) { - mAnimatingToBounds = bounds; + mAnimatingToBounds.set(bounds); mFloatingContentCoordinator.onContentMoved(this); } diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java index 6206dd576ec41..050acd5a87285 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java +++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java @@ -51,6 +51,7 @@ import com.android.systemui.UiOffloadThread; import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.pip.BasePipManager; import com.android.systemui.pip.PipBoundsHandler; +import com.android.systemui.pip.PipSurfaceTransactionHelper; import com.android.systemui.pip.PipTaskOrganizer; import com.android.systemui.shared.system.ActivityManagerWrapper; import com.android.systemui.shared.system.PinnedStackListenerForwarder.PinnedStackListener; @@ -229,7 +230,8 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio @Inject public PipManager(Context context, BroadcastDispatcher broadcastDispatcher, - PipBoundsHandler pipBoundsHandler) { + PipBoundsHandler pipBoundsHandler, + PipSurfaceTransactionHelper surfaceTransactionHelper) { if (mInitialized) { return; } @@ -239,7 +241,8 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio mPipBoundsHandler = pipBoundsHandler; mResizeAnimationDuration = context.getResources() .getInteger(R.integer.config_pipResizeAnimationDuration); - mPipTaskOrganizer = new PipTaskOrganizer(mContext, mPipBoundsHandler); + mPipTaskOrganizer = new PipTaskOrganizer(mContext, mPipBoundsHandler, + surfaceTransactionHelper); mPipTaskOrganizer.registerPipTransitionCallback(this); mActivityTaskManager = ActivityTaskManager.getService(); ActivityManagerWrapper.getInstance().registerTaskStackListener(mTaskStackListener); diff --git a/packages/SystemUI/tests/src/com/android/systemui/pip/PipAnimationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/pip/PipAnimationControllerTest.java index a2ab78483b686..b863f143056fa 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/pip/PipAnimationControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/pip/PipAnimationControllerTest.java @@ -58,7 +58,8 @@ public class PipAnimationControllerTest extends SysuiTestCase { @Before public void setUp() throws Exception { - mPipAnimationController = new PipAnimationController(mContext); + mPipAnimationController = new PipAnimationController( + mContext, new PipSurfaceTransactionHelper(mContext)); MockitoAnnotations.initMocks(this); }