From c6876ff4c8005e27b794fc4eb7adc074d2f50ee0 Mon Sep 17 00:00:00 2001 From: Galia Peycheva Date: Fri, 11 Feb 2022 17:46:11 +0100 Subject: [PATCH] Implement expanded PiP on TV. - Launch into expanded PiP - Let user toggle expanded PiP in Menu - Update moving the PiP via DPAD for expanded PiP - Let app dynamically change the expanded PiP aspect ratio - Let app dynamically change the PiP aspect ratio - Let app dynamically enable/disable expanded PiP Bug: 203647003 Test: atest PinnedStackTests#testEnterExpandedPipAspectRatio Test: atest PinnedStackTests#testEnterExpandedPipAspectRatioMaxWidth Test: atest PinnedStackTests#testEnterExpandedPipAspectRatioMaxHeight Change-Id: Ie7de6a7fcc424b0c086fdae1f66aa8de42e53b0c --- .../android/view/IPinnedTaskListener.aidl | 5 + core/res/res/values-television/config.xml | 8 + core/res/res/values/symbols.xml | 2 + .../Shell/res/drawable/pip_ic_collapse.xml | 25 ++ .../Shell/res/drawable/pip_ic_expand.xml | 25 ++ .../Shell/res/layout/tv_pip_menu.xml | 35 ++- .../res/layout/tv_pip_menu_action_button.xml | 3 +- .../Shell/res/values/strings_tv.xml | 6 + .../android/wm/shell/dagger/TvPipModule.java | 26 +- .../pip/PinnedStackListenerForwarder.java | 17 ++ .../wm/shell/pip/PipBoundsAlgorithm.java | 6 +- .../android/wm/shell/pip/PipBoundsState.java | 12 +- .../wm/shell/pip/PipTaskOrganizer.java | 9 +- .../wm/shell/pip/PipTransitionController.java | 5 +- .../wm/shell/pip/tv/TvPipBoundsAlgorithm.java | 276 +++++++++++++++++- .../wm/shell/pip/tv/TvPipBoundsState.java | 166 +++++++++++ .../wm/shell/pip/tv/TvPipController.java | 154 ++++++---- .../shell/pip/tv/TvPipMenuActionButton.java | 9 +- .../wm/shell/pip/tv/TvPipMenuController.java | 42 ++- .../wm/shell/pip/tv/TvPipMenuView.java | 77 ++++- .../server/wm/ActivityClientController.java | 22 +- .../server/wm/ActivityTaskManagerService.java | 10 +- .../server/wm/PinnedTaskController.java | 39 ++- .../core/java/com/android/server/wm/Task.java | 23 +- .../server/wm/WindowManagerService.java | 6 + 25 files changed, 869 insertions(+), 139 deletions(-) create mode 100644 libs/WindowManager/Shell/res/drawable/pip_ic_collapse.xml create mode 100644 libs/WindowManager/Shell/res/drawable/pip_ic_expand.xml create mode 100644 libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBoundsState.java diff --git a/core/java/android/view/IPinnedTaskListener.aidl b/core/java/android/view/IPinnedTaskListener.aidl index c31e67e59a997..7d39ffe182c76 100644 --- a/core/java/android/view/IPinnedTaskListener.aidl +++ b/core/java/android/view/IPinnedTaskListener.aidl @@ -61,4 +61,9 @@ oneway interface IPinnedTaskListener { * Called by the window manager when the aspect ratio is reset. */ void onAspectRatioChanged(float aspectRatio); + + /** + * Called by the window manager when the expanded aspect ratio is reset. + */ + void onExpandedAspectRatioChanged(float aspectRatio); } diff --git a/core/res/res/values-television/config.xml b/core/res/res/values-television/config.xml index 92bea34d55242..009df4ab553a0 100644 --- a/core/res/res/values-television/config.xml +++ b/core/res/res/values-television/config.xml @@ -37,6 +37,14 @@ Currently, this maps to Gravity.BOTTOM | Gravity.RIGHT --> 0x55 + + 110dp + + + 110dp + false diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index c63e5436c5429..2a93e4c04f177 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -415,6 +415,8 @@ + + diff --git a/libs/WindowManager/Shell/res/drawable/pip_ic_collapse.xml b/libs/WindowManager/Shell/res/drawable/pip_ic_collapse.xml new file mode 100644 index 0000000000000..63e2a4035cbfc --- /dev/null +++ b/libs/WindowManager/Shell/res/drawable/pip_ic_collapse.xml @@ -0,0 +1,25 @@ + + + + + diff --git a/libs/WindowManager/Shell/res/drawable/pip_ic_expand.xml b/libs/WindowManager/Shell/res/drawable/pip_ic_expand.xml new file mode 100644 index 0000000000000..758b92c4f4da6 --- /dev/null +++ b/libs/WindowManager/Shell/res/drawable/pip_ic_expand.xml @@ -0,0 +1,25 @@ + + + + + diff --git a/libs/WindowManager/Shell/res/layout/tv_pip_menu.xml b/libs/WindowManager/Shell/res/layout/tv_pip_menu.xml index b56b114e9a4c7..b826d03bf7650 100644 --- a/libs/WindowManager/Shell/res/layout/tv_pip_menu.xml +++ b/libs/WindowManager/Shell/res/layout/tv_pip_menu.xml @@ -20,25 +20,36 @@ android:layout_width="match_parent" android:layout_height="match_parent"> - + + + + + + + + diff --git a/libs/WindowManager/Shell/res/layout/tv_pip_menu_action_button.xml b/libs/WindowManager/Shell/res/layout/tv_pip_menu_action_button.xml index f9d0968a16df8..a86a145250228 100644 --- a/libs/WindowManager/Shell/res/layout/tv_pip_menu_action_button.xml +++ b/libs/WindowManager/Shell/res/layout/tv_pip_menu_action_button.xml @@ -20,8 +20,7 @@ android:id="@+id/button" android:layout_width="@dimen/pip_menu_button_size" android:layout_height="@dimen/pip_menu_button_size" - android:layout_marginStart="@dimen/pip_menu_button_margin" - android:layout_marginEnd="@dimen/pip_menu_button_margin" + android:layout_margin="@dimen/pip_menu_button_margin" android:background="@drawable/tv_pip_button_bg" android:focusable="true"> diff --git a/libs/WindowManager/Shell/res/values/strings_tv.xml b/libs/WindowManager/Shell/res/values/strings_tv.xml index 730d80894c419..c7b8a130e141a 100644 --- a/libs/WindowManager/Shell/res/values/strings_tv.xml +++ b/libs/WindowManager/Shell/res/values/strings_tv.xml @@ -33,5 +33,11 @@ Move PIP + + + Expand PIP + + + Collapse PIP diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/TvPipModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/TvPipModule.java index f91d7e2d28e82..4f160427dca66 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/TvPipModule.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/TvPipModule.java @@ -30,7 +30,6 @@ import com.android.wm.shell.common.annotations.ShellMainThread; import com.android.wm.shell.legacysplitscreen.LegacySplitScreenController; import com.android.wm.shell.pip.Pip; import com.android.wm.shell.pip.PipAnimationController; -import com.android.wm.shell.pip.PipBoundsState; import com.android.wm.shell.pip.PipMediaController; import com.android.wm.shell.pip.PipSnapAlgorithm; import com.android.wm.shell.pip.PipSurfaceTransactionHelper; @@ -39,6 +38,7 @@ import com.android.wm.shell.pip.PipTransitionController; import com.android.wm.shell.pip.PipTransitionState; import com.android.wm.shell.pip.PipUiEventLogger; import com.android.wm.shell.pip.tv.TvPipBoundsAlgorithm; +import com.android.wm.shell.pip.tv.TvPipBoundsState; import com.android.wm.shell.pip.tv.TvPipController; import com.android.wm.shell.pip.tv.TvPipMenuController; import com.android.wm.shell.pip.tv.TvPipNotificationController; @@ -60,7 +60,7 @@ public abstract class TvPipModule { @Provides static Optional providePip( Context context, - PipBoundsState pipBoundsState, + TvPipBoundsState tvPipBoundsState, TvPipBoundsAlgorithm tvPipBoundsAlgorithm, PipTaskOrganizer pipTaskOrganizer, TvPipMenuController tvPipMenuController, @@ -73,7 +73,7 @@ public abstract class TvPipModule { return Optional.of( TvPipController.create( context, - pipBoundsState, + tvPipBoundsState, tvPipBoundsAlgorithm, pipTaskOrganizer, pipTransitionController, @@ -94,14 +94,14 @@ public abstract class TvPipModule { @WMSingleton @Provides static TvPipBoundsAlgorithm provideTvPipBoundsAlgorithm(Context context, - PipBoundsState pipBoundsState, PipSnapAlgorithm pipSnapAlgorithm) { - return new TvPipBoundsAlgorithm(context, pipBoundsState, pipSnapAlgorithm); + TvPipBoundsState tvPipBoundsState, PipSnapAlgorithm pipSnapAlgorithm) { + return new TvPipBoundsAlgorithm(context, tvPipBoundsState, pipSnapAlgorithm); } @WMSingleton @Provides - static PipBoundsState providePipBoundsState(Context context) { - return new PipBoundsState(context); + static TvPipBoundsState provideTvPipBoundsState(Context context) { + return new TvPipBoundsState(context); } // Handler needed for loadDrawableAsync() in PipControlsViewController @@ -111,8 +111,8 @@ public abstract class TvPipModule { Transitions transitions, ShellTaskOrganizer shellTaskOrganizer, PipAnimationController pipAnimationController, TvPipBoundsAlgorithm tvPipBoundsAlgorithm, - PipBoundsState pipBoundsState, TvPipMenuController pipMenuController) { - return new TvPipTransition(pipBoundsState, pipMenuController, + TvPipBoundsState tvPipBoundsState, TvPipMenuController pipMenuController) { + return new TvPipTransition(tvPipBoundsState, pipMenuController, tvPipBoundsAlgorithm, pipAnimationController, transitions, shellTaskOrganizer); } @@ -120,11 +120,11 @@ public abstract class TvPipModule { @Provides static TvPipMenuController providesTvPipMenuController( Context context, - PipBoundsState pipBoundsState, + TvPipBoundsState tvPipBoundsState, SystemWindows systemWindows, PipMediaController pipMediaController, @ShellMainThread Handler mainHandler) { - return new TvPipMenuController(context, pipBoundsState, systemWindows, pipMediaController, + return new TvPipMenuController(context, tvPipBoundsState, systemWindows, pipMediaController, mainHandler); } @@ -155,7 +155,7 @@ public abstract class TvPipModule { static PipTaskOrganizer providePipTaskOrganizer(Context context, TvPipMenuController tvPipMenuController, SyncTransactionQueue syncTransactionQueue, - PipBoundsState pipBoundsState, + TvPipBoundsState tvPipBoundsState, PipTransitionState pipTransitionState, TvPipBoundsAlgorithm tvPipBoundsAlgorithm, PipAnimationController pipAnimationController, @@ -167,7 +167,7 @@ public abstract class TvPipModule { PipUiEventLogger pipUiEventLogger, ShellTaskOrganizer shellTaskOrganizer, @ShellMainThread ShellExecutor mainExecutor) { return new PipTaskOrganizer(context, - syncTransactionQueue, pipTransitionState, pipBoundsState, tvPipBoundsAlgorithm, + syncTransactionQueue, pipTransitionState, tvPipBoundsState, tvPipBoundsAlgorithm, tvPipMenuController, pipAnimationController, pipSurfaceTransactionHelper, pipTransitionController, splitScreenOptional, newSplitScreenOptional, displayController, pipUiEventLogger, shellTaskOrganizer, mainExecutor); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PinnedStackListenerForwarder.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PinnedStackListenerForwarder.java index b3b1ba7cd1c1f..3fefc4a0e0bfa 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PinnedStackListenerForwarder.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PinnedStackListenerForwarder.java @@ -90,6 +90,12 @@ public class PinnedStackListenerForwarder { } } + private void onExpandedAspectRatioChanged(float aspectRatio) { + for (PinnedTaskListener listener : mListeners) { + listener.onExpandedAspectRatioChanged(aspectRatio); + } + } + @BinderThread private class PinnedTaskListenerImpl extends IPinnedTaskListener.Stub { @Override @@ -126,6 +132,15 @@ public class PinnedStackListenerForwarder { PinnedStackListenerForwarder.this.onAspectRatioChanged(aspectRatio); }); } + + @Override + public void onExpandedAspectRatioChanged(float aspectRatio) { + mMainExecutor.execute(() -> { + PinnedStackListenerForwarder.this.onExpandedAspectRatioChanged(aspectRatio); + }); + } + + } /** @@ -142,5 +157,7 @@ public class PinnedStackListenerForwarder { public void onActivityHidden(ComponentName componentName) {} public void onAspectRatioChanged(float aspectRatio) {} + + public void onExpandedAspectRatioChanged(float aspectRatio) {} } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsAlgorithm.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsAlgorithm.java index 1a3c51ea4f921..e29dde2726e39 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsAlgorithm.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsAlgorithm.java @@ -44,7 +44,7 @@ public class PipBoundsAlgorithm { private static final String TAG = PipBoundsAlgorithm.class.getSimpleName(); private static final float INVALID_SNAP_FRACTION = -1f; - protected final @NonNull PipBoundsState mPipBoundsState; + private final @NonNull PipBoundsState mPipBoundsState; private final PipSnapAlgorithm mSnapAlgorithm; private float mDefaultSizePercent; @@ -56,7 +56,7 @@ public class PipBoundsAlgorithm { private int mDefaultStackGravity; private int mDefaultMinSize; private int mOverridableMinSize; - private Point mScreenEdgeInsets; + protected Point mScreenEdgeInsets; public PipBoundsAlgorithm(Context context, @NonNull PipBoundsState pipBoundsState, @NonNull PipSnapAlgorithm pipSnapAlgorithm) { @@ -73,7 +73,7 @@ public class PipBoundsAlgorithm { /** * TODO: move the resources to SysUI package. */ - private void reloadResources(Context context) { + protected void reloadResources(Context context) { final Resources res = context.getResources(); mDefaultAspectRatio = res.getFloat( com.android.internal.R.dimen.config_pictureInPictureDefaultAspectRatio); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsState.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsState.java index b3558ad4b91ef..bebf2cad83a42 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsState.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsState.java @@ -20,9 +20,11 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityTaskManager; +import android.app.PictureInPictureParams; import android.app.PictureInPictureUiState; import android.content.ComponentName; import android.content.Context; +import android.content.pm.ActivityInfo; import android.graphics.Point; import android.graphics.Rect; import android.os.RemoteException; @@ -46,7 +48,7 @@ import java.util.function.Consumer; /** * Singleton source of truth for the current state of PIP bounds. */ -public final class PipBoundsState { +public class PipBoundsState { public static final int STASH_TYPE_NONE = 0; public static final int STASH_TYPE_LEFT = 1; public static final int STASH_TYPE_RIGHT = 2; @@ -368,11 +370,11 @@ public final class PipBoundsState { /** * Initialize states when first entering PiP. */ - public void setBoundsStateForEntry(ComponentName componentName, float aspectRatio, - Size overrideMinSize) { + public void setBoundsStateForEntry(ComponentName componentName, ActivityInfo activityInfo, + PictureInPictureParams params, PipBoundsAlgorithm pipBoundsAlgorithm) { setLastPipComponentName(componentName); - setAspectRatio(aspectRatio); - setOverrideMinSize(overrideMinSize); + setAspectRatio(pipBoundsAlgorithm.getAspectRatioOrDefault(params)); + setOverrideMinSize(pipBoundsAlgorithm.getMinimalSize(activityInfo)); } /** Returns whether the shelf is currently showing. */ 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 6b0d7f5fa4619..67b39839826c3 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 @@ -369,11 +369,10 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, return mLeash; } - private void setBoundsStateForEntry(ComponentName componentName, PictureInPictureParams params, - ActivityInfo activityInfo) { - mPipBoundsState.setBoundsStateForEntry(componentName, - mPipBoundsAlgorithm.getAspectRatioOrDefault(params), - mPipBoundsAlgorithm.getMinimalSize(activityInfo)); + private void setBoundsStateForEntry(ComponentName componentName, + PictureInPictureParams params, ActivityInfo activityInfo) { + mPipBoundsState.setBoundsStateForEntry(componentName, activityInfo, params, + mPipBoundsAlgorithm); } /** diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java index 22b3ef3bfe0b1..3403fb5aa9400 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java @@ -187,9 +187,8 @@ public abstract class PipTransitionController implements Transitions.TransitionH protected void setBoundsStateForEntry(ComponentName componentName, PictureInPictureParams params, ActivityInfo activityInfo) { - mPipBoundsState.setBoundsStateForEntry(componentName, - mPipBoundsAlgorithm.getAspectRatioOrDefault(params), - mPipBoundsAlgorithm.getMinimalSize(activityInfo)); + mPipBoundsState.setBoundsStateForEntry(componentName, activityInfo, params, + mPipBoundsAlgorithm); } /** diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBoundsAlgorithm.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBoundsAlgorithm.java index 33f3bfb7b2668..8ab78e64e2f6d 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBoundsAlgorithm.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBoundsAlgorithm.java @@ -16,15 +16,26 @@ package com.android.wm.shell.pip.tv; +import static android.view.KeyEvent.KEYCODE_DPAD_DOWN; +import static android.view.KeyEvent.KEYCODE_DPAD_LEFT; +import static android.view.KeyEvent.KEYCODE_DPAD_RIGHT; +import static android.view.KeyEvent.KEYCODE_DPAD_UP; + +import static com.android.wm.shell.pip.tv.TvPipBoundsState.ORIENTATION_HORIZONTAL; +import static com.android.wm.shell.pip.tv.TvPipBoundsState.ORIENTATION_UNDETERMINED; +import static com.android.wm.shell.pip.tv.TvPipBoundsState.ORIENTATION_VERTICAL; + import android.content.Context; +import android.content.res.Resources; import android.graphics.Rect; import android.util.Log; +import android.util.Size; import android.view.Gravity; import androidx.annotation.NonNull; +import com.android.wm.shell.common.DisplayLayout; import com.android.wm.shell.pip.PipBoundsAlgorithm; -import com.android.wm.shell.pip.PipBoundsState; import com.android.wm.shell.pip.PipSnapAlgorithm; /** @@ -33,37 +44,282 @@ import com.android.wm.shell.pip.PipSnapAlgorithm; public class TvPipBoundsAlgorithm extends PipBoundsAlgorithm { private static final String TAG = TvPipBoundsAlgorithm.class.getSimpleName(); - private static final boolean DEBUG = false; + private static final boolean DEBUG = TvPipController.DEBUG; + + private final @android.annotation.NonNull TvPipBoundsState mTvPipBoundsState; + + private int mFixedExpandedHeightInPx; + private int mFixedExpandedWidthInPx; public TvPipBoundsAlgorithm(Context context, - @NonNull PipBoundsState pipBoundsState, + @NonNull TvPipBoundsState tvPipBoundsState, @NonNull PipSnapAlgorithm pipSnapAlgorithm) { - super(context, pipBoundsState, pipSnapAlgorithm); + super(context, tvPipBoundsState, pipSnapAlgorithm); + this.mTvPipBoundsState = tvPipBoundsState; + } + + @Override + protected void reloadResources(Context context) { + super.reloadResources(context); + final Resources res = context.getResources(); + mFixedExpandedHeightInPx = res.getDimensionPixelSize( + com.android.internal.R.dimen.config_pictureInPictureExpandedHorizontalHeight); + mFixedExpandedWidthInPx = res.getDimensionPixelSize( + com.android.internal.R.dimen.config_pictureInPictureExpandedVerticalWidth); + } + + /** Returns the destination bounds to place the PIP window on entry. */ + @Override + public Rect getEntryDestinationBounds() { + if (DEBUG) Log.d(TAG, "getEntryDestinationBounds()"); + if (mTvPipBoundsState.getTvExpandedAspectRatio() != 0 + && !mTvPipBoundsState.isTvPipManuallyCollapsed()) { + updatePositionOnExpandToggled(Gravity.NO_GRAVITY, true); + } + return getTvPipBounds(true); + } + + /** Returns the current bounds adjusted to the new aspect ratio, if valid. */ + @Override + public Rect getAdjustedDestinationBounds(Rect currentBounds, float newAspectRatio) { + if (DEBUG) Log.d(TAG, "getAdjustedDestinationBounds: " + newAspectRatio); + return getTvPipBounds(mTvPipBoundsState.isTvPipExpanded()); } /** * The normal bounds at a different position on the screen. */ - public Rect getTvNormalBounds(int gravity) { + public Rect getTvNormalBounds() { Rect normalBounds = getNormalBounds(); Rect insetBounds = new Rect(); getInsetBounds(insetBounds); - if (mPipBoundsState.isImeShowing()) { - if (DEBUG) Log.d(TAG, "IME showing, height: " + mPipBoundsState.getImeHeight()); - insetBounds.bottom -= mPipBoundsState.getImeHeight(); + if (mTvPipBoundsState.isImeShowing()) { + if (DEBUG) Log.d(TAG, "IME showing, height: " + mTvPipBoundsState.getImeHeight()); + insetBounds.bottom -= mTvPipBoundsState.getImeHeight(); } Rect result = new Rect(); - Gravity.apply(gravity, normalBounds.width(), normalBounds.height(), insetBounds, result); + Gravity.apply(mTvPipBoundsState.getTvPipGravity(), normalBounds.width(), + normalBounds.height(), insetBounds, result); if (DEBUG) { Log.d(TAG, "normalBounds: " + normalBounds.toShortString()); Log.d(TAG, "insetBounds: " + insetBounds.toShortString()); - Log.d(TAG, "gravity: " + Gravity.toString(gravity)); + Log.d(TAG, "gravity: " + Gravity.toString(mTvPipBoundsState.getTvPipGravity())); Log.d(TAG, "resultBounds: " + result.toShortString()); } + mTvPipBoundsState.setTvPipExpanded(false); + return result; } + + /** + * @return previous gravity if it is to be saved, or Gravity.NO_GRAVITY if not. + */ + int updatePositionOnExpandToggled(int previousGravity, boolean expanding) { + if (DEBUG) { + Log.d(TAG, "updatePositionOnExpandToggle(), expanding: " + expanding + + ", mOrientation: " + mTvPipBoundsState.getTvFixedPipOrientation() + + ", previous gravity: " + Gravity.toString(previousGravity)); + } + + if (!mTvPipBoundsState.isTvExpandedPipEnabled()) { + return Gravity.NO_GRAVITY; + } + + if (expanding && mTvPipBoundsState.getTvFixedPipOrientation() == ORIENTATION_UNDETERMINED) { + float expandedRatio = mTvPipBoundsState.getTvExpandedAspectRatio(); + if (expandedRatio == 0) { + return Gravity.NO_GRAVITY; + } + if (expandedRatio < 1) { + mTvPipBoundsState.setTvFixedPipOrientation(ORIENTATION_VERTICAL); + } else { + mTvPipBoundsState.setTvFixedPipOrientation(ORIENTATION_HORIZONTAL); + } + + } + + int gravityToSave = Gravity.NO_GRAVITY; + int currentGravity = mTvPipBoundsState.getTvPipGravity(); + int updatedGravity; + + if (expanding) { + // save collapsed gravity + gravityToSave = mTvPipBoundsState.getTvPipGravity(); + + if (mTvPipBoundsState.getTvFixedPipOrientation() == ORIENTATION_HORIZONTAL) { + updatedGravity = + Gravity.CENTER_HORIZONTAL | (currentGravity + & Gravity.VERTICAL_GRAVITY_MASK); + } else { + updatedGravity = + Gravity.CENTER_VERTICAL | (currentGravity + & Gravity.HORIZONTAL_GRAVITY_MASK); + } + } else { + if (previousGravity != Gravity.NO_GRAVITY) { + // The pip hasn't been moved since expanding, + // go back to previous collapsed position. + updatedGravity = previousGravity; + } else { + if (mTvPipBoundsState.getTvFixedPipOrientation() == ORIENTATION_HORIZONTAL) { + updatedGravity = + Gravity.RIGHT | (currentGravity & Gravity.VERTICAL_GRAVITY_MASK); + } else { + updatedGravity = + Gravity.BOTTOM | (currentGravity & Gravity.HORIZONTAL_GRAVITY_MASK); + } + } + } + mTvPipBoundsState.setTvPipGravity(updatedGravity); + if (DEBUG) Log.d(TAG, "new gravity: " + Gravity.toString(updatedGravity)); + + return gravityToSave; + } + + /** + * @return true if position changed + */ + boolean updatePosition(int keycode) { + if (DEBUG) Log.d(TAG, "updatePosition, keycode: " + keycode); + + // Check if position change is valid + if (mTvPipBoundsState.isTvPipExpanded()) { + int mOrientation = mTvPipBoundsState.getTvFixedPipOrientation(); + if (mOrientation == ORIENTATION_VERTICAL + && (keycode == KEYCODE_DPAD_UP || keycode == KEYCODE_DPAD_DOWN) + || mOrientation == ORIENTATION_HORIZONTAL + && (keycode == KEYCODE_DPAD_RIGHT || keycode == KEYCODE_DPAD_LEFT)) { + return false; + } + } + + int currentGravity = mTvPipBoundsState.getTvPipGravity(); + int updatedGravity; + // First axis + switch (keycode) { + case KEYCODE_DPAD_UP: + updatedGravity = Gravity.TOP; + break; + case KEYCODE_DPAD_DOWN: + updatedGravity = Gravity.BOTTOM; + break; + case KEYCODE_DPAD_LEFT: + updatedGravity = Gravity.LEFT; + break; + case KEYCODE_DPAD_RIGHT: + updatedGravity = Gravity.RIGHT; + break; + default: + updatedGravity = currentGravity; + } + + // Second axis + switch (keycode) { + case KEYCODE_DPAD_UP: + case KEYCODE_DPAD_DOWN: + if (mTvPipBoundsState.isTvPipExpanded()) { + updatedGravity |= Gravity.CENTER_HORIZONTAL; + } else { + updatedGravity |= (currentGravity & Gravity.HORIZONTAL_GRAVITY_MASK); + } + break; + case KEYCODE_DPAD_LEFT: + case KEYCODE_DPAD_RIGHT: + if (mTvPipBoundsState.isTvPipExpanded()) { + updatedGravity |= Gravity.CENTER_VERTICAL; + } else { + updatedGravity |= (currentGravity & Gravity.VERTICAL_GRAVITY_MASK); + } + break; + default: + break; + } + + if (updatedGravity != currentGravity) { + mTvPipBoundsState.setTvPipGravity(updatedGravity); + if (DEBUG) Log.d(TAG, "new gravity: " + Gravity.toString(updatedGravity)); + return true; + } + return false; + } + + /** + * Calculates the PiP bounds. + */ + public Rect getTvPipBounds(boolean expandedIfPossible) { + if (DEBUG) { + Log.d(TAG, "getExpandedBoundsIfPossible with gravity " + + Gravity.toString(mTvPipBoundsState.getTvPipGravity()) + + ", fixed orientation: " + mTvPipBoundsState.getTvFixedPipOrientation()); + } + + if (!mTvPipBoundsState.isTvExpandedPipEnabled() || !expandedIfPossible) { + return getTvNormalBounds(); + } + + DisplayLayout displayLayout = mTvPipBoundsState.getDisplayLayout(); + float expandedRatio = mTvPipBoundsState.getTvExpandedAspectRatio(); // width / height + Size expandedSize; + if (expandedRatio == 0) { + Log.d(TAG, "Expanded mode not supported"); + return getTvNormalBounds(); + } else if (expandedRatio < 1) { + // vertical + if (mTvPipBoundsState.getTvFixedPipOrientation() == ORIENTATION_HORIZONTAL) { + expandedSize = mTvPipBoundsState.getTvExpandedSize(); + } else { + int maxHeight = displayLayout.height() - (2 * mScreenEdgeInsets.y); + float aspectRatioHeight = mFixedExpandedWidthInPx / expandedRatio; + + if (maxHeight > aspectRatioHeight) { + if (DEBUG) Log.d(TAG, "Accommodate aspect ratio"); + expandedSize = new Size(mFixedExpandedWidthInPx, (int) aspectRatioHeight); + } else { + if (DEBUG) Log.d(TAG, "Aspect ratio is too extreme, use max size"); + expandedSize = new Size(mFixedExpandedWidthInPx, maxHeight); + } + } + } else { + // horizontal + if (mTvPipBoundsState.getTvFixedPipOrientation() == ORIENTATION_VERTICAL) { + expandedSize = mTvPipBoundsState.getTvExpandedSize(); + } else { + int maxWidth = displayLayout.width() - (2 * mScreenEdgeInsets.x); + float aspectRatioWidth = mFixedExpandedHeightInPx * expandedRatio; + if (maxWidth > aspectRatioWidth) { + if (DEBUG) Log.d(TAG, "Accommodate aspect ratio"); + expandedSize = new Size((int) aspectRatioWidth, mFixedExpandedHeightInPx); + } else { + if (DEBUG) Log.d(TAG, "Aspect ratio is too extreme, use max size"); + expandedSize = new Size(maxWidth, mFixedExpandedHeightInPx); + } + } + } + + if (expandedSize == null) { + return getTvNormalBounds(); + } + + if (DEBUG) { + Log.d(TAG, "expanded size, width: " + expandedSize.getWidth() + + ", height: " + expandedSize.getHeight()); + } + + Rect insetBounds = new Rect(); + getInsetBounds(insetBounds); + + Rect expandedBounds = new Rect(); + Gravity.apply(mTvPipBoundsState.getTvPipGravity(), expandedSize.getWidth(), + expandedSize.getHeight(), insetBounds, expandedBounds); + if (DEBUG) Log.d(TAG, "expanded bounds: " + expandedBounds.toShortString()); + + mTvPipBoundsState.setTvExpandedSize(expandedSize); + mTvPipBoundsState.setTvPipExpanded(true); + return expandedBounds; + } + } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBoundsState.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBoundsState.java new file mode 100644 index 0000000000000..9370e33fce656 --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBoundsState.java @@ -0,0 +1,166 @@ +/* + * Copyright (C) 2022 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.wm.shell.pip.tv; + +import android.annotation.IntDef; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.app.PictureInPictureParams; +import android.content.ComponentName; +import android.content.Context; +import android.content.pm.ActivityInfo; +import android.content.pm.PackageManager; +import android.util.Size; +import android.view.Gravity; + +import com.android.wm.shell.pip.PipBoundsAlgorithm; +import com.android.wm.shell.pip.PipBoundsState; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * TV specific values of the current state of the PIP bounds. + */ +public class TvPipBoundsState extends PipBoundsState { + + public static final int ORIENTATION_UNDETERMINED = 0; + public static final int ORIENTATION_VERTICAL = 1; + public static final int ORIENTATION_HORIZONTAL = 2; + + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = {"ORIENTATION_"}, value = { + ORIENTATION_UNDETERMINED, + ORIENTATION_VERTICAL, + ORIENTATION_HORIZONTAL + }) + public @interface Orientation { + } + + public static final int DEFAULT_TV_GRAVITY = Gravity.BOTTOM | Gravity.RIGHT; + + private boolean mIsTvExpandedPipEnabled; + private boolean mIsTvPipExpanded; + private boolean mTvPipManuallyCollapsed; + private float mTvExpandedAspectRatio; + private @Orientation int mTvFixedPipOrientation; + private int mTvPipGravity; + private @Nullable Size mTvExpandedSize; + + + public TvPipBoundsState(@NonNull Context context) { + super(context); + setIsTvExpandedPipEnabled(context.getPackageManager().hasSystemFeature( + PackageManager.FEATURE_EXPANDED_PICTURE_IN_PICTURE)); + } + + /** + * Initialize states when first entering PiP. + */ + @Override + public void setBoundsStateForEntry(ComponentName componentName, ActivityInfo activityInfo, + PictureInPictureParams params, PipBoundsAlgorithm pipBoundsAlgorithm) { + super.setBoundsStateForEntry(componentName, activityInfo, params, pipBoundsAlgorithm); + setTvExpandedAspectRatio(params.getExpandedAspectRatio(), true); + } + + /** Resets the TV PiP state for a new activity. */ + public void resetTvPipState() { + mTvFixedPipOrientation = ORIENTATION_UNDETERMINED; + mTvPipGravity = DEFAULT_TV_GRAVITY; + } + + /** Set the tv expanded bounds of PIP */ + public void setTvExpandedSize(@Nullable Size bounds) { + mTvExpandedSize = bounds; + } + + /** Get the PIP tv expanded bounds. */ + @Nullable + public Size getTvExpandedSize() { + return mTvExpandedSize; + } + + /** Set the PIP aspect ratio for the expanded PIP (TV) that is desired by the app. */ + public void setTvExpandedAspectRatio(float aspectRatio, boolean override) { + if (override || mTvFixedPipOrientation == ORIENTATION_UNDETERMINED || aspectRatio == 0) { + mTvExpandedAspectRatio = aspectRatio; + resetTvPipState(); + return; + } + if ((aspectRatio > 1 && mTvFixedPipOrientation == ORIENTATION_HORIZONTAL) + || (aspectRatio <= 1 && mTvFixedPipOrientation == ORIENTATION_VERTICAL)) { + mTvExpandedAspectRatio = aspectRatio; + } + } + + /** Get the PIP aspect ratio for the expanded PIP (TV) that is desired by the app. */ + public float getTvExpandedAspectRatio() { + return mTvExpandedAspectRatio; + } + + /** Sets the orientation the expanded TV PiP activity has been fixed to. */ + public void setTvFixedPipOrientation(@Orientation int orientation) { + mTvFixedPipOrientation = orientation; + } + + /** Returns the fixed orientation of the expanded PiP on TV. */ + @Orientation + public int getTvFixedPipOrientation() { + return mTvFixedPipOrientation; + } + + /** Sets the current gravity of the TV PiP. */ + public void setTvPipGravity(int gravity) { + mTvPipGravity = gravity; + } + + /** Returns the current gravity of the TV PiP. */ + public int getTvPipGravity() { + return mTvPipGravity; + } + + /** Sets whether the TV PiP is currently expanded. */ + public void setTvPipExpanded(boolean expanded) { + mIsTvPipExpanded = expanded; + } + + /** Returns whether the TV PiP is currently expanded. */ + public boolean isTvPipExpanded() { + return mIsTvPipExpanded; + } + + /** Sets whether the user has manually collapsed the TV PiP. */ + public void setTvPipManuallyCollapsed(boolean collapsed) { + mTvPipManuallyCollapsed = collapsed; + } + + /** Returns whether the user has manually collapsed the TV PiP. */ + public boolean isTvPipManuallyCollapsed() { + return mTvPipManuallyCollapsed; + } + + /** Sets whether expanded PiP is supported by the device. */ + public void setIsTvExpandedPipEnabled(boolean enabled) { + mIsTvExpandedPipEnabled = enabled; + } + + /** Returns whether expanded PiP is supported by the device. */ + public boolean isTvExpandedPipEnabled() { + return mIsTvExpandedPipEnabled; + } +} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipController.java index de53939c01db2..5996acd269d23 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipController.java @@ -18,10 +18,6 @@ package com.android.wm.shell.pip.tv; import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; -import static android.view.KeyEvent.KEYCODE_DPAD_DOWN; -import static android.view.KeyEvent.KEYCODE_DPAD_LEFT; -import static android.view.KeyEvent.KEYCODE_DPAD_RIGHT; -import static android.view.KeyEvent.KEYCODE_DPAD_UP; import android.annotation.IntDef; import android.app.ActivityManager; @@ -47,7 +43,6 @@ import com.android.wm.shell.common.TaskStackListenerCallback; import com.android.wm.shell.common.TaskStackListenerImpl; import com.android.wm.shell.pip.PinnedStackListenerForwarder; import com.android.wm.shell.pip.Pip; -import com.android.wm.shell.pip.PipBoundsState; import com.android.wm.shell.pip.PipMediaController; import com.android.wm.shell.pip.PipTaskOrganizer; import com.android.wm.shell.pip.PipTransitionController; @@ -69,7 +64,7 @@ public class TvPipController implements PipTransitionController.PipTransitionCal @IntDef(prefix = { "STATE_" }, value = { STATE_NO_PIP, STATE_PIP, - STATE_PIP_MENU + STATE_PIP_MENU, }) public @interface State {} @@ -89,11 +84,9 @@ public class TvPipController implements PipTransitionController.PipTransitionCal */ private static final int STATE_PIP_MENU = 2; - private static final int DEFAULT_GRAVITY = Gravity.BOTTOM | Gravity.RIGHT; - private final Context mContext; - private final PipBoundsState mPipBoundsState; + private final TvPipBoundsState mTvPipBoundsState; private final TvPipBoundsAlgorithm mTvPipBoundsAlgorithm; private final PipTaskOrganizer mPipTaskOrganizer; private final PipMediaController mPipMediaController; @@ -103,14 +96,14 @@ public class TvPipController implements PipTransitionController.PipTransitionCal private final TvPipImpl mImpl = new TvPipImpl(); private @State int mState = STATE_NO_PIP; - private @Gravity.GravityFlags int mGravity = DEFAULT_GRAVITY; + private int mPreviousGravity = TvPipBoundsState.DEFAULT_TV_GRAVITY; private int mPinnedTaskId = NONEXISTENT_TASK_ID; private int mResizeAnimationDuration; public static Pip create( Context context, - PipBoundsState pipBoundsState, + TvPipBoundsState tvPipBoundsState, TvPipBoundsAlgorithm tvPipBoundsAlgorithm, PipTaskOrganizer pipTaskOrganizer, PipTransitionController pipTransitionController, @@ -122,7 +115,7 @@ public class TvPipController implements PipTransitionController.PipTransitionCal ShellExecutor mainExecutor) { return new TvPipController( context, - pipBoundsState, + tvPipBoundsState, tvPipBoundsAlgorithm, pipTaskOrganizer, pipTransitionController, @@ -136,7 +129,7 @@ public class TvPipController implements PipTransitionController.PipTransitionCal private TvPipController( Context context, - PipBoundsState pipBoundsState, + TvPipBoundsState tvPipBoundsState, TvPipBoundsAlgorithm tvPipBoundsAlgorithm, PipTaskOrganizer pipTaskOrganizer, PipTransitionController pipTransitionController, @@ -149,9 +142,9 @@ public class TvPipController implements PipTransitionController.PipTransitionCal mContext = context; mMainExecutor = mainExecutor; - mPipBoundsState = pipBoundsState; - mPipBoundsState.setDisplayId(context.getDisplayId()); - mPipBoundsState.setDisplayLayout(new DisplayLayout(context, context.getDisplay())); + mTvPipBoundsState = tvPipBoundsState; + mTvPipBoundsState.setDisplayId(context.getDisplayId()); + mTvPipBoundsState.setDisplayLayout(new DisplayLayout(context, context.getDisplay())); mTvPipBoundsAlgorithm = tvPipBoundsAlgorithm; mPipMediaController = pipMediaController; @@ -225,11 +218,25 @@ public class TvPipController implements PipTransitionController.PipTransitionCal onPipDisappeared(); } + @Override + public void togglePipExpansion() { + if (DEBUG) Log.d(TAG, "togglePipExpansion()"); + boolean expanding = !mTvPipBoundsState.isTvPipExpanded(); + int saveGravity = mTvPipBoundsAlgorithm + .updatePositionOnExpandToggled(mPreviousGravity, expanding); + if (saveGravity != Gravity.NO_GRAVITY) { + mPreviousGravity = saveGravity; + } + mTvPipBoundsState.setTvPipManuallyCollapsed(!expanding); + mTvPipBoundsState.setTvPipExpanded(expanding); + movePinnedStack(); + } + @Override public void movePip(int keycode) { - if (updatePosition(keycode)) { - if (DEBUG) Log.d(TAG, "New gravity: " + Gravity.toString(mGravity)); - mTvPipMenuController.updateMenu(mGravity); + if (mTvPipBoundsAlgorithm.updatePosition(keycode)) { + mTvPipMenuController.updateGravity(mTvPipBoundsState.getTvPipGravity()); + mPreviousGravity = Gravity.NO_GRAVITY; movePinnedStack(); } else { if (DEBUG) Log.d(TAG, "Position hasn't changed"); @@ -238,38 +245,11 @@ public class TvPipController implements PipTransitionController.PipTransitionCal @Override public int getPipGravity() { - return mGravity; + return mTvPipBoundsState.getTvPipGravity(); } - /** - * @return true if position changed - */ - private boolean updatePosition(int keycode) { - if (DEBUG) Log.d(TAG, "updatePosition, keycode: " + keycode); - - int updatedGravity; - switch (keycode) { - case KEYCODE_DPAD_UP: - updatedGravity = (mGravity & (~Gravity.BOTTOM)) | Gravity.TOP; - break; - case KEYCODE_DPAD_DOWN: - updatedGravity = (mGravity & (~Gravity.TOP)) | Gravity.BOTTOM; - break; - case KEYCODE_DPAD_LEFT: - updatedGravity = (mGravity & (~Gravity.RIGHT)) | Gravity.LEFT; - break; - case KEYCODE_DPAD_RIGHT: - updatedGravity = (mGravity & (~Gravity.LEFT)) | Gravity.RIGHT; - break; - default: - updatedGravity = mGravity; - } - - if (updatedGravity != mGravity) { - mGravity = updatedGravity; - return true; - } - return false; + public int getOrientation() { + return mTvPipBoundsState.getTvFixedPipOrientation(); } /** @@ -280,11 +260,12 @@ public class TvPipController implements PipTransitionController.PipTransitionCal return; } - Rect bounds = mTvPipBoundsAlgorithm.getTvNormalBounds(mGravity); + Rect bounds = mTvPipBoundsAlgorithm.getTvPipBounds(mTvPipBoundsState.isTvPipExpanded()); if (DEBUG) Log.d(TAG, "movePinnedStack() - new pip bounds: " + bounds.toShortString()); mPipTaskOrganizer.scheduleAnimateResizePip(bounds, mResizeAnimationDuration, rect -> { if (DEBUG) Log.d(TAG, "movePinnedStack() animation done"); + mTvPipMenuController.updateExpansionState(); }); } @@ -328,7 +309,7 @@ public class TvPipController implements PipTransitionController.PipTransitionCal mPipNotificationController.dismiss(); mTvPipMenuController.hideMenu(); - mGravity = DEFAULT_GRAVITY; + mTvPipBoundsState.resetTvPipState(); setState(STATE_NO_PIP); mPinnedTaskId = NONEXISTENT_TASK_ID; } @@ -346,11 +327,6 @@ public class TvPipController implements PipTransitionController.PipTransitionCal @Override public void onPipTransitionFinished(int direction) { if (DEBUG) Log.d(TAG, "onPipTransition_Finished(), state=" + stateToName(mState)); - - if (mState == STATE_PIP_MENU) { - if (DEBUG) Log.d(TAG, " > show menu"); - mTvPipMenuController.showMenu(); - } } private void setState(@State int state) { @@ -359,6 +335,11 @@ public class TvPipController implements PipTransitionController.PipTransitionCal + stateToName(mState)); } mState = state; + + if (mState == STATE_PIP_MENU) { + if (DEBUG) Log.d(TAG, " > show menu"); + mTvPipMenuController.showMenu(); + } } private void loadConfigurations() { @@ -408,19 +389,74 @@ public class TvPipController implements PipTransitionController.PipTransitionCal + ", height=" + imeHeight); } - if (imeVisible == mPipBoundsState.isImeShowing() - && (!imeVisible || imeHeight == mPipBoundsState.getImeHeight())) { + if (imeVisible == mTvPipBoundsState.isImeShowing() + && (!imeVisible || imeHeight == mTvPipBoundsState.getImeHeight())) { // Nothing changed: either IME has been and remains invisible, or remains // visible with the same height. return; } - mPipBoundsState.setImeVisibility(imeVisible, imeHeight); + mTvPipBoundsState.setImeVisibility(imeVisible, imeHeight); if (mState != STATE_NO_PIP) { movePinnedStack(); } } + @Override + public void onAspectRatioChanged(float ratio) { + if (DEBUG) Log.d(TAG, "onAspectRatioChanged: " + ratio); + + boolean ratioChanged = mTvPipBoundsState.getAspectRatio() != ratio; + mTvPipBoundsState.setAspectRatio(ratio); + + if (!mTvPipBoundsState.isTvPipExpanded() && ratioChanged) { + movePinnedStack(); + } + } + + @Override + public void onExpandedAspectRatioChanged(float ratio) { + if (DEBUG) Log.d(TAG, "onExpandedAspectRatioChanged: " + ratio); + + // 0) No update to the ratio --> don't do anything + if (mTvPipBoundsState.getTvExpandedAspectRatio() == ratio) { + return; + } + + mTvPipBoundsState.setTvExpandedAspectRatio(ratio, false); + + // 1) PiP is expanded and only aspect ratio changed, but wasn't disabled + // --> update bounds, but don't toggle + if (mTvPipBoundsState.isTvPipExpanded() && ratio != 0) { + movePinnedStack(); + } + + // 2) PiP is expanded, but expanded PiP was disabled + // --> collapse PiP + if (mTvPipBoundsState.isTvPipExpanded() && ratio == 0) { + int saveGravity = mTvPipBoundsAlgorithm + .updatePositionOnExpandToggled(mPreviousGravity, false); + if (saveGravity != Gravity.NO_GRAVITY) { + mPreviousGravity = saveGravity; + } + mTvPipBoundsState.setTvPipExpanded(false); + movePinnedStack(); + } + + // 3) PiP not expanded and not manually collapsed and expand was enabled + // --> expand to new ratio + if (!mTvPipBoundsState.isTvPipExpanded() && ratio != 0 + && !mTvPipBoundsState.isTvPipManuallyCollapsed()) { + int saveGravity = mTvPipBoundsAlgorithm + .updatePositionOnExpandToggled(mPreviousGravity, true); + if (saveGravity != Gravity.NO_GRAVITY) { + mPreviousGravity = saveGravity; + } + mTvPipBoundsState.setTvPipExpanded(true); + movePinnedStack(); + } + } + @Override public void onMovementBoundsChanged(boolean fromImeAdjustment) {} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuActionButton.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuActionButton.java index bda685e99a12a..4eb46d93c8878 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuActionButton.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuActionButton.java @@ -65,7 +65,7 @@ public class TvPipMenuActionButton extends RelativeLayout implements View.OnClic setImageResource(typedArray.getResourceId(0, 0)); final int textResId = typedArray.getResourceId(1, 0); if (textResId != 0) { - setTextAndDescription(getContext().getString(textResId)); + setTextAndDescription(textResId); } typedArray.recycle(); } @@ -110,6 +110,13 @@ public class TvPipMenuActionButton extends RelativeLayout implements View.OnClic mButtonView.setContentDescription(text); } + /** + * Sets the text and description with the given string resource id. + */ + public void setTextAndDescription(int resId) { + setTextAndDescription(getContext().getString(resId)); + } + @Override public void setEnabled(boolean enabled) { mButtonView.setEnabled(enabled); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java index f838a0bece814..69d6c9e0c3bd6 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java @@ -18,6 +18,7 @@ package com.android.wm.shell.pip.tv; import static android.view.WindowManager.SHELL_ROOT_LAYER_PIP; +import android.app.ActivityManager; import android.app.RemoteAction; import android.content.BroadcastReceiver; import android.content.Context; @@ -37,7 +38,6 @@ import androidx.annotation.Nullable; import com.android.wm.shell.R; import com.android.wm.shell.common.SystemWindows; -import com.android.wm.shell.pip.PipBoundsState; import com.android.wm.shell.pip.PipMediaController; import com.android.wm.shell.pip.PipMenuController; @@ -53,7 +53,7 @@ public class TvPipMenuController implements PipMenuController, TvPipMenuView.Lis private final Context mContext; private final SystemWindows mSystemWindows; - private final PipBoundsState mPipBoundsState; + private final TvPipBoundsState mTvPipBoundsState; private final Handler mMainHandler; private Delegate mDelegate; @@ -85,11 +85,11 @@ public class TvPipMenuController implements PipMenuController, TvPipMenuView.Lis } }; - public TvPipMenuController(Context context, PipBoundsState pipBoundsState, + public TvPipMenuController(Context context, TvPipBoundsState tvPipBoundsState, SystemWindows systemWindows, PipMediaController pipMediaController, Handler mainHandler) { mContext = context; - mPipBoundsState = pipBoundsState; + mTvPipBoundsState = tvPipBoundsState; mSystemWindows = systemWindows; mMainHandler = mainHandler; @@ -151,12 +151,13 @@ public class TvPipMenuController implements PipMenuController, TvPipMenuView.Lis if (DEBUG) Log.d(TAG, "showMenu()"); if (mPipMenuView != null) { - Rect menuBounds = getMenuBounds(mPipBoundsState.getBounds()); + Rect menuBounds = getMenuBounds(mTvPipBoundsState.getBounds()); mSystemWindows.updateViewLayout(mPipMenuView, getPipMenuLayoutParams( MENU_WINDOW_TITLE, menuBounds.width(), menuBounds.height())); maybeUpdateMenuViewActions(); + updateExpansionState(); - SurfaceControl menuSurfaceControl = mSystemWindows.getViewSurface(mPipMenuView); + SurfaceControl menuSurfaceControl = getSurfaceControl(); if (menuSurfaceControl != null) { SurfaceControl.Transaction t = new SurfaceControl.Transaction(); t.setRelativeLayer(mPipMenuView.getWindowSurfaceControl(), mLeash, 1); @@ -167,10 +168,16 @@ public class TvPipMenuController implements PipMenuController, TvPipMenuView.Lis } } - void updateMenu(int gravity) { + void updateGravity(int gravity) { mPipMenuView.showMovementHints(gravity); } + void updateExpansionState() { + mPipMenuView.setExpandedModeEnabled(mTvPipBoundsState.isTvExpandedPipEnabled() + && mTvPipBoundsState.getTvExpandedAspectRatio() != 0); + mPipMenuView.setIsExpanded(mTvPipBoundsState.isTvPipExpanded()); + } + private Rect getMenuBounds(Rect pipBounds) { int extraSpaceInPx = mContext.getResources() .getDimensionPixelSize(R.dimen.pip_menu_outer_space); @@ -350,7 +357,9 @@ public class TvPipMenuController implements PipMenuController, TvPipMenuView.Lis SurfaceControl surfaceControl = getSurfaceControl(); SyncRtSurfaceTransactionApplier.SurfaceParams params = new SyncRtSurfaceTransactionApplier.SurfaceParams.Builder( - surfaceControl).withMatrix(mMoveTransform).build(); + surfaceControl) + .withMatrix(mMoveTransform) + .build(); if (pipLeash != null && transaction != null) { SyncRtSurfaceTransactionApplier.SurfaceParams @@ -366,6 +375,8 @@ public class TvPipMenuController implements PipMenuController, TvPipMenuView.Lis mPipMenuView.getHandler().removeCallbacks(mUpdateEmbeddedMatrix); mPipMenuView.getHandler().post(mUpdateEmbeddedMatrix); } + + updateMenuBounds(pipDestBounds); } private boolean maybeCreateSyncApplier() { @@ -397,6 +408,14 @@ public class TvPipMenuController implements PipMenuController, TvPipMenuView.Lis mSystemWindows.updateViewLayout(mPipMenuView, getPipMenuLayoutParams(MENU_WINDOW_TITLE, menuBounds.width(), menuBounds.height())); + if (mPipMenuView != null) { + mPipMenuView.updateLayout(destinationBounds); + } + } + + @Override + public void onFocusTaskChanged(ActivityManager.RunningTaskInfo taskInfo) { + Log.d(TAG, "onFocusTaskChanged"); } @Override @@ -416,6 +435,11 @@ public class TvPipMenuController implements PipMenuController, TvPipMenuView.Lis mDelegate.movePipToFullscreen(); } + @Override + public void onToggleExpandedMode() { + mDelegate.togglePipExpansion(); + } + interface Delegate { void movePipToFullscreen(); @@ -423,6 +447,8 @@ public class TvPipMenuController implements PipMenuController, TvPipMenuView.Lis int getPipGravity(); + void togglePipExpansion(); + void closeMenu(); void closePip(); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuView.java index 84eae9e0febbb..773e9bfa89772 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuView.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuView.java @@ -23,19 +23,21 @@ import static android.view.KeyEvent.KEYCODE_DPAD_DOWN; import static android.view.KeyEvent.KEYCODE_DPAD_LEFT; import static android.view.KeyEvent.KEYCODE_DPAD_RIGHT; import static android.view.KeyEvent.KEYCODE_DPAD_UP; +import static android.view.KeyEvent.KEYCODE_ENTER; import android.app.PendingIntent; import android.app.RemoteAction; import android.content.Context; +import android.graphics.Rect; import android.os.Handler; import android.os.IBinder; import android.util.AttributeSet; import android.util.Log; import android.view.Gravity; import android.view.KeyEvent; -import android.view.LayoutInflater; import android.view.SurfaceControl; import android.view.View; +import android.view.ViewGroup; import android.view.ViewRootImpl; import android.view.WindowManagerGlobal; import android.widget.FrameLayout; @@ -72,6 +74,13 @@ public class TvPipMenuView extends FrameLayout implements View.OnClickListener { private final ImageView mArrowLeft; private IBinder mFocusGrantToken = null; + private final ViewGroup mScrollView; + private final ViewGroup mHorizontalScrollView; + + private Rect mCurrentBounds; + + private final TvPipMenuActionButton mExpandButton; + public TvPipMenuView(@NonNull Context context) { this(context, null); } @@ -97,6 +106,11 @@ public class TvPipMenuView extends FrameLayout implements View.OnClickListener { .setOnClickListener(this); mActionButtonsContainer.findViewById(R.id.tv_pip_menu_move_button) .setOnClickListener(this); + mExpandButton = findViewById(R.id.tv_pip_menu_expand_button); + mExpandButton.setOnClickListener(this); + + mScrollView = findViewById(R.id.tv_pip_menu_scroll); + mHorizontalScrollView = findViewById(R.id.tv_pip_menu_horizontal_scroll); mMenuFrameView = findViewById(R.id.tv_pip_menu_frame); @@ -106,6 +120,34 @@ public class TvPipMenuView extends FrameLayout implements View.OnClickListener { mArrowLeft = findViewById(R.id.tv_pip_menu_arrow_left); } + void updateLayout(Rect updatedBounds) { + Log.d(TAG, "update menu layout: " + updatedBounds.toShortString()); + boolean previouslyVertical = + mCurrentBounds != null && mCurrentBounds.height() > mCurrentBounds.width(); + boolean vertical = updatedBounds.height() > updatedBounds.width(); + + mCurrentBounds = updatedBounds; + if (previouslyVertical == vertical) { + if (DEBUG) Log.d(TAG, "no update for menu layout"); + return; + } else { + if (DEBUG) Log.d(TAG, "change menu layout to vertical: " + vertical); + } + + if (vertical) { + mHorizontalScrollView.removeView(mActionButtonsContainer); + mScrollView.addView(mActionButtonsContainer); + } else { + mScrollView.removeView(mActionButtonsContainer); + mHorizontalScrollView.addView(mActionButtonsContainer); + } + mActionButtonsContainer.setOrientation(vertical ? LinearLayout.VERTICAL + : LinearLayout.HORIZONTAL); + + mScrollView.setVisibility(vertical ? VISIBLE : GONE); + mHorizontalScrollView.setVisibility(vertical ? GONE : VISIBLE); + } + void setListener(@Nullable Listener listener) { mListener = listener; } @@ -114,6 +156,18 @@ public class TvPipMenuView extends FrameLayout implements View.OnClickListener { mFocusGrantToken = token; } + void setExpandedModeEnabled(boolean enabled) { + mExpandButton.setVisibility(enabled ? VISIBLE : GONE); + } + + void setIsExpanded(boolean expanded) { + if (DEBUG) Log.d(TAG, "setIsExpanded, expanded: " + expanded); + mExpandButton.setImageResource( + expanded ? R.drawable.pip_ic_collapse : R.drawable.pip_ic_expand); + mExpandButton.setTextAndDescription( + expanded ? R.string.pip_collapse : R.string.pip_expand); + } + void show(boolean inMoveMode, int gravity) { if (DEBUG) Log.d(TAG, "show(), inMoveMode: " + inMoveMode); grantWindowFocus(true); @@ -181,13 +235,13 @@ public class TvPipMenuView extends FrameLayout implements View.OnClickListener { final int actionsNumber = actions.size(); int buttonsNumber = mAdditionalButtons.size(); if (actionsNumber > buttonsNumber) { - final LayoutInflater layoutInflater = LayoutInflater.from(mContext); // Add buttons until we have enough to display all of the actions. while (actionsNumber > buttonsNumber) { TvPipMenuActionButton button = new TvPipMenuActionButton(mContext); button.setOnClickListener(this); - mActionButtonsContainer.addView(button); + mActionButtonsContainer.addView(button, + mActionButtonsContainer.getChildCount() - 1); mAdditionalButtons.add(button); buttonsNumber++; @@ -239,6 +293,8 @@ public class TvPipMenuView extends FrameLayout implements View.OnClickListener { mListener.onEnterMoveMode(); } else if (id == R.id.tv_pip_menu_close_button) { mListener.onCloseButtonClick(); + } else if (id == R.id.tv_pip_menu_expand_button) { + mListener.onToggleExpandedMode(); } else { // This should be an "additional action" final RemoteAction action = (RemoteAction) v.getTag(); @@ -271,6 +327,7 @@ public class TvPipMenuView extends FrameLayout implements View.OnClickListener { case KEYCODE_DPAD_RIGHT: return mListener.onPipMovement(event.getKeyCode()) || super.dispatchKeyEvent( event); + case KEYCODE_ENTER: case KEYCODE_DPAD_CENTER: return mListener.onExitMoveMode() || super.dispatchKeyEvent(event); default: @@ -286,10 +343,14 @@ public class TvPipMenuView extends FrameLayout implements View.OnClickListener { public void showMovementHints(int gravity) { if (DEBUG) Log.d(TAG, "showMovementHints(), position: " + Gravity.toString(gravity)); - animateAlphaTo((gravity & Gravity.BOTTOM) == Gravity.BOTTOM ? 1f : 0f, mArrowUp); - animateAlphaTo((gravity & Gravity.TOP) == Gravity.TOP ? 1f : 0f, mArrowDown); - animateAlphaTo((gravity & Gravity.RIGHT) == Gravity.RIGHT ? 1f : 0f, mArrowLeft); - animateAlphaTo((gravity & Gravity.LEFT) == Gravity.LEFT ? 1f : 0f, mArrowRight); + animateAlphaTo(checkGravity(gravity, Gravity.BOTTOM) ? 1f : 0f, mArrowUp); + animateAlphaTo(checkGravity(gravity, Gravity.TOP) ? 1f : 0f, mArrowDown); + animateAlphaTo(checkGravity(gravity, Gravity.RIGHT) ? 1f : 0f, mArrowLeft); + animateAlphaTo(checkGravity(gravity, Gravity.LEFT) ? 1f : 0f, mArrowRight); + } + + private boolean checkGravity(int gravity, int feature) { + return (gravity & feature) == feature; } /** @@ -330,5 +391,7 @@ public class TvPipMenuView extends FrameLayout implements View.OnClickListener { void onCloseButtonClick(); void onFullscreenButtonClick(); + + void onToggleExpandedMode(); } } diff --git a/services/core/java/com/android/server/wm/ActivityClientController.java b/services/core/java/com/android/server/wm/ActivityClientController.java index d526845f749a2..76e1c438d2e7e 100644 --- a/services/core/java/com/android/server/wm/ActivityClientController.java +++ b/services/core/java/com/android/server/wm/ActivityClientController.java @@ -746,8 +746,8 @@ class ActivityClientController extends IActivityClientController.Stub { // if it is not already expanding to fullscreen. Otherwise, the arguments will // be used the next time the activity enters PiP. final Task rootTask = r.getRootTask(); - rootTask.setPictureInPictureAspectRatio( - r.pictureInPictureArgs.getAspectRatio()); + rootTask.setPictureInPictureAspectRatio(r.pictureInPictureArgs.getAspectRatio(), + r.pictureInPictureArgs.getExpandedAspectRatio()); rootTask.setPictureInPictureActions(r.pictureInPictureArgs.getActions()); } } @@ -808,18 +808,28 @@ class ActivityClientController extends IActivityClientController.Stub { + ": Current activity does not support picture-in-picture."); } + final float minAspectRatio = mContext.getResources().getFloat( + com.android.internal.R.dimen.config_pictureInPictureMinAspectRatio); + final float maxAspectRatio = mContext.getResources().getFloat( + com.android.internal.R.dimen.config_pictureInPictureMaxAspectRatio); + if (params.hasSetAspectRatio() && !mService.mWindowManager.isValidPictureInPictureAspectRatio( r.mDisplayContent, params.getAspectRatio())) { - final float minAspectRatio = mContext.getResources().getFloat( - com.android.internal.R.dimen.config_pictureInPictureMinAspectRatio); - final float maxAspectRatio = mContext.getResources().getFloat( - com.android.internal.R.dimen.config_pictureInPictureMaxAspectRatio); throw new IllegalArgumentException(String.format(caller + ": Aspect ratio is too extreme (must be between %f and %f).", minAspectRatio, maxAspectRatio)); } + if (mService.mSupportsExpandedPictureInPicture && params.hasSetExpandedAspectRatio() + && !mService.mWindowManager.isValidExpandedPictureInPictureAspectRatio( + r.mDisplayContent, params.getExpandedAspectRatio())) { + throw new IllegalArgumentException(String.format(caller + + ": Expanded aspect ratio is not extreme enough (must not be between" + + " %f and %f).", + minAspectRatio, maxAspectRatio)); + } + // Truncate the number of actions if necessary. params.truncateActions(ActivityTaskManager.getMaxNumPictureInPictureActions(mContext)); return r; diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java index 580ab1798f539..02810a69abe81 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java @@ -44,6 +44,7 @@ import static android.content.pm.ApplicationInfo.FLAG_FACTORY_TEST; import static android.content.pm.ConfigurationInfo.GL_ES_VERSION_UNDEFINED; import static android.content.pm.PackageManager.FEATURE_ACTIVITIES_ON_SECONDARY_DISPLAYS; import static android.content.pm.PackageManager.FEATURE_CANT_SAVE_STATE; +import static android.content.pm.PackageManager.FEATURE_EXPANDED_PICTURE_IN_PICTURE; import static android.content.pm.PackageManager.FEATURE_FREEFORM_WINDOW_MANAGEMENT; import static android.content.pm.PackageManager.FEATURE_LEANBACK; import static android.content.pm.PackageManager.FEATURE_PICTURE_IN_PICTURE; @@ -590,6 +591,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { boolean mSupportsSplitScreenMultiWindow; boolean mSupportsFreeformWindowManagement; boolean mSupportsPictureInPicture; + boolean mSupportsExpandedPictureInPicture; boolean mSupportsMultiDisplay; boolean mForceResizableActivities; @@ -883,6 +885,9 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { final boolean supportsMultiWindow = ActivityTaskManager.supportsMultiWindow(mContext); final boolean supportsPictureInPicture = supportsMultiWindow && mContext.getPackageManager().hasSystemFeature(FEATURE_PICTURE_IN_PICTURE); + final boolean supportsExpandedPictureInPicture = + supportsPictureInPicture && mContext.getPackageManager().hasSystemFeature( + FEATURE_EXPANDED_PICTURE_IN_PICTURE); final boolean supportsSplitScreenMultiWindow = ActivityTaskManager.supportsSplitScreenMultiWindow(mContext); final boolean supportsMultiDisplay = mContext.getPackageManager() @@ -930,12 +935,14 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { mSupportsFreeformWindowManagement = freeformWindowManagement; mSupportsSplitScreenMultiWindow = supportsSplitScreenMultiWindow; mSupportsPictureInPicture = supportsPictureInPicture; + mSupportsExpandedPictureInPicture = supportsExpandedPictureInPicture; mSupportsMultiDisplay = supportsMultiDisplay; } else { mSupportsMultiWindow = false; mSupportsFreeformWindowManagement = false; mSupportsSplitScreenMultiWindow = false; mSupportsPictureInPicture = false; + mSupportsExpandedPictureInPicture = false; mSupportsMultiDisplay = false; } mWindowManager.mRoot.onSettingsRetrieved(); @@ -3494,11 +3501,12 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { // Only update the saved args from the args that are set r.setPictureInPictureParams(params); final float aspectRatio = r.pictureInPictureArgs.getAspectRatio(); + final float expandedAspectRatio = r.pictureInPictureArgs.getExpandedAspectRatio(); final List actions = r.pictureInPictureArgs.getActions(); mRootWindowContainer.moveActivityToPinnedRootTask( r, "enterPictureInPictureMode"); final Task task = r.getTask(); - task.setPictureInPictureAspectRatio(aspectRatio); + task.setPictureInPictureAspectRatio(aspectRatio, expandedAspectRatio); task.setPictureInPictureActions(actions); // Continue the pausing process after entering pip. diff --git a/services/core/java/com/android/server/wm/PinnedTaskController.java b/services/core/java/com/android/server/wm/PinnedTaskController.java index 1da0fe731709f..06e3a73940b47 100644 --- a/services/core/java/com/android/server/wm/PinnedTaskController.java +++ b/services/core/java/com/android/server/wm/PinnedTaskController.java @@ -93,6 +93,7 @@ class PinnedTaskController { // The set of actions and aspect-ratio for the that are currently allowed on the PiP activity private ArrayList mActions = new ArrayList<>(); private float mAspectRatio = -1f; + private float mExpandedAspectRatio = 0f; // The aspect ratio bounds of the PIP. private float mMinAspectRatio; @@ -160,13 +161,21 @@ class PinnedTaskController { } /** - * @return whether the given {@param aspectRatio} is valid. + * @return whether the given {@param aspectRatio} is valid, i.e. min <= ratio <= max. */ public boolean isValidPictureInPictureAspectRatio(float aspectRatio) { return Float.compare(mMinAspectRatio, aspectRatio) <= 0 && Float.compare(aspectRatio, mMaxAspectRatio) <= 0; } + /** + * @return whether the given {@param aspectRatio} is valid, i.e. ratio < min or ratio > max. + */ + public boolean isValidExpandedPictureInPictureAspectRatio(float aspectRatio) { + return Float.compare(mMinAspectRatio, aspectRatio) > 0 + || Float.compare(aspectRatio, mMaxAspectRatio) > 0; + } + /** * Called when a fullscreen task is entering PiP with display orientation change. This is used * to avoid flickering when running PiP animation across different orientations. @@ -377,6 +386,25 @@ class PinnedTaskController { return mAspectRatio; } + /** + * Sets the current aspect ratio. + */ + void setExpandedAspectRatio(float aspectRatio) { + if (Float.compare(mExpandedAspectRatio, aspectRatio) != 0) { + mExpandedAspectRatio = aspectRatio; + notifyExpandedAspectRatioChanged(aspectRatio); + notifyMovementBoundsChanged(false /* fromImeAdjustment */); + } + } + + /** + * @return the current aspect ratio. + */ + float getExpandedAspectRatio() { + return mExpandedAspectRatio; + } + + /** * Sets the current set of actions. */ @@ -410,6 +438,15 @@ class PinnedTaskController { } } + private void notifyExpandedAspectRatioChanged(float aspectRatio) { + if (mPinnedTaskListener == null) return; + try { + mPinnedTaskListener.onExpandedAspectRatioChanged(aspectRatio); + } catch (RemoteException e) { + Slog.e(TAG_WM, "Error delivering aspect ratio changed event.", e); + } + } + /** * Notifies listeners that the PIP actions have changed. */ diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index 6df54cd939cb4..f7c5b2626b883 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -6013,9 +6013,9 @@ class Task extends TaskFragment { } /** - * Sets the current picture-in-picture aspect ratio. + * Sets the current picture-in-picture aspect ratios. */ - void setPictureInPictureAspectRatio(float aspectRatio) { + void setPictureInPictureAspectRatio(float aspectRatio, float expandedAspectRatio) { if (!mWmService.mAtmService.mSupportsPictureInPicture) { return; } @@ -6032,16 +6032,21 @@ class Task extends TaskFragment { final PinnedTaskController pinnedTaskController = getDisplayContent().getPinnedTaskController(); - if (Float.compare(aspectRatio, pinnedTaskController.getAspectRatio()) == 0) { - return; - } - // Notify the pinned stack controller about aspect ratio change. // This would result a callback delivered from SystemUI to WM to start animation, // if the bounds are ought to be altered due to aspect ratio change. - pinnedTaskController.setAspectRatio( - pinnedTaskController.isValidPictureInPictureAspectRatio(aspectRatio) - ? aspectRatio : -1f); + if (Float.compare(aspectRatio, pinnedTaskController.getAspectRatio()) != 0) { + pinnedTaskController.setAspectRatio( + pinnedTaskController.isValidPictureInPictureAspectRatio(aspectRatio) + ? aspectRatio : -1f); + } + + if (mWmService.mAtmService.mSupportsExpandedPictureInPicture && Float.compare( + expandedAspectRatio, pinnedTaskController.getExpandedAspectRatio()) != 0) { + pinnedTaskController.setExpandedAspectRatio(pinnedTaskController + .isValidExpandedPictureInPictureAspectRatio(expandedAspectRatio) + ? expandedAspectRatio : 0f); + } } /** diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 4d1bc22f24376..11cdc0cfb527e 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -3007,6 +3007,12 @@ public class WindowManagerService extends IWindowManager.Stub aspectRatio); } + boolean isValidExpandedPictureInPictureAspectRatio(DisplayContent displayContent, + float aspectRatio) { + return displayContent.getPinnedTaskController().isValidExpandedPictureInPictureAspectRatio( + aspectRatio); + } + @Override public void notifyKeyguardTrustedChanged() { synchronized (mGlobalLock) {