summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/Pip.java27
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java71
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java41
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl26
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java34
5 files changed, 178 insertions, 21 deletions
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/Pip.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/Pip.java
index 7c2625133cad..488f9092b7da 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/Pip.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/Pip.java
@@ -18,7 +18,10 @@ package com.android.wm.shell.pip;
import android.annotation.Nullable;
import android.app.ActivityManager;
+import android.app.PictureInPictureParams;
import android.content.ComponentName;
+import android.content.pm.ActivityInfo;
+import android.graphics.Rect;
import android.media.session.MediaController;
import com.android.wm.shell.pip.phone.PipTouchHandler;
@@ -232,4 +235,28 @@ public interface Pip {
*/
default void suspendPipResizing(int reason) {
}
+
+ /**
+ * Called by Launcher when swiping an auto-pip enabled Activity to home starts
+ * @param componentName {@link ComponentName} represents the Activity entering PiP
+ * @param activityInfo {@link ActivityInfo} tied to the Activity
+ * @param pictureInPictureParams {@link PictureInPictureParams} tied to the Activity
+ * @param launcherRotation Rotation Launcher is in
+ * @param shelfHeight Shelf height when landing PiP window onto Launcher
+ * @return Destination bounds of PiP window based on the parameters passed in
+ */
+ default Rect startSwipePipToHome(ComponentName componentName, ActivityInfo activityInfo,
+ PictureInPictureParams pictureInPictureParams,
+ int launcherRotation, int shelfHeight) {
+ return null;
+ }
+
+ /**
+ * Called by Launcher when swiping an auto-pip enable Activity to home finishes
+ * @param componentName {@link ComponentName} represents the Activity entering PiP
+ * @param destinationBounds Destination bounds of PiP window
+ */
+ default void stopSwipePipToHome(ComponentName componentName, Rect destinationBounds) {
+ return;
+ }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
index e8e1be7e6400..a17cd8c6f9af 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
@@ -104,7 +104,8 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
UNDEFINED(0),
TASK_APPEARED(1),
ENTERING_PIP(2),
- EXITING_PIP(3);
+ ENTERED_PIP(3),
+ EXITING_PIP(4);
private final int mStateValue;
@@ -241,6 +242,14 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
*/
private boolean mShouldDeferEnteringPip;
+ /**
+ * If set to {@code true}, no entering PiP transition would be kicked off and most likely
+ * it's due to the fact that Launcher is handling the transition directly when swiping
+ * auto PiP-able Activity to home.
+ * See also {@link #startSwipePipToHome(ComponentName, ActivityInfo, PictureInPictureParams)}.
+ */
+ private boolean mShouldIgnoreEnteringPipTransition;
+
public PipTaskOrganizer(Context context, @NonNull PipBoundsHandler boundsHandler,
@NonNull PipSurfaceTransactionHelper surfaceTransactionHelper,
Optional<SplitScreen> splitScreenOptional,
@@ -309,6 +318,27 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
}
/**
+ * Callback when Launcher starts swipe-pip-to-home operation.
+ * @return {@link Rect} for destination bounds.
+ */
+ public Rect startSwipePipToHome(ComponentName componentName, ActivityInfo activityInfo,
+ PictureInPictureParams pictureInPictureParams) {
+ mShouldIgnoreEnteringPipTransition = true;
+ mState = State.ENTERING_PIP;
+ return mPipBoundsHandler.getDestinationBounds(componentName,
+ getAspectRatioOrDefault(pictureInPictureParams),
+ null /* bounds */, getMinimalSize(activityInfo));
+ }
+
+ /**
+ * Callback when launcher finishes swipe-pip-to-home operation.
+ * Expect {@link #onTaskAppeared(ActivityManager.RunningTaskInfo, SurfaceControl)} afterwards.
+ */
+ public void stopSwipePipToHome(ComponentName componentName, Rect destinationBounds) {
+ mLastReportedBounds.set(destinationBounds);
+ }
+
+ /**
* 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
@@ -435,6 +465,16 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
mPipUiEventLoggerLogger.setTaskInfo(mTaskInfo);
mPipUiEventLoggerLogger.log(PipUiEventLogger.PipUiEventEnum.PICTURE_IN_PICTURE_ENTER);
+ if (mShouldIgnoreEnteringPipTransition) {
+ // Animation has been finished together with Recents, directly apply the sync
+ // transaction to PiP here.
+ applyEnterPipSyncTransaction(mLastReportedBounds, () -> {
+ mState = State.ENTERED_PIP;
+ });
+ mShouldIgnoreEnteringPipTransition = false;
+ return;
+ }
+
if (mShouldDeferEnteringPip) {
if (DEBUG) Log.d(TAG, "Defer entering PiP animation, fixed rotation is ongoing");
// if deferred, hide the surface till fixed rotation is completed
@@ -489,6 +529,20 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
mSurfaceControlTransactionFactory.getTransaction();
tx.setAlpha(mLeash, 0f);
tx.apply();
+ applyEnterPipSyncTransaction(destinationBounds, () -> {
+ mUpdateHandler.post(() -> mPipAnimationController
+ .getAnimator(mLeash, destinationBounds, 0f, 1f)
+ .setTransitionDirection(TRANSITION_DIRECTION_TO_PIP)
+ .setPipAnimationCallback(mPipAnimationCallback)
+ .setDuration(durationMs)
+ .start());
+ // mState is set right after the animation is kicked off to block any resize
+ // requests such as offsetPip that may have been called prior to the transition.
+ mState = State.ENTERING_PIP;
+ });
+ }
+
+ private void applyEnterPipSyncTransaction(Rect destinationBounds, Runnable runnable) {
final WindowContainerTransaction wct = new WindowContainerTransaction();
wct.setActivityWindowingMode(mToken, WINDOWING_MODE_UNDEFINED);
wct.setBounds(mToken, destinationBounds);
@@ -497,15 +551,9 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
@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(durationMs)
- .start());
- // mState is set right after the animation is kicked off to block any resize
- // requests such as offsetPip that may have been called prior to the transition.
- mState = State.ENTERING_PIP;
+ if (runnable != null) {
+ runnable.run();
+ }
}
});
}
@@ -523,6 +571,9 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
private void sendOnPipTransitionFinished(
@PipAnimationController.TransitionDirection int direction) {
+ if (direction == TRANSITION_DIRECTION_TO_PIP) {
+ mState = State.ENTERED_PIP;
+ }
runOnMainHandler(() -> {
for (int i = mPipTransitionCallbacks.size() - 1; i >= 0; i--) {
final PipTransitionCallback callback = mPipTransitionCallbacks.get(i);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
index 5193656e8299..41c0a881c039 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
@@ -22,9 +22,11 @@ import static com.android.wm.shell.pip.PipAnimationController.isOutPipDirection;
import android.annotation.Nullable;
import android.app.ActivityManager;
+import android.app.PictureInPictureParams;
import android.app.RemoteAction;
import android.content.ComponentName;
import android.content.Context;
+import android.content.pm.ActivityInfo;
import android.content.pm.ParceledListSlice;
import android.graphics.Rect;
import android.os.Handler;
@@ -87,7 +89,7 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac
}
// If there is an animation running (ie. from a shelf offset), then ensure that we calculate
// the bounds for the next orientation using the destination bounds of the animation
- // TODO: Techincally this should account for movement animation bounds as well
+ // TODO: Technically this should account for movement animation bounds as well
Rect currentBounds = mPipTaskOrganizer.getCurrentOrAnimatingBounds();
final boolean changed = mPipBoundsHandler.onDisplayRotationChanged(mContext,
mTmpNormalBounds, currentBounds, mTmpInsetBounds, displayId, fromRotation,
@@ -351,16 +353,18 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac
*/
@Override
public void setShelfHeight(boolean visible, int height) {
- mHandler.post(() -> {
- final int shelfHeight = visible ? height : 0;
- final boolean changed = mPipBoundsHandler.setShelfHeight(visible, shelfHeight);
- if (changed) {
- mTouchHandler.onShelfVisibilityChanged(visible, shelfHeight);
- updateMovementBounds(mPipTaskOrganizer.getLastReportedBounds(),
- false /* fromRotation */, false /* fromImeAdjustment */,
- true /* fromShelfAdjustment */, null /* windowContainerTransaction */);
- }
- });
+ mHandler.post(() -> setShelfHeightLocked(visible, height));
+ }
+
+ private void setShelfHeightLocked(boolean visible, int height) {
+ final int shelfHeight = visible ? height : 0;
+ final boolean changed = mPipBoundsHandler.setShelfHeight(visible, shelfHeight);
+ if (changed) {
+ mTouchHandler.onShelfVisibilityChanged(visible, shelfHeight);
+ updateMovementBounds(mPipTaskOrganizer.getLastReportedBounds(),
+ false /* fromRotation */, false /* fromImeAdjustment */,
+ true /* fromShelfAdjustment */, null /* windowContainerTransaction */);
+ }
}
@Override
@@ -374,6 +378,21 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac
}
@Override
+ public Rect startSwipePipToHome(ComponentName componentName, ActivityInfo activityInfo,
+ PictureInPictureParams pictureInPictureParams,
+ int launcherRotation, int shelfHeight) {
+ setShelfHeightLocked(shelfHeight > 0 /* visible */, shelfHeight);
+ mPipBoundsHandler.onDisplayRotationChangedNotInPip(mContext, launcherRotation);
+ return mPipTaskOrganizer.startSwipePipToHome(componentName, activityInfo,
+ pictureInPictureParams);
+ }
+
+ @Override
+ public void stopSwipePipToHome(ComponentName componentName, Rect destinationBounds) {
+ mPipTaskOrganizer.stopSwipePipToHome(componentName, destinationBounds);
+ }
+
+ @Override
public void onPipTransitionStarted(ComponentName activity, int direction, Rect pipBounds) {
if (isOutPipDirection(direction)) {
// Exiting PIP, save the reentry bounds to restore to when re-entering.
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl
index c94bcaaf7383..e4427f49e030 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl
@@ -16,6 +16,9 @@
package com.android.systemui.shared.recents;
+import android.app.PictureInPictureParams;
+import android.content.ComponentName;
+import android.content.pm.ActivityInfo;
import android.graphics.Bitmap;
import android.graphics.Insets;
import android.graphics.Rect;
@@ -166,4 +169,27 @@ interface ISystemUiProxy {
* Notifies to expand notification panel.
*/
void expandNotificationPanel() = 29;
+
+ /**
+ * Notifies that Activity is about to be swiped to home with entering PiP transition and
+ * queries the destination bounds for PiP depends on Launcher's rotation and shelf height.
+ *
+ * @param componentName ComponentName represents the Activity
+ * @param activityInfo ActivityInfo tied to the Activity
+ * @param pictureInPictureParams PictureInPictureParams tied to the Activity
+ * @param launcherRotation Launcher rotation to calculate the PiP destination bounds
+ * @param shelfHeight Shelf height of launcher to calculate the PiP destination bounds
+ * @return destination bounds the PiP window should land into
+ */
+ Rect startSwipePipToHome(in ComponentName componentName, in ActivityInfo activityInfo,
+ in PictureInPictureParams pictureInPictureParams,
+ int launcherRotation, int shelfHeight) = 30;
+
+ /**
+ * Notifies the swiping Activity to PiP onto home transition is finished
+ *
+ * @param componentName ComponentName represents the Activity
+ * @param destinationBounds the destination bounds the PiP window lands into
+ */
+ void stopSwipePipToHome(in ComponentName componentName, in Rect destinationBounds) = 31;
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
index 0ae1170a25fc..3b0415b31eb5 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
@@ -35,12 +35,14 @@ import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_T
import android.annotation.FloatRange;
import android.app.ActivityTaskManager;
+import android.app.PictureInPictureParams;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
+import android.content.pm.ActivityInfo;
import android.graphics.Bitmap;
import android.graphics.Insets;
import android.graphics.Rect;
@@ -503,6 +505,38 @@ public class OverviewProxyService extends CurrentUserTracker implements
}
}
+ @Override
+ public Rect startSwipePipToHome(ComponentName componentName, ActivityInfo activityInfo,
+ PictureInPictureParams pictureInPictureParams,
+ int launcherRotation, int shelfHeight) {
+ if (!verifyCaller("startSwipePipToHome") || !mHasPipFeature) {
+ return null;
+ }
+ long binderToken = Binder.clearCallingIdentity();
+ try {
+ return mPipOptional.map(pip ->
+ pip.startSwipePipToHome(componentName, activityInfo,
+ pictureInPictureParams, launcherRotation, shelfHeight))
+ .orElse(null);
+ } finally {
+ Binder.restoreCallingIdentity(binderToken);
+ }
+ }
+
+ @Override
+ public void stopSwipePipToHome(ComponentName componentName, Rect destinationBounds) {
+ if (!verifyCaller("stopSwipePipToHome") || !mHasPipFeature) {
+ return;
+ }
+ long binderToken = Binder.clearCallingIdentity();
+ try {
+ mPipOptional.ifPresent(pip -> pip.stopSwipePipToHome(
+ componentName, destinationBounds));
+ } finally {
+ Binder.restoreCallingIdentity(binderToken);
+ }
+ }
+
private boolean verifyCaller(String reason) {
final int callerId = Binder.getCallingUserHandle().getIdentifier();
if (callerId != mCurrentBoundedUserId) {