diff options
12 files changed, 199 insertions, 88 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipAnimationController.java b/packages/SystemUI/src/com/android/systemui/pip/PipAnimationController.java index f72de11a01ed..13516a9e03c4 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/PipAnimationController.java +++ b/packages/SystemUI/src/com/android/systemui/pip/PipAnimationController.java @@ -65,6 +65,10 @@ public class PipAnimationController { @Retention(RetentionPolicy.SOURCE) public @interface TransitionDirection {} + public static boolean isInPipDirection(@TransitionDirection int direction) { + return direction == TRANSITION_DIRECTION_TO_PIP; + } + public static boolean isOutPipDirection(@TransitionDirection int direction) { return direction == TRANSITION_DIRECTION_TO_FULLSCREEN || direction == TRANSITION_DIRECTION_TO_SPLIT_SCREEN; @@ -104,6 +108,12 @@ public class PipAnimationController { if (mCurrentAnimator == null) { mCurrentAnimator = setupPipTransitionAnimator( PipTransitionAnimator.ofBounds(leash, startBounds, endBounds)); + } else if (mCurrentAnimator.getAnimationType() == ANIM_TYPE_ALPHA + && mCurrentAnimator.isRunning()) { + // If we are still animating the fade into pip, then just move the surface and ensure + // we update with the new destination bounds, but don't interrupt the existing animation + // with a new bounds + mCurrentAnimator.setDestinationBounds(endBounds); } else if (mCurrentAnimator.getAnimationType() == ANIM_TYPE_BOUNDS && mCurrentAnimator.isRunning()) { mCurrentAnimator.setDestinationBounds(endBounds); @@ -265,8 +275,7 @@ public class PipAnimationController { boolean inScaleTransition() { if (mAnimationType != ANIM_TYPE_BOUNDS) return false; - final int direction = getTransitionDirection(); - return !isOutPipDirection(direction) && direction != TRANSITION_DIRECTION_TO_PIP; + return !isInPipDirection(getTransitionDirection()); } /** @@ -354,7 +363,11 @@ public class PipAnimationController { getCastedFractionValue(start.bottom, end.bottom, fraction)); setCurrentValue(mTmpRect); if (inScaleTransition()) { - getSurfaceTransactionHelper().scale(tx, leash, start, mTmpRect); + if (isOutPipDirection(getTransitionDirection())) { + getSurfaceTransactionHelper().scale(tx, leash, end, mTmpRect); + } else { + getSurfaceTransactionHelper().scale(tx, leash, start, mTmpRect); + } } else { getSurfaceTransactionHelper().crop(tx, leash, mTmpRect); } diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipBoundsHandler.java b/packages/SystemUI/src/com/android/systemui/pip/PipBoundsHandler.java index 3eeadc367b0d..394f9975579d 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/PipBoundsHandler.java +++ b/packages/SystemUI/src/com/android/systemui/pip/PipBoundsHandler.java @@ -209,6 +209,10 @@ public class PipBoundsHandler { return new Rect(0, 0, mDisplayInfo.logicalWidth, mDisplayInfo.logicalHeight); } + public int getDisplayRotation() { + return mDisplayInfo.rotation; + } + /** * Responds to IPinnedStackListener on {@link DisplayInfo} change. * It will normally follow up with a diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java b/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java index 7e2efc04ea8e..fd13890b8767 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java +++ b/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java @@ -16,6 +16,9 @@ package com.android.systemui.pip; +import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; +import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; +import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static com.android.systemui.pip.PipAnimationController.ANIM_TYPE_ALPHA; @@ -25,25 +28,30 @@ import static com.android.systemui.pip.PipAnimationController.TRANSITION_DIRECTI import static com.android.systemui.pip.PipAnimationController.TRANSITION_DIRECTION_TO_FULLSCREEN; import static com.android.systemui.pip.PipAnimationController.TRANSITION_DIRECTION_TO_PIP; import static com.android.systemui.pip.PipAnimationController.TRANSITION_DIRECTION_TO_SPLIT_SCREEN; +import static com.android.systemui.pip.PipAnimationController.isInPipDirection; import static com.android.systemui.pip.PipAnimationController.isOutPipDirection; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityManager; +import android.app.ActivityTaskManager; import android.app.PictureInPictureParams; import android.content.ComponentName; import android.content.Context; import android.content.pm.ActivityInfo; +import android.content.res.Configuration; import android.graphics.Rect; import android.os.Handler; import android.os.IBinder; import android.os.Looper; +import android.os.RemoteException; import android.util.Log; import android.util.Size; import android.view.SurfaceControl; import android.window.TaskOrganizer; import android.window.WindowContainerToken; import android.window.WindowContainerTransaction; +import android.window.WindowContainerTransactionCallback; import android.window.WindowOrganizer; import com.android.internal.os.SomeArgs; @@ -51,6 +59,7 @@ import com.android.systemui.R; import com.android.systemui.pip.phone.PipUpdateThread; import com.android.systemui.stackdivider.Divider; +import java.io.PrintWriter; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -90,7 +99,7 @@ public class PipTaskOrganizer extends TaskOrganizer { private final Rect mLastReportedBounds = new Rect(); private final int mEnterExitAnimationDuration; private final PipSurfaceTransactionHelper mSurfaceTransactionHelper; - private final Map<IBinder, Rect> mBoundsToRestore = new HashMap<>(); + private final Map<IBinder, Configuration> mInitialState = new HashMap<>(); private final Divider mSplitDivider; // These callbacks are called on the update thread @@ -110,7 +119,8 @@ public class PipTaskOrganizer extends TaskOrganizer { @Override public void onPipAnimationEnd(SurfaceControl.Transaction tx, PipAnimationController.PipTransitionAnimator animator) { - finishResize(tx, animator.getDestinationBounds(), animator.getTransitionDirection()); + finishResize(tx, animator.getDestinationBounds(), animator.getTransitionDirection(), + animator.getAnimationType()); mMainHandler.post(() -> { for (int i = mPipTransitionCallbacks.size() - 1; i >= 0; i--) { final PipTransitionCallback callback = mPipTransitionCallbacks.get(i); @@ -170,7 +180,7 @@ public class PipTaskOrganizer extends TaskOrganizer { case MSG_FINISH_RESIZE: { SurfaceControl.Transaction tx = (SurfaceControl.Transaction) args.arg2; Rect toBounds = (Rect) args.arg3; - finishResize(tx, toBounds, args.argi1 /* direction */); + finishResize(tx, toBounds, args.argi1 /* direction */, -1); if (updateBoundsCallback != null) { updateBoundsCallback.accept(toBounds); } @@ -240,28 +250,76 @@ public class PipTaskOrganizer extends TaskOrganizer { } /** - * Dismiss PiP, this is done in two phases using {@link WindowContainerTransaction} - * - setActivityWindowingMode to undefined at beginning of the transaction. without changing - * the windowing mode of the Task itself. This makes sure the activity render it's final - * configuration while the Task is still in PiP. + * Expands PiP to the previous bounds, this is done in two phases using + * {@link WindowContainerTransaction} + * - setActivityWindowingMode to either fullscreen or split-secondary at beginning of the + * transaction. without changing the windowing mode of the Task itself. This makes sure the + * activity render it's final configuration while the Task is still in PiP. * - setWindowingMode to undefined at the end of transition * @param animationDurationMs duration in millisecond for the exiting PiP transition */ - public void dismissPip(int animationDurationMs) { + public void exitPip(int animationDurationMs) { if (!mInPip || mToken == null) { - Log.wtf(TAG, "Not allowed to dismissPip in current state" + Log.wtf(TAG, "Not allowed to exitPip in current state" + " mInPip=" + mInPip + " mToken=" + mToken); return; } + + final Configuration initialConfig = mInitialState.remove(mToken.asBinder()); + final boolean orientationDiffers = initialConfig.windowConfiguration.getRotation() + != mPipBoundsHandler.getDisplayRotation(); final WindowContainerTransaction wct = new WindowContainerTransaction(); - wct.setActivityWindowingMode(mToken, WINDOWING_MODE_UNDEFINED); - WindowOrganizer.applyTransaction(wct); - final Rect destinationBounds = mBoundsToRestore.remove(mToken.asBinder()); - final int direction = syncWithSplitScreenBounds(destinationBounds) - ? TRANSITION_DIRECTION_TO_SPLIT_SCREEN : TRANSITION_DIRECTION_TO_FULLSCREEN; - scheduleAnimateResizePip(mLastReportedBounds, destinationBounds, - direction, animationDurationMs, null /* updateBoundsCallback */); - mInPip = false; + if (orientationDiffers) { + // Don't bother doing an animation if the display rotation differs or if it's in + // a non-supported windowing mode + wct.setWindowingMode(mToken, WINDOWING_MODE_UNDEFINED); + wct.setActivityWindowingMode(mToken, WINDOWING_MODE_UNDEFINED); + WindowOrganizer.applyTransaction(wct); + mInPip = false; + } else { + final Rect destinationBounds = initialConfig.windowConfiguration.getBounds(); + final int direction = syncWithSplitScreenBounds(destinationBounds) + ? TRANSITION_DIRECTION_TO_SPLIT_SCREEN + : TRANSITION_DIRECTION_TO_FULLSCREEN; + final SurfaceControl.Transaction tx = new SurfaceControl.Transaction(); + mSurfaceTransactionHelper.scale(tx, mLeash, destinationBounds, + mLastReportedBounds); + tx.setWindowCrop(mLeash, destinationBounds.width(), destinationBounds.height()); + wct.setActivityWindowingMode(mToken, direction == TRANSITION_DIRECTION_TO_SPLIT_SCREEN + ? WINDOWING_MODE_SPLIT_SCREEN_SECONDARY + : WINDOWING_MODE_FULLSCREEN); + wct.setBounds(mToken, destinationBounds); + wct.setBoundsChangeTransaction(mToken, tx); + applySyncTransaction(wct, new WindowContainerTransactionCallback() { + @Override + public void onTransactionReady(int id, SurfaceControl.Transaction t) { + t.apply(); + scheduleAnimateResizePip(mLastReportedBounds, destinationBounds, + direction, animationDurationMs, null /* updateBoundsCallback */); + mInPip = false; + } + }); + } + } + + /** + * Removes PiP immediately. + */ + public void removePip() { + if (!mInPip || mToken == null) { + Log.wtf(TAG, "Not allowed to removePip in current state" + + " mInPip=" + mInPip + " mToken=" + mToken); + return; + } + getUpdateHandler().post(() -> { + try { + ActivityTaskManager.getService().removeStacksInWindowingModes( + new int[]{ WINDOWING_MODE_PINNED }); + } catch (RemoteException e) { + Log.e(TAG, "Failed to remove PiP", e); + } + }); + mInitialState.remove(mToken.asBinder()); } @Override @@ -277,19 +335,37 @@ public class PipTaskOrganizer extends TaskOrganizer { mInPip = true; mLeash = leash; + // TODO: Skip enter animation when entering pip from another orientation final Rect currentBounds = mTaskInfo.configuration.windowConfiguration.getBounds(); - mBoundsToRestore.put(mToken.asBinder(), currentBounds); + mInitialState.put(mToken.asBinder(), new Configuration(mTaskInfo.configuration)); + if (mOneShotAnimationType == ANIM_TYPE_BOUNDS) { scheduleAnimateResizePip(currentBounds, destinationBounds, TRANSITION_DIRECTION_TO_PIP, mEnterExitAnimationDuration, null /* updateBoundsCallback */); } else if (mOneShotAnimationType == ANIM_TYPE_ALPHA) { - mUpdateHandler.post(() -> mPipAnimationController - .getAnimator(mLeash, destinationBounds, 0f, 1f) - .setTransitionDirection(TRANSITION_DIRECTION_TO_PIP) - .setPipAnimationCallback(mPipAnimationCallback) - .setDuration(mEnterExitAnimationDuration) - .start()); + // If we are fading the PIP in, then we should move the pip to the final location as + // soon as possible, but set the alpha immediately since the transaction can take a + // while to process + final SurfaceControl.Transaction tx = new SurfaceControl.Transaction(); + tx.setAlpha(mLeash, 0f); + tx.apply(); + final WindowContainerTransaction wct = new WindowContainerTransaction(); + wct.setActivityWindowingMode(mToken, WINDOWING_MODE_UNDEFINED); + wct.setBounds(mToken, destinationBounds); + wct.scheduleFinishEnterPip(mToken, destinationBounds); + applySyncTransaction(wct, new WindowContainerTransactionCallback() { + @Override + public void onTransactionReady(int id, SurfaceControl.Transaction t) { + t.apply(); + mUpdateHandler.post(() -> mPipAnimationController + .getAnimator(mLeash, destinationBounds, 0f, 1f) + .setTransitionDirection(TRANSITION_DIRECTION_TO_PIP) + .setPipAnimationCallback(mPipAnimationCallback) + .setDuration(mEnterExitAnimationDuration) + .start()); + } + }); mOneShotAnimationType = ANIM_TYPE_BOUNDS; } else { throw new RuntimeException("Unrecognized animation type: " + mOneShotAnimationType); @@ -297,7 +373,7 @@ public class PipTaskOrganizer extends TaskOrganizer { } /** - * Note that dismissing PiP is now originated from SystemUI, see {@link #dismissPip(int)}. + * Note that dismissing PiP is now originated from SystemUI, see {@link #exitPip(int)}. * Meanwhile this callback is invoked whenever the task is removed. For instance: * - as a result of removeStacksInWindowingModes from WM * - activity itself is died @@ -411,6 +487,7 @@ public class PipTaskOrganizer extends TaskOrganizer { // can be initiated in other component, ignore if we are no longer in PIP return; } + SomeArgs args = SomeArgs.obtain(); args.arg1 = updateBoundsCallback; args.arg2 = currentBounds; @@ -509,7 +586,7 @@ public class PipTaskOrganizer extends TaskOrganizer { throw new RuntimeException("Callers should call scheduleResizePip() instead of this " + "directly"); } - // Could happen when dismissPip + // Could happen when exitPip if (mToken == null || mLeash == null) { Log.w(TAG, "Abort animation, invalid leash"); return; @@ -526,7 +603,7 @@ public class PipTaskOrganizer extends TaskOrganizer { throw new RuntimeException("Callers should call scheduleUserResizePip() instead of " + "this directly"); } - // Could happen when dismissPip + // Could happen when exitPip if (mToken == null || mLeash == null) { Log.w(TAG, "Abort animation, invalid leash"); return; @@ -537,32 +614,43 @@ public class PipTaskOrganizer extends TaskOrganizer { } private void finishResize(SurfaceControl.Transaction tx, Rect destinationBounds, - @PipAnimationController.TransitionDirection int direction) { + @PipAnimationController.TransitionDirection int direction, + @PipAnimationController.AnimationType int type) { if (Looper.myLooper() != mUpdateHandler.getLooper()) { throw new RuntimeException("Callers should call scheduleResizePip() instead of this " + "directly"); } mLastReportedBounds.set(destinationBounds); + if (isInPipDirection(direction) && type == ANIM_TYPE_ALPHA) { + return; + } + final WindowContainerTransaction wct = new WindowContainerTransaction(); final Rect taskBounds; - if (isOutPipDirection(direction)) { + if (isInPipDirection(direction)) { + // If we are animating from fullscreen using a bounds animation, then reset the + // activity windowing mode set by WM, and set the task bounds to the final bounds + taskBounds = destinationBounds; + wct.setActivityWindowingMode(mToken, WINDOWING_MODE_UNDEFINED); + wct.scheduleFinishEnterPip(mToken, destinationBounds); + } else if (isOutPipDirection(direction)) { // If we are animating to fullscreen, then we need to reset the override bounds // on the task to ensure that the task "matches" the parent's bounds. taskBounds = (direction == TRANSITION_DIRECTION_TO_FULLSCREEN) ? null : destinationBounds; - // As for the final windowing mode, simply reset it to undefined. + // As for the final windowing mode, simply reset it to undefined and reset the activity + // mode set prior to the animation running wct.setWindowingMode(mToken, WINDOWING_MODE_UNDEFINED); + wct.setActivityWindowingMode(mToken, WINDOWING_MODE_UNDEFINED); if (mSplitDivider != null && direction == TRANSITION_DIRECTION_TO_SPLIT_SCREEN) { wct.reparent(mToken, mSplitDivider.getSecondaryRoot(), true /* onTop */); } } else { + // Just a resize in PIP taskBounds = destinationBounds; } - if (direction == TRANSITION_DIRECTION_TO_PIP) { - wct.scheduleFinishEnterPip(mToken, taskBounds); - } else { - wct.setBounds(mToken, taskBounds); - } + + wct.setBounds(mToken, taskBounds); wct.setBoundsChangeTransaction(mToken, tx); WindowOrganizer.applyTransaction(wct); } @@ -573,17 +661,17 @@ public class PipTaskOrganizer extends TaskOrganizer { throw new RuntimeException("Callers should call scheduleAnimateResizePip() instead of " + "this directly"); } - // Could happen when dismissPip + // Could happen when exitPip if (mToken == null || mLeash == null) { Log.w(TAG, "Abort animation, invalid leash"); return; } - mUpdateHandler.post(() -> mPipAnimationController + mPipAnimationController .getAnimator(mLeash, currentBounds, destinationBounds) .setTransitionDirection(direction) .setPipAnimationCallback(mPipAnimationCallback) .setDuration(durationMs) - .start()); + .start(); } private Size getMinimalSize(ActivityInfo activityInfo) { @@ -624,6 +712,27 @@ public class PipTaskOrganizer extends TaskOrganizer { } /** + * Dumps internal states. + */ + public void dump(PrintWriter pw, String prefix) { + final String innerPrefix = prefix + " "; + pw.println(prefix + TAG); + pw.println(innerPrefix + "mTaskInfo=" + mTaskInfo); + pw.println(innerPrefix + "mToken=" + mToken + + " binder=" + (mToken != null ? mToken.asBinder() : null)); + pw.println(innerPrefix + "mLeash=" + mLeash); + pw.println(innerPrefix + "mInPip=" + mInPip); + pw.println(innerPrefix + "mOneShotAnimationType=" + mOneShotAnimationType); + pw.println(innerPrefix + "mPictureInPictureParams=" + mPictureInPictureParams); + pw.println(innerPrefix + "mLastReportedBounds=" + mLastReportedBounds); + pw.println(innerPrefix + "mInitialState:"); + for (Map.Entry<IBinder, Configuration> e : mInitialState.entrySet()) { + pw.println(innerPrefix + " binder=" + e.getKey() + + " winConfig=" + e.getValue().windowConfiguration); + } + } + + /** * Callback interface for PiP transitions (both from and to PiP mode) */ public interface PipTransitionCallback { diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipAccessibilityInteractionConnection.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipAccessibilityInteractionConnection.java index 84f7e89d9f2f..f1eef4353d32 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipAccessibilityInteractionConnection.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipAccessibilityInteractionConnection.java @@ -101,7 +101,7 @@ public class PipAccessibilityInteractionConnection result = true; break; case AccessibilityNodeInfo.ACTION_EXPAND: - mMotionHelper.expandPip(); + mMotionHelper.expandPipToFullscreen(); result = true; break; default: 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 0841bb70f205..30d6cd9d23b7 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java @@ -25,7 +25,6 @@ import android.annotation.Nullable; import android.app.ActivityManager; import android.app.ActivityTaskManager; import android.app.IActivityManager; -import android.app.IActivityTaskManager; import android.content.ComponentName; import android.content.Context; import android.content.pm.ParceledListSlice; @@ -140,7 +139,7 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio != WINDOWING_MODE_PINNED) { return; } - mTouchHandler.getMotionHelper().expandPip(clearedTask /* skipAnimation */); + mTouchHandler.getMotionHelper().expandPipToFullscreen(clearedTask /* skipAnimation */); } }; @@ -214,7 +213,6 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio } ActivityManagerWrapper.getInstance().registerTaskStackListener(mTaskStackListener); - final IActivityTaskManager activityTaskManager = ActivityTaskManager.getService(); mPipBoundsHandler = pipBoundsHandler; mPipTaskOrganizer = pipTaskOrganizer; mPipTaskOrganizer.registerPipTransitionCallback(this); @@ -222,7 +220,7 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio mMediaController = new PipMediaController(context, mActivityManager, broadcastDispatcher); mMenuController = new PipMenuActivityController(context, mMediaController, mInputConsumerController); - mTouchHandler = new PipTouchHandler(context, mActivityManager, activityTaskManager, + mTouchHandler = new PipTouchHandler(context, mActivityManager, mMenuController, mInputConsumerController, mPipBoundsHandler, mPipTaskOrganizer, floatingContentCoordinator, deviceConfig, pipSnapAlgorithm); mAppOpsListener = new PipAppOpsListener(context, mActivityManager, @@ -237,7 +235,7 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio try { mPipTaskOrganizer.registerOrganizer(WINDOWING_MODE_PINNED); - ActivityManager.StackInfo stackInfo = activityTaskManager.getStackInfo( + ActivityManager.StackInfo stackInfo = ActivityTaskManager.getService().getStackInfo( WINDOWING_MODE_PINNED, ACTIVITY_TYPE_UNDEFINED); if (stackInfo != null) { // If SystemUI restart, and it already existed a pinned stack, @@ -261,7 +259,7 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio */ @Override public void expandPip() { - mTouchHandler.getMotionHelper().expandPip(false /* skipAnimation */); + mTouchHandler.getMotionHelper().expandPipToFullscreen(false /* skipAnimation */); } /** @@ -378,5 +376,6 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio mMenuController.dump(pw, innerPrefix); mTouchHandler.dump(pw, innerPrefix); mPipBoundsHandler.dump(pw, innerPrefix); + mPipTaskOrganizer.dump(pw, innerPrefix); } } 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 08d42224c3c0..d0995972e8a8 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java @@ -16,16 +16,12 @@ package com.android.systemui.pip.phone; -import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; - import android.annotation.NonNull; import android.annotation.Nullable; -import android.app.IActivityTaskManager; import android.content.ComponentName; import android.content.Context; import android.graphics.Rect; import android.os.Debug; -import android.os.RemoteException; import android.util.Log; import androidx.dynamicanimation.animation.SpringForce; @@ -33,7 +29,6 @@ import androidx.dynamicanimation.animation.SpringForce; import com.android.systemui.pip.PipSnapAlgorithm; import com.android.systemui.pip.PipTaskOrganizer; import com.android.systemui.shared.system.WindowManagerWrapper; -import com.android.systemui.statusbar.FlingAnimationUtils; import com.android.systemui.util.FloatingContentCoordinator; import com.android.systemui.util.animation.FloatProperties; import com.android.systemui.util.animation.PhysicsAnimator; @@ -60,12 +55,10 @@ public class PipMotionHelper implements PipAppOpsListener.Callback, private static final float DEFAULT_FRICTION = 2f; private final Context mContext; - private final IActivityTaskManager mActivityTaskManager; private final PipTaskOrganizer mPipTaskOrganizer; private PipMenuActivityController mMenuController; private PipSnapAlgorithm mSnapAlgorithm; - private FlingAnimationUtils mFlingAnimationUtils; private final Rect mStableInsets = new Rect(); @@ -147,16 +140,13 @@ public class PipMotionHelper implements PipAppOpsListener.Callback, public void onPipTransitionCanceled(ComponentName activity, int direction) {} }; - public PipMotionHelper(Context context, IActivityTaskManager activityTaskManager, - PipTaskOrganizer pipTaskOrganizer, PipMenuActivityController menuController, - PipSnapAlgorithm snapAlgorithm, FlingAnimationUtils flingAnimationUtils, + public PipMotionHelper(Context context, PipTaskOrganizer pipTaskOrganizer, + PipMenuActivityController menuController, PipSnapAlgorithm snapAlgorithm, FloatingContentCoordinator floatingContentCoordinator) { mContext = context; - mActivityTaskManager = activityTaskManager; mPipTaskOrganizer = pipTaskOrganizer; mMenuController = menuController; mSnapAlgorithm = snapAlgorithm; - mFlingAnimationUtils = flingAnimationUtils; mFloatingContentCoordinator = floatingContentCoordinator; onConfigurationChanged(); mPipTaskOrganizer.registerPipTransitionCallback(mPipTransitionCallback); @@ -267,22 +257,24 @@ public class PipMotionHelper implements PipAppOpsListener.Callback, /** * Resizes the pinned stack back to fullscreen. */ - void expandPip() { - expandPip(false /* skipAnimation */); + void expandPipToFullscreen() { + expandPipToFullscreen(false /* skipAnimation */); } /** * Resizes the pinned stack back to fullscreen. */ - void expandPip(boolean skipAnimation) { + void expandPipToFullscreen(boolean skipAnimation) { if (DEBUG) { - Log.d(TAG, "expandPip: skipAnimation=" + skipAnimation + Log.d(TAG, "exitPip: skipAnimation=" + skipAnimation + " callers=\n" + Debug.getCallers(5, " ")); } cancelAnimations(); mMenuController.hideMenuWithoutResize(); mPipTaskOrganizer.getUpdateHandler().post(() -> { - mPipTaskOrganizer.dismissPip(skipAnimation ? 0 : EXPAND_STACK_TO_FULLSCREEN_DURATION); + mPipTaskOrganizer.exitPip(skipAnimation + ? 0 + : EXPAND_STACK_TO_FULLSCREEN_DURATION); }); } @@ -292,18 +284,11 @@ public class PipMotionHelper implements PipAppOpsListener.Callback, @Override public void dismissPip() { if (DEBUG) { - Log.d(TAG, "dismissPip: callers=\n" + Debug.getCallers(5, " ")); + Log.d(TAG, "removePip: callers=\n" + Debug.getCallers(5, " ")); } cancelAnimations(); mMenuController.hideMenuWithoutResize(); - mPipTaskOrganizer.getUpdateHandler().post(() -> { - try { - mActivityTaskManager.removeStacksInWindowingModes( - new int[]{ WINDOWING_MODE_PINNED }); - } catch (RemoteException e) { - Log.e(TAG, "Failed to remove PiP", e); - } - }); + mPipTaskOrganizer.removePip(); } /** Sets the movement bounds to use to constrain PIP position animations. */ diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java index b70fb3f8e1e9..ca73a6c68670 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java @@ -23,7 +23,6 @@ import static com.android.systemui.pip.phone.PipMenuActivityController.MENU_STAT import android.annotation.SuppressLint; import android.app.IActivityManager; -import android.app.IActivityTaskManager; import android.content.ComponentName; import android.content.Context; import android.content.res.Resources; @@ -188,7 +187,7 @@ public class PipTouchHandler { @Override public void onPipExpand() { - mMotionHelper.expandPip(); + mMotionHelper.expandPipToFullscreen(); } @Override @@ -210,7 +209,7 @@ public class PipTouchHandler { @SuppressLint("InflateParams") public PipTouchHandler(Context context, IActivityManager activityManager, - IActivityTaskManager activityTaskManager, PipMenuActivityController menuController, + PipMenuActivityController menuController, InputConsumerController inputConsumerController, PipBoundsHandler pipBoundsHandler, PipTaskOrganizer pipTaskOrganizer, @@ -228,8 +227,8 @@ public class PipTouchHandler { mFlingAnimationUtils = new FlingAnimationUtils(context.getResources().getDisplayMetrics(), 2.5f); mGesture = new DefaultPipTouchGesture(); - mMotionHelper = new PipMotionHelper(mContext, activityTaskManager, pipTaskOrganizer, - mMenuController, mSnapAlgorithm, mFlingAnimationUtils, floatingContentCoordinator); + mMotionHelper = new PipMotionHelper(mContext, pipTaskOrganizer, mMenuController, + mSnapAlgorithm, floatingContentCoordinator); mPipResizeGestureHandler = new PipResizeGestureHandler(context, pipBoundsHandler, mMotionHelper, deviceConfig, pipTaskOrganizer); @@ -905,7 +904,7 @@ public class PipTouchHandler { // Expand to fullscreen if this is a double tap // the PiP should be frozen until the transition ends setTouchEnabled(false); - mMotionHelper.expandPip(); + mMotionHelper.expandPipToFullscreen(); } else if (mMenuState != MENU_STATE_FULL) { if (!mTouchState.isWaitingForDoubleTap()) { // User has stalled long enough for this not to be a drag or a double tap, just 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 f49732d98ae8..628223630af7 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java +++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java @@ -468,7 +468,7 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio mPipTaskOrganizer.scheduleAnimateResizePip(mCurrentPipBounds, mResizeAnimationDuration, null); } else { - mPipTaskOrganizer.dismissPip(mResizeAnimationDuration); + mPipTaskOrganizer.exitPip(mResizeAnimationDuration); } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/pip/phone/PipTouchHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/pip/phone/PipTouchHandlerTest.java index 721125409c5a..601fad6e0fef 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/pip/phone/PipTouchHandlerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/pip/phone/PipTouchHandlerTest.java @@ -65,9 +65,6 @@ public class PipTouchHandlerTest extends SysuiTestCase { private IActivityManager mActivityManager; @Mock - private IActivityTaskManager mIActivityTaskManager; - - @Mock private PipMenuActivityController mPipMenuActivityController; @Mock @@ -101,7 +98,7 @@ public class PipTouchHandlerTest extends SysuiTestCase { public void setUp() throws Exception { MockitoAnnotations.initMocks(this); mPipSnapAlgorithm = new PipSnapAlgorithm(mContext); - mPipTouchHandler = new PipTouchHandler(mContext, mActivityManager, mIActivityTaskManager, + mPipTouchHandler = new PipTouchHandler(mContext, mActivityManager, mPipMenuActivityController, mInputConsumerController, mPipBoundsHandler, mPipTaskOrganizer, mFloatingContentCoordinator, mDeviceConfigProxy, mPipSnapAlgorithm); diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index 131e44963033..c0282af8b546 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -2184,8 +2184,10 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A @Override boolean isFocusable() { - return super.isFocusable() - && (getWindowConfiguration().canReceiveKeys() || isAlwaysFocusable()); + // TODO(156521483): Propagate the state down the hierarchy instead of checking the parent + boolean canReceiveKeys = getWindowConfiguration().canReceiveKeys() + && getTask().getWindowConfiguration().canReceiveKeys(); + return super.isFocusable() && (canReceiveKeys || isAlwaysFocusable()); } boolean isResizeable() { diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java index c93b7354999b..76403c24e652 100644 --- a/services/core/java/com/android/server/wm/RootWindowContainer.java +++ b/services/core/java/com/android/server/wm/RootWindowContainer.java @@ -2188,6 +2188,10 @@ class RootWindowContainer extends WindowContainer<DisplayContent> // display area, so reparent. stack.reparent(taskDisplayArea, true /* onTop */); } + // Defer the windowing mode change until after the transition to prevent the activity + // from doing work and changing the activity visuals while animating + // TODO(task-org): Figure-out more structured way to do this long term. + r.setWindowingMode(stack.getWindowingMode()); stack.setWindowingMode(WINDOWING_MODE_PINNED); // Reset the state that indicates it can enter PiP while pausing after we've moved it diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index b9e65137665a..d06e87511f77 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -1940,7 +1940,6 @@ class Task extends WindowContainer<WindowContainer> { setLastNonFullscreenBounds(currentBounds); } } - // TODO: Should also take care of Pip mode changes here. saveLaunchingStateIfNeeded(); final boolean taskOrgChanged = updateTaskOrganizerState(false /* forceUpdate */); |