Loading libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip2Module.java +7 −2 Original line number Diff line number Diff line Loading @@ -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)); } } Loading libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipController.java +137 −4 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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 Loading @@ -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); } /** Loading @@ -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) { Loading Loading @@ -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() {} } } libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipScheduler.java +11 −0 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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; Loading libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java +25 −0 Original line number Diff line number Diff line Loading @@ -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. Loading Loading @@ -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, Loading Loading
libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip2Module.java +7 −2 Original line number Diff line number Diff line Loading @@ -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)); } } Loading
libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipController.java +137 −4 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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 Loading @@ -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); } /** Loading @@ -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) { Loading Loading @@ -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() {} } }
libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipScheduler.java +11 −0 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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; Loading
libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java +25 −0 Original line number Diff line number Diff line Loading @@ -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. Loading Loading @@ -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, Loading