diff options
Diffstat (limited to 'libs')
4 files changed, 180 insertions, 6 deletions
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip2Module.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip2Module.java index 8eecf1c58db0..458ea05e620d 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip2Module.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip2Module.java @@ -74,13 +74,18 @@ public abstract class Pip2Module { ShellController shellController, DisplayController displayController, DisplayInsetsController displayInsetsController, - PipDisplayLayoutState pipDisplayLayoutState) { + PipBoundsState pipBoundsState, + PipBoundsAlgorithm pipBoundsAlgorithm, + PipDisplayLayoutState pipDisplayLayoutState, + PipScheduler pipScheduler, + @ShellMainThread ShellExecutor mainExecutor) { if (!PipUtils.isPip2ExperimentEnabled()) { return Optional.empty(); } else { return Optional.ofNullable(PipController.create( context, shellInit, shellController, displayController, displayInsetsController, - pipDisplayLayoutState)); + pipBoundsState, pipBoundsAlgorithm, pipDisplayLayoutState, pipScheduler, + mainExecutor)); } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipController.java index 186cb615f4ec..e73a85003881 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipController.java @@ -18,14 +18,31 @@ package com.android.wm.shell.pip2.phone; import static android.content.pm.PackageManager.FEATURE_PICTURE_IN_PICTURE; +import static com.android.wm.shell.common.ExecutorUtils.executeRemoteCallWithTaskPermission; +import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_PIP; + +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.view.InsetsState; +import android.view.SurfaceControl; + +import androidx.annotation.BinderThread; import com.android.internal.protolog.common.ProtoLog; import com.android.wm.shell.common.DisplayController; import com.android.wm.shell.common.DisplayInsetsController; import com.android.wm.shell.common.DisplayLayout; +import com.android.wm.shell.common.ExternalInterfaceBinder; +import com.android.wm.shell.common.RemoteCallable; +import com.android.wm.shell.common.ShellExecutor; +import com.android.wm.shell.common.pip.IPip; +import com.android.wm.shell.common.pip.IPipAnimationListener; +import com.android.wm.shell.common.pip.PipBoundsAlgorithm; +import com.android.wm.shell.common.pip.PipBoundsState; import com.android.wm.shell.common.pip.PipDisplayLayoutState; import com.android.wm.shell.common.pip.PipUtils; import com.android.wm.shell.protolog.ShellProtoLogGroup; @@ -37,32 +54,54 @@ import com.android.wm.shell.sysui.ShellInit; * Manages the picture-in-picture (PIP) UI and states for Phones. */ public class PipController implements ConfigurationChangeListener, - DisplayController.OnDisplaysChangedListener { + DisplayController.OnDisplaysChangedListener, RemoteCallable<PipController> { private static final String TAG = PipController.class.getSimpleName(); private Context mContext; private ShellController mShellController; private DisplayController mDisplayController; private DisplayInsetsController mDisplayInsetsController; + private PipBoundsState mPipBoundsState; + private PipBoundsAlgorithm mPipBoundsAlgorithm; private PipDisplayLayoutState mPipDisplayLayoutState; + private PipScheduler mPipScheduler; + private ShellExecutor mMainExecutor; private PipController(Context context, ShellInit shellInit, ShellController shellController, DisplayController displayController, DisplayInsetsController displayInsetsController, - PipDisplayLayoutState pipDisplayLayoutState) { + PipBoundsState pipBoundsState, + PipBoundsAlgorithm pipBoundsAlgorithm, + PipDisplayLayoutState pipDisplayLayoutState, + PipScheduler pipScheduler, + ShellExecutor mainExecutor) { mContext = context; mShellController = shellController; mDisplayController = displayController; mDisplayInsetsController = displayInsetsController; + mPipBoundsState = pipBoundsState; + mPipBoundsAlgorithm = pipBoundsAlgorithm; mPipDisplayLayoutState = pipDisplayLayoutState; + mPipScheduler = pipScheduler; + mMainExecutor = mainExecutor; if (PipUtils.isPip2ExperimentEnabled()) { shellInit.addInitCallback(this::onInit, this); } } + @Override + public Context getContext() { + return mContext; + } + + @Override + public ShellExecutor getRemoteCallExecutor() { + return mMainExecutor; + } + private void onInit() { // Ensure that we have the display info in case we get calls to update the bounds before the // listener calls back @@ -80,6 +119,10 @@ public class PipController implements ConfigurationChangeListener, .getDisplayLayout(mPipDisplayLayoutState.getDisplayId())); } }); + + // Allow other outside processes to bind to PiP controller using the key below. + mShellController.addExternalInterface(KEY_EXTRA_SHELL_PIP, + this::createExternalInterface, this); } /** @@ -90,16 +133,24 @@ public class PipController implements ConfigurationChangeListener, ShellController shellController, DisplayController displayController, DisplayInsetsController displayInsetsController, - PipDisplayLayoutState pipDisplayLayoutState) { + PipBoundsState pipBoundsState, + PipBoundsAlgorithm pipBoundsAlgorithm, + PipDisplayLayoutState pipDisplayLayoutState, + PipScheduler pipScheduler, + ShellExecutor mainExecutor) { if (!context.getPackageManager().hasSystemFeature(FEATURE_PICTURE_IN_PICTURE)) { ProtoLog.w(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE, "%s: Device doesn't support Pip feature", TAG); return null; } return new PipController(context, shellInit, shellController, displayController, - displayInsetsController, pipDisplayLayoutState); + displayInsetsController, pipBoundsState, pipBoundsAlgorithm, pipDisplayLayoutState, + pipScheduler, mainExecutor); } + private ExternalInterfaceBinder createExternalInterface() { + return new IPipImpl(this); + } @Override public void onConfigurationChanged(Configuration newConfiguration) { @@ -130,4 +181,86 @@ public class PipController implements ConfigurationChangeListener, private void onDisplayChanged(DisplayLayout layout) { mPipDisplayLayoutState.setDisplayLayout(layout); } + + private Rect getSwipePipToHomeBounds(ComponentName componentName, ActivityInfo activityInfo, + PictureInPictureParams pictureInPictureParams, + int launcherRotation, Rect hotseatKeepClearArea) { + ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE, + "getSwipePipToHomeBounds: %s", componentName); + mPipBoundsState.setBoundsStateForEntry(componentName, activityInfo, pictureInPictureParams, + mPipBoundsAlgorithm); + return mPipBoundsAlgorithm.getEntryDestinationBounds(); + } + + private void onSwipePipToHomeAnimationStart(int taskId, ComponentName componentName, + Rect destinationBounds, SurfaceControl overlay, Rect appBounds) { + ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE, + "onSwipePipToHomeAnimationStart: %s", componentName); + mPipScheduler.setInSwipePipToHomeTransition(true); + // TODO: cache the overlay if provided for reparenting later. + } + + /** + * The interface for calls from outside the host process. + */ + @BinderThread + private static class IPipImpl extends IPip.Stub implements ExternalInterfaceBinder { + private PipController mController; + + IPipImpl(PipController controller) { + mController = controller; + } + + /** + * Invalidates this instance, preventing future calls from updating the controller. + */ + @Override + public void invalidate() { + mController = null; + } + + @Override + public Rect startSwipePipToHome(ComponentName componentName, ActivityInfo activityInfo, + PictureInPictureParams pictureInPictureParams, int launcherRotation, + Rect keepClearArea) { + Rect[] result = new Rect[1]; + executeRemoteCallWithTaskPermission(mController, "startSwipePipToHome", + (controller) -> { + result[0] = controller.getSwipePipToHomeBounds(componentName, activityInfo, + pictureInPictureParams, launcherRotation, keepClearArea); + }, true /* blocking */); + return result[0]; + } + + @Override + public void stopSwipePipToHome(int taskId, ComponentName componentName, + Rect destinationBounds, SurfaceControl overlay, Rect appBounds) { + if (overlay != null) { + overlay.setUnreleasedWarningCallSite("PipController.stopSwipePipToHome"); + } + executeRemoteCallWithTaskPermission(mController, "stopSwipePipToHome", + (controller) -> controller.onSwipePipToHomeAnimationStart( + taskId, componentName, destinationBounds, overlay, appBounds)); + } + + @Override + public void abortSwipePipToHome(int taskId, ComponentName componentName) {} + + @Override + public void setShelfHeight(boolean visible, int height) {} + + @Override + public void setLauncherKeepClearAreaHeight(boolean visible, int height) {} + + @Override + public void setLauncherAppIconSize(int iconSizePx) {} + + @Override + public void setPipAnimationListener(IPipAnimationListener listener) { + // TODO: set a proper animation listener to update the Launcher state as needed. + } + + @Override + public void setPipAnimationTypeToAlpha() {} + } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipScheduler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipScheduler.java index 57b73b3019f4..895c793007a5 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipScheduler.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipScheduler.java @@ -63,6 +63,9 @@ public class PipScheduler { @Nullable private SurfaceControl mPinnedTaskLeash; + // true if Launcher has started swipe PiP to home animation + private boolean mInSwipePipToHomeTransition; + /** * Temporary PiP CUJ codes to schedule PiP related transitions directly from Shell. * This is used for a broadcast receiver to resolve intents. This should be removed once @@ -168,6 +171,14 @@ public class PipScheduler { mPipTransitionController.startResizeTransition(wct, onFinishResizeCallback); } + void setInSwipePipToHomeTransition(boolean inSwipePipToHome) { + mInSwipePipToHomeTransition = true; + } + + boolean isInSwipePipToHomeTransition() { + return mInSwipePipToHomeTransition; + } + void onExitPip() { mPipTaskToken = null; mPinnedTaskLeash = null; diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java index fbf4d13a0c19..dfb04758c851 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java @@ -152,6 +152,12 @@ public class PipTransition extends PipTransitionController { @NonNull Transitions.TransitionFinishCallback finishCallback) { if (transition == mEnterTransition) { mEnterTransition = null; + if (mPipScheduler.isInSwipePipToHomeTransition()) { + // If this is the second transition as a part of swipe PiP to home cuj, + // handle this transition as a special case with no-op animation. + return handleSwipePipToHomeTransition(info, startTransaction, finishTransaction, + finishCallback); + } if (isLegacyEnter(info)) { // If this is a legacy-enter-pip (auto-enter is off and PiP activity went to pause), // then we should run an ALPHA type (cross-fade) animation. @@ -207,6 +213,25 @@ public class PipTransition extends PipTransitionController { return true; } + private boolean handleSwipePipToHomeTransition(@NonNull TransitionInfo info, + @NonNull SurfaceControl.Transaction startTransaction, + @NonNull SurfaceControl.Transaction finishTransaction, + @NonNull Transitions.TransitionFinishCallback finishCallback) { + TransitionInfo.Change pipChange = getPipChange(info); + if (pipChange == null) { + return false; + } + mPipScheduler.setInSwipePipToHomeTransition(false); + mPipTaskToken = pipChange.getContainer(); + + // cache the PiP task token and leash + mPipScheduler.setPipTaskToken(mPipTaskToken); + + startTransaction.apply(); + finishCallback.onTransitionFinished(null); + return true; + } + private boolean startBoundsTypeEnterAnimation(@NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction startTransaction, @NonNull SurfaceControl.Transaction finishTransaction, |