diff options
11 files changed, 315 insertions, 113 deletions
diff --git a/libs/WindowManager/Shell/res/drawable/tv_pip_menu_background.xml b/libs/WindowManager/Shell/res/drawable/tv_pip_menu_background.xml new file mode 100644 index 000000000000..0c627921573c --- /dev/null +++ b/libs/WindowManager/Shell/res/drawable/tv_pip_menu_background.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ 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. + --> +<shape xmlns:android="http://schemas.android.com/apk/res/android" + android:shape="rectangle"> + <corners android:radius="@dimen/pip_menu_background_corner_radius" /> + <solid android:color="@color/tv_pip_menu_background"/> + <stroke android:width="@dimen/pip_menu_border_width" + android:color="@color/tv_pip_menu_background"/> +</shape> diff --git a/libs/WindowManager/Shell/res/drawable/tv_pip_menu_border.xml b/libs/WindowManager/Shell/res/drawable/tv_pip_menu_border.xml index 9bc03112b118..846fdb3e8a58 100644 --- a/libs/WindowManager/Shell/res/drawable/tv_pip_menu_border.xml +++ b/libs/WindowManager/Shell/res/drawable/tv_pip_menu_border.xml @@ -14,9 +14,20 @@ ~ See the License for the specific language governing permissions and ~ limitations under the License. --> -<shape xmlns:android="http://schemas.android.com/apk/res/android" - android:shape="rectangle"> - <corners android:radius="@dimen/pip_menu_border_radius" /> - <stroke android:width="@dimen/pip_menu_border_width" - android:color="@color/tv_pip_menu_focus_border" /> -</shape>
\ No newline at end of file +<selector xmlns:android="http://schemas.android.com/apk/res/android" + android:exitFadeDuration="@integer/pip_menu_fade_animation_duration"> + <item android:state_activated="true"> + <shape android:shape="rectangle"> + <corners android:radius="@dimen/pip_menu_border_corner_radius" /> + <stroke android:width="@dimen/pip_menu_border_width" + android:color="@color/tv_pip_menu_focus_border" /> + </shape> + </item> + <item> + <shape android:shape="rectangle"> + <corners android:radius="@dimen/pip_menu_border_corner_radius" /> + <stroke android:width="@dimen/pip_menu_border_width" + android:color="@color/tv_pip_menu_background"/> + </shape> + </item> +</selector> diff --git a/libs/WindowManager/Shell/res/layout/tv_pip_menu.xml b/libs/WindowManager/Shell/res/layout/tv_pip_menu.xml index b826d03bf765..f84b8f642953 100644 --- a/libs/WindowManager/Shell/res/layout/tv_pip_menu.xml +++ b/libs/WindowManager/Shell/res/layout/tv_pip_menu.xml @@ -16,9 +16,10 @@ --> <!-- Layout for TvPipMenuView --> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:id="@+id/tv_pip_menu" - android:layout_width="match_parent" - android:layout_height="match_parent"> + android:id="@+id/tv_pip_menu" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:gravity="center|top"> <ScrollView android:id="@+id/tv_pip_menu_scroll" @@ -92,7 +93,6 @@ android:id="@+id/tv_pip_menu_frame" android:layout_width="match_parent" android:layout_height="match_parent" - android:alpha="0" android:layout_margin="@dimen/pip_menu_outer_space_frame" android:background="@drawable/tv_pip_menu_border"/> diff --git a/libs/WindowManager/Shell/res/layout/tv_pip_menu_background.xml b/libs/WindowManager/Shell/res/layout/tv_pip_menu_background.xml new file mode 100644 index 000000000000..5af40200d240 --- /dev/null +++ b/libs/WindowManager/Shell/res/layout/tv_pip_menu_background.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + 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. +--> +<!-- Layout for the back surface of the PiP menu --> +<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent"> + <View + android:layout_width="match_parent" + android:layout_height="match_parent" + android:layout_margin="@dimen/pip_menu_outer_space_frame" + android:background="@drawable/tv_pip_menu_background" + android:elevation="@dimen/pip_menu_elevation"/> +</FrameLayout> + diff --git a/libs/WindowManager/Shell/res/values-tvdpi/dimen.xml b/libs/WindowManager/Shell/res/values-tvdpi/dimen.xml index 558ec51752b9..63c26dadfab4 100644 --- a/libs/WindowManager/Shell/res/values-tvdpi/dimen.xml +++ b/libs/WindowManager/Shell/res/values-tvdpi/dimen.xml @@ -22,7 +22,12 @@ <dimen name="pip_menu_button_margin">4dp</dimen> <dimen name="pip_menu_button_wrapper_margin">26dp</dimen> <dimen name="pip_menu_border_width">4dp</dimen> - <dimen name="pip_menu_border_radius">4dp</dimen> + <integer name="pip_menu_fade_animation_duration">500</integer> + <!-- The pip menu front border corner radius is 2dp smaller than + the background corner radius to hide the background from + showing through. --> + <dimen name="pip_menu_border_corner_radius">4dp</dimen> + <dimen name="pip_menu_background_corner_radius">6dp</dimen> <dimen name="pip_menu_outer_space">24dp</dimen> <!-- outer space minus border width --> @@ -30,5 +35,7 @@ <dimen name="pip_menu_arrow_size">24dp</dimen> <dimen name="pip_menu_arrow_elevation">5dp</dimen> + + <dimen name="pip_menu_elevation">1dp</dimen> </resources> diff --git a/libs/WindowManager/Shell/res/values/colors_tv.xml b/libs/WindowManager/Shell/res/values/colors_tv.xml index 64b146ec3a83..4e7fee8e2e1e 100644 --- a/libs/WindowManager/Shell/res/values/colors_tv.xml +++ b/libs/WindowManager/Shell/res/values/colors_tv.xml @@ -23,4 +23,5 @@ <color name="tv_pip_menu_icon_bg_focused">#E8EAED</color> <color name="tv_pip_menu_icon_bg_unfocused">#990E0E0F</color> <color name="tv_pip_menu_focus_border">#E8EAED</color> -</resources>
\ No newline at end of file + <color name="tv_pip_menu_background">#1E232C</color> +</resources> 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 1aefd77419aa..93f699e4645d 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 @@ -27,6 +27,7 @@ import static com.android.wm.shell.pip.tv.TvPipBoundsState.ORIENTATION_VERTICAL; import android.content.Context; import android.content.res.Resources; +import android.graphics.Insets; import android.graphics.Rect; import android.os.SystemClock; import android.util.ArraySet; @@ -150,6 +151,7 @@ public class TvPipBoundsAlgorithm extends PipBoundsAlgorithm { mKeepClearAlgorithm.setScreenSize(screenSize); mKeepClearAlgorithm.setMovementBounds(insetBounds); mKeepClearAlgorithm.setStashOffset(mTvPipBoundsState.getStashOffset()); + mKeepClearAlgorithm.setPipDecorInsets(mTvPipBoundsState.getPipMenuPermanentDecorInsets()); final Placement placement = mKeepClearAlgorithm.calculatePipPosition( pipSize, @@ -340,6 +342,7 @@ public class TvPipBoundsAlgorithm extends PipBoundsAlgorithm { final DisplayLayout displayLayout = mTvPipBoundsState.getDisplayLayout(); final float expandedRatio = mTvPipBoundsState.getDesiredTvExpandedAspectRatio(); // width / height + final Insets pipDecorations = mTvPipBoundsState.getPipMenuPermanentDecorInsets(); final Size expandedSize; if (expandedRatio == 0) { @@ -352,7 +355,8 @@ public class TvPipBoundsAlgorithm extends PipBoundsAlgorithm { if (mTvPipBoundsState.getTvFixedPipOrientation() == ORIENTATION_HORIZONTAL) { expandedSize = mTvPipBoundsState.getTvExpandedSize(); } else { - int maxHeight = displayLayout.height() - (2 * mScreenEdgeInsets.y); + int maxHeight = displayLayout.height() - (2 * mScreenEdgeInsets.y) + - pipDecorations.top - pipDecorations.bottom; float aspectRatioHeight = mFixedExpandedWidthInPx / expandedRatio; if (maxHeight > aspectRatioHeight) { @@ -374,7 +378,8 @@ public class TvPipBoundsAlgorithm extends PipBoundsAlgorithm { if (mTvPipBoundsState.getTvFixedPipOrientation() == ORIENTATION_VERTICAL) { expandedSize = mTvPipBoundsState.getTvExpandedSize(); } else { - int maxWidth = displayLayout.width() - (2 * mScreenEdgeInsets.x); + int maxWidth = displayLayout.width() - (2 * mScreenEdgeInsets.x) + - pipDecorations.left - pipDecorations.right; float aspectRatioWidth = mFixedExpandedHeightInPx * expandedRatio; if (maxWidth > aspectRatioWidth) { if (DEBUG) { 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 index 986554853034..cdb18bc180be 100644 --- 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 @@ -24,6 +24,7 @@ import android.content.ComponentName; import android.content.Context; import android.content.pm.ActivityInfo; import android.content.pm.PackageManager; +import android.graphics.Insets; import android.util.Size; import android.view.Gravity; @@ -60,7 +61,7 @@ public class TvPipBoundsState extends PipBoundsState { private @Orientation int mTvFixedPipOrientation; private int mTvPipGravity; private @Nullable Size mTvExpandedSize; - + private @NonNull Insets mPipMenuPermanentDecorInsets = Insets.NONE; public TvPipBoundsState(@NonNull Context context) { super(context); @@ -159,4 +160,11 @@ public class TvPipBoundsState extends PipBoundsState { return mIsTvExpandedPipSupported; } + public void setPipMenuPermanentDecorInsets(@NonNull Insets permanentInsets) { + mPipMenuPermanentDecorInsets = permanentInsets; + } + + public @NonNull Insets getPipMenuPermanentDecorInsets() { + return mPipMenuPermanentDecorInsets; + } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipKeepClearAlgorithm.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipKeepClearAlgorithm.kt index 5ac7a7200494..48f76288f1ec 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipKeepClearAlgorithm.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipKeepClearAlgorithm.kt @@ -16,6 +16,7 @@ package com.android.wm.shell.pip.tv +import android.graphics.Insets import android.graphics.Point import android.graphics.Rect import android.util.Size @@ -94,6 +95,9 @@ class TvPipKeepClearAlgorithm(private val clock: () -> Long) { private var lastAreasOverlappingUnstashPosition: Set<Rect> = emptySet() private var lastStashTime: Long = Long.MIN_VALUE + /** Spaces around the PiP that we should leave space for when placing the PiP */ + private var pipDecorInsets = Insets.NONE + /** * Calculates the position the PiP should be placed at, taking into consideration the * given keep clear areas. @@ -120,7 +124,9 @@ class TvPipKeepClearAlgorithm(private val clock: () -> Long) { ): Placement { val transformedRestrictedAreas = transformAndFilterAreas(restrictedAreas) val transformedUnrestrictedAreas = transformAndFilterAreas(unrestrictedAreas) - val pipAnchorBounds = getNormalPipAnchorBounds(pipSize, transformedMovementBounds) + + val pipSizeWithDecors = addDecors(pipSize) + val pipAnchorBounds = getNormalPipAnchorBounds(pipSizeWithDecors, transformedMovementBounds) val result = calculatePipPositionTransformed( pipAnchorBounds, @@ -128,12 +134,17 @@ class TvPipKeepClearAlgorithm(private val clock: () -> Long) { transformedUnrestrictedAreas ) - val screenSpaceBounds = fromTransformedSpace(result.bounds) + val pipBounds = removeDecors(fromTransformedSpace(result.bounds)) + val anchorBounds = removeDecors(fromTransformedSpace(result.anchorBounds)) + val unstashedDestBounds = result.unstashDestinationBounds?.let { + removeDecors(fromTransformedSpace(it)) + } + return Placement( - screenSpaceBounds, - fromTransformedSpace(result.anchorBounds), - getStashType(screenSpaceBounds, movementBounds), - result.unstashDestinationBounds?.let { fromTransformedSpace(it) }, + pipBounds, + anchorBounds, + getStashType(pipBounds, movementBounds), + unstashedDestBounds, result.unstashTime ) } @@ -447,6 +458,11 @@ class TvPipKeepClearAlgorithm(private val clock: () -> Long) { transformedMovementBounds = toTransformedSpace(movementBounds) } + fun setPipDecorInsets(insets: Insets) { + if (pipDecorInsets == insets) return + pipDecorInsets = insets + } + /** * @param open Whether this event marks the opening of an occupied segment * @param pos The coordinate of this event @@ -735,6 +751,25 @@ class TvPipKeepClearAlgorithm(private val clock: () -> Long) { return horizontal && vertical } + /** + * Adds space around [size] to leave space for decorations that will be drawn around the pip + */ + private fun addDecors(size: Size): Size { + val bounds = Rect(0, 0, size.width, size.height) + bounds.inset(pipDecorInsets) + + return Size(bounds.width(), bounds.height()) + } + + /** + * Removes the space that was reserved for decorations around the pip + */ + private fun removeDecors(bounds: Rect): Rect { + val pipDecorReverseInsets = Insets.subtract(Insets.NONE, pipDecorInsets) + bounds.inset(pipDecorReverseInsets) + return bounds + } + private fun Rect.offsetCopy(dx: Int, dy: Int) = Rect(this).apply { offset(dx, dy) } private fun Rect.intersectsY(other: Rect) = bottom >= other.top && top <= other.bottom private fun Rect.intersectsX(other: Rect) = right >= other.left && left <= other.right 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 35c34ac8315f..3e7d10c3fcb8 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 @@ -25,13 +25,17 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.ParceledListSlice; +import android.graphics.Insets; import android.graphics.Matrix; import android.graphics.Rect; import android.graphics.RectF; import android.os.Handler; import android.os.RemoteException; +import android.view.LayoutInflater; import android.view.SurfaceControl; import android.view.SyncRtSurfaceTransactionApplier; +import android.view.View; +import android.view.ViewRootImpl; import android.view.WindowManagerGlobal; import androidx.annotation.Nullable; @@ -53,6 +57,7 @@ import java.util.Objects; public class TvPipMenuController implements PipMenuController, TvPipMenuView.Listener { private static final String TAG = "TvPipMenuController"; private static final boolean DEBUG = TvPipController.DEBUG; + private static final String BACKGROUND_WINDOW_TITLE = "PipBackgroundView"; private final Context mContext; private final SystemWindows mSystemWindows; @@ -62,6 +67,7 @@ public class TvPipMenuController implements PipMenuController, TvPipMenuView.Lis private Delegate mDelegate; private SurfaceControl mLeash; private TvPipMenuView mPipMenuView; + private View mPipBackgroundView; // User can actively move the PiP via the DPAD. private boolean mInMoveMode; @@ -74,6 +80,7 @@ public class TvPipMenuController implements PipMenuController, TvPipMenuView.Lis private RemoteAction mCloseAction; private SyncRtSurfaceTransactionApplier mApplier; + private SyncRtSurfaceTransactionApplier mBackgroundApplier; RectF mTmpSourceRectF = new RectF(); RectF mTmpDestinationRectF = new RectF(); Matrix mMoveTransform = new Matrix(); @@ -91,6 +98,7 @@ public class TvPipMenuController implements PipMenuController, TvPipMenuView.Lis if (DEBUG) e.printStackTrace(); } }; + private final int mPipMenuSurfaceOuterSpace; public TvPipMenuController(Context context, TvPipBoundsState tvPipBoundsState, SystemWindows systemWindows, PipMediaController pipMediaController, @@ -113,6 +121,14 @@ public class TvPipMenuController implements PipMenuController, TvPipMenuView.Lis mainHandler, Context.RECEIVER_EXPORTED); pipMediaController.addActionListener(this::onMediaActionsChanged); + + mPipMenuSurfaceOuterSpace = context.getResources() + .getDimensionPixelSize(R.dimen.pip_menu_outer_space); + + final int pipBorderWidth = context.getResources() + .getDimensionPixelSize(R.dimen.pip_menu_border_width); + mTvPipBoundsState.setPipMenuPermanentDecorInsets(Insets.of(-pipBorderWidth, + -pipBorderWidth, -pipBorderWidth, -pipBorderWidth)); } void setDelegate(Delegate delegate) { @@ -138,24 +154,54 @@ public class TvPipMenuController implements PipMenuController, TvPipMenuView.Lis } mLeash = leash; - attachPipMenuView(); + attachPipMenu(); } - private void attachPipMenuView() { + private void attachPipMenu() { if (DEBUG) { ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE, - "%s: attachPipMenuView()", TAG); + "%s: attachPipMenu()", TAG); } if (mPipMenuView != null) { - detachPipMenuView(); + detachPipMenu(); } + attachPipBackgroundView(); + attachPipMenuView(); + } + + private void attachPipMenuView() { mPipMenuView = new TvPipMenuView(mContext); mPipMenuView.setListener(this); - mSystemWindows.addView(mPipMenuView, - getPipMenuLayoutParams(MENU_WINDOW_TITLE, 0 /* width */, 0 /* height */), - 0, SHELL_ROOT_LAYER_PIP); + setUpViewSurfaceZOrder(mPipMenuView, 1); + addPipMenuViewToSystemWindows(mPipMenuView, MENU_WINDOW_TITLE); + } + + private void attachPipBackgroundView() { + mPipBackgroundView = LayoutInflater.from(mContext) + .inflate(R.layout.tv_pip_menu_background, null); + setUpViewSurfaceZOrder(mPipBackgroundView, -1); + addPipMenuViewToSystemWindows(mPipBackgroundView, BACKGROUND_WINDOW_TITLE); + } + + private void setUpViewSurfaceZOrder(View v, int zOrderRelativeToPip) { + v.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() { + @Override + public void onViewAttachedToWindow(View v) { + v.getViewRootImpl().addSurfaceChangedCallback( + new PipMenuSurfaceChangedCallback(v, zOrderRelativeToPip)); + } + + @Override + public void onViewDetachedFromWindow(View v) { + } + }); + } + + private void addPipMenuViewToSystemWindows(View v, String title) { + mSystemWindows.addView(v, getPipMenuLayoutParams(title, 0 /* width */, 0 /* height */), + 0 /* displayId */, SHELL_ROOT_LAYER_PIP); } void showMovementMenuOnly() { @@ -171,8 +217,7 @@ public class TvPipMenuController implements PipMenuController, TvPipMenuView.Lis @Override public void showMenu() { if (DEBUG) { - ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE, - "%s: showMenu()", TAG); + ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE, "%s: showMenu()", TAG); } mInMoveMode = false; mCloseAfterExitMoveMenu = false; @@ -183,24 +228,14 @@ public class TvPipMenuController implements PipMenuController, TvPipMenuView.Lis if (mPipMenuView == null) { return; } - Rect menuBounds = getMenuBounds(mTvPipBoundsState.getBounds()); - mSystemWindows.updateViewLayout(mPipMenuView, getPipMenuLayoutParams( - MENU_WINDOW_TITLE, menuBounds.width(), menuBounds.height())); maybeUpdateMenuViewActions(); updateExpansionState(); - SurfaceControl menuSurfaceControl = getSurfaceControl(); - if (menuSurfaceControl != null) { - SurfaceControl.Transaction t = new SurfaceControl.Transaction(); - t.setRelativeLayer(mPipMenuView.getWindowSurfaceControl(), mLeash, 1); - t.setPosition(menuSurfaceControl, menuBounds.left, menuBounds.top); - t.apply(); - } grantPipMenuFocus(true); if (mInMoveMode) { mPipMenuView.showMoveMenu(mDelegate.getPipGravity()); } else { - mPipMenuView.showButtonMenu(); + mPipMenuView.showButtonsMenu(); } } @@ -214,11 +249,9 @@ public class TvPipMenuController implements PipMenuController, TvPipMenuView.Lis mPipMenuView.setIsExpanded(mTvPipBoundsState.isTvPipExpanded()); } - private Rect getMenuBounds(Rect pipBounds) { - int extraSpaceInPx = mContext.getResources() - .getDimensionPixelSize(R.dimen.pip_menu_outer_space); + private Rect calculateMenuSurfaceBounds(Rect pipBounds) { Rect menuBounds = new Rect(pipBounds); - menuBounds.inset(-extraSpaceInPx, -extraSpaceInPx); + menuBounds.inset(-mPipMenuSurfaceOuterSpace, -mPipMenuSurfaceOuterSpace); return menuBounds; } @@ -227,11 +260,12 @@ public class TvPipMenuController implements PipMenuController, TvPipMenuView.Lis ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE, "%s: closeMenu()", TAG); } + if (mPipMenuView == null) { return; } - mPipMenuView.hideAll(); + mPipMenuView.hideAllUserControls(); grantPipMenuFocus(false); mDelegate.onMenuClosed(); } @@ -266,7 +300,7 @@ public class TvPipMenuController implements PipMenuController, TvPipMenuView.Lis } if (mInMoveMode) { mInMoveMode = false; - mPipMenuView.showButtonMenu(); + mPipMenuView.showButtonsMenu(); return true; } return false; @@ -287,7 +321,7 @@ public class TvPipMenuController implements PipMenuController, TvPipMenuView.Lis @Override public void detach() { closeMenu(); - detachPipMenuView(); + detachPipMenu(); mLeash = null; } @@ -346,20 +380,15 @@ public class TvPipMenuController implements PipMenuController, TvPipMenuView.Lis @Override public boolean isMenuVisible() { - boolean isVisible = mPipMenuView != null && mPipMenuView.isVisible(); - if (DEBUG) { - ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE, - "%s: isMenuVisible: %b", TAG, isVisible); - } - return isVisible; + return true; } /** * Does an immediate window crop of the PiP menu. */ @Override - public void resizePipMenu(@android.annotation.Nullable SurfaceControl pipLeash, - @android.annotation.Nullable SurfaceControl.Transaction t, + public void resizePipMenu(@Nullable SurfaceControl pipLeash, + @Nullable SurfaceControl.Transaction t, Rect destinationBounds) { if (DEBUG) { ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE, @@ -373,24 +402,36 @@ public class TvPipMenuController implements PipMenuController, TvPipMenuView.Lis return; } - SurfaceControl surfaceControl = getSurfaceControl(); - SyncRtSurfaceTransactionApplier.SurfaceParams - params = new SyncRtSurfaceTransactionApplier.SurfaceParams.Builder(surfaceControl) - .withWindowCrop(getMenuBounds(destinationBounds)) + final Rect menuBounds = calculateMenuSurfaceBounds(destinationBounds); + + final SurfaceControl frontSurface = getSurfaceControl(mPipMenuView); + final SyncRtSurfaceTransactionApplier.SurfaceParams frontParams = + new SyncRtSurfaceTransactionApplier.SurfaceParams.Builder(frontSurface) + .withWindowCrop(menuBounds) .build(); + + final SurfaceControl backSurface = getSurfaceControl(mPipBackgroundView); + final SyncRtSurfaceTransactionApplier.SurfaceParams backParams = + new SyncRtSurfaceTransactionApplier.SurfaceParams.Builder(backSurface) + .withWindowCrop(menuBounds) + .build(); + + // TODO(b/226580399): switch to using SurfaceSyncer (see b/200284684) to synchronize the + // animations of the pip surface with the content of the front and back menu surfaces + mBackgroundApplier.scheduleApply(backParams); if (pipLeash != null && t != null) { - SyncRtSurfaceTransactionApplier.SurfaceParams + final SyncRtSurfaceTransactionApplier.SurfaceParams pipParams = new SyncRtSurfaceTransactionApplier.SurfaceParams.Builder(pipLeash) .withMergeTransaction(t) .build(); - mApplier.scheduleApply(params, pipParams); + mApplier.scheduleApply(frontParams, pipParams); } else { - mApplier.scheduleApply(params); + mApplier.scheduleApply(frontParams); } } - private SurfaceControl getSurfaceControl() { - return mSystemWindows.getViewSurface(mPipMenuView); + private SurfaceControl getSurfaceControl(View v) { + return mSystemWindows.getViewSurface(v); } @Override @@ -412,44 +453,52 @@ public class TvPipMenuController implements PipMenuController, TvPipMenuView.Lis return; } - Rect menuDestBounds = getMenuBounds(pipDestBounds); - Rect mTmpSourceBounds = new Rect(); + final Rect menuDestBounds = calculateMenuSurfaceBounds(pipDestBounds); + final Rect tmpSourceBounds = new Rect(); // If there is no pip leash supplied, that means the PiP leash is already finalized // resizing and the PiP menu is also resized. We then want to do a scale from the current // new menu bounds. if (pipLeash != null && transaction != null) { if (DEBUG) { ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE, - "%s: mTmpSourceBounds based on mPipMenuView.getBoundsOnScreen()", TAG); + "%s: tmpSourceBounds based on mPipMenuView.getBoundsOnScreen()", TAG); } - mPipMenuView.getBoundsOnScreen(mTmpSourceBounds); + mPipMenuView.getBoundsOnScreen(tmpSourceBounds); } else { if (DEBUG) { ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE, - "%s: mTmpSourceBounds based on menu width and height", TAG); + "%s: tmpSourceBounds based on menu width and height", TAG); } - mTmpSourceBounds.set(0, 0, menuDestBounds.width(), menuDestBounds.height()); + tmpSourceBounds.set(0, 0, menuDestBounds.width(), menuDestBounds.height()); } - mTmpSourceRectF.set(mTmpSourceBounds); + mTmpSourceRectF.set(tmpSourceBounds); mTmpDestinationRectF.set(menuDestBounds); - mMoveTransform.setRectToRect(mTmpSourceRectF, mTmpDestinationRectF, Matrix.ScaleToFit.FILL); + mMoveTransform.setTranslate(mTmpDestinationRectF.left, mTmpDestinationRectF.top); - SurfaceControl surfaceControl = getSurfaceControl(); - SyncRtSurfaceTransactionApplier.SurfaceParams params = - new SyncRtSurfaceTransactionApplier.SurfaceParams.Builder( - surfaceControl) + final SurfaceControl frontSurface = getSurfaceControl(mPipMenuView); + final SyncRtSurfaceTransactionApplier.SurfaceParams frontParams = + new SyncRtSurfaceTransactionApplier.SurfaceParams.Builder(frontSurface) .withMatrix(mMoveTransform) .build(); + final SurfaceControl backSurface = getSurfaceControl(mPipBackgroundView); + final SyncRtSurfaceTransactionApplier.SurfaceParams backParams = + new SyncRtSurfaceTransactionApplier.SurfaceParams.Builder(backSurface) + .withMatrix(mMoveTransform) + .build(); + + // TODO(b/226580399): switch to using SurfaceSyncer (see b/200284684) to synchronize the + // animations of the pip surface with the content of the front and back menu surfaces + mBackgroundApplier.scheduleApply(backParams); if (pipLeash != null && transaction != null) { - SyncRtSurfaceTransactionApplier.SurfaceParams - pipParams = new SyncRtSurfaceTransactionApplier.SurfaceParams.Builder(pipLeash) + final SyncRtSurfaceTransactionApplier.SurfaceParams pipParams = + new SyncRtSurfaceTransactionApplier.SurfaceParams.Builder(pipLeash) .withMergeTransaction(transaction) .build(); - mApplier.scheduleApply(params, pipParams); + mApplier.scheduleApply(frontParams, pipParams); } else { - mApplier.scheduleApply(params); + mApplier.scheduleApply(frontParams); } if (mPipMenuView.getViewRootImpl() != null) { @@ -470,29 +519,40 @@ public class TvPipMenuController implements PipMenuController, TvPipMenuView.Lis if (mApplier == null) { mApplier = new SyncRtSurfaceTransactionApplier(mPipMenuView); } + if (mBackgroundApplier == null) { + mBackgroundApplier = new SyncRtSurfaceTransactionApplier(mPipBackgroundView); + } return true; } - private void detachPipMenuView() { - if (mPipMenuView == null) { - return; + private void detachPipMenu() { + if (mPipMenuView != null) { + mApplier = null; + mSystemWindows.removeView(mPipMenuView); + mPipMenuView = null; } - mApplier = null; - mSystemWindows.removeView(mPipMenuView); - mPipMenuView = null; + if (mPipBackgroundView != null) { + mBackgroundApplier = null; + mSystemWindows.removeView(mPipBackgroundView); + mPipBackgroundView = null; + } } @Override public void updateMenuBounds(Rect destinationBounds) { - Rect menuBounds = getMenuBounds(destinationBounds); + final Rect menuBounds = calculateMenuSurfaceBounds(destinationBounds); if (DEBUG) { ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE, "%s: updateMenuBounds: %s", TAG, menuBounds.toShortString()); } + mSystemWindows.updateViewLayout(mPipBackgroundView, + getPipMenuLayoutParams(BACKGROUND_WINDOW_TITLE, menuBounds.width(), + menuBounds.height())); mSystemWindows.updateViewLayout(mPipMenuView, getPipMenuLayoutParams(MENU_WINDOW_TITLE, menuBounds.width(), menuBounds.height())); + if (mPipMenuView != null) { mPipMenuView.updateLayout(destinationBounds); } @@ -555,4 +615,30 @@ public class TvPipMenuController implements PipMenuController, TvPipMenuView.Lis "%s: Unable to update focus, %s", TAG, e); } } + + private class PipMenuSurfaceChangedCallback implements ViewRootImpl.SurfaceChangedCallback { + private final View mView; + private final int mZOrder; + + PipMenuSurfaceChangedCallback(View v, int zOrder) { + mView = v; + mZOrder = zOrder; + } + + @Override + public void surfaceCreated(SurfaceControl.Transaction t) { + final SurfaceControl sc = getSurfaceControl(mView); + if (sc != null) { + t.setRelativeLayer(sc, mLeash, mZOrder); + } + } + + @Override + public void surfaceReplaced(SurfaceControl.Transaction t) { + } + + @Override + public void surfaceDestroyed() { + } + } } 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 9529d04fe185..f5c8871cb991 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 @@ -81,6 +81,8 @@ public class TvPipMenuView extends FrameLayout implements View.OnClickListener { private final TvPipMenuActionButton mExpandButton; private final TvPipMenuActionButton mCloseButton; + private final int mPipMenuFadeAnimationDuration; + public TvPipMenuView(@NonNull Context context) { this(context, null); } @@ -121,6 +123,9 @@ public class TvPipMenuView extends FrameLayout implements View.OnClickListener { mArrowRight = findViewById(R.id.tv_pip_menu_arrow_right); mArrowDown = findViewById(R.id.tv_pip_menu_arrow_down); mArrowLeft = findViewById(R.id.tv_pip_menu_arrow_left); + + mPipMenuFadeAnimationDuration = context.getResources() + .getInteger(R.integer.pip_menu_fade_animation_duration); } void updateLayout(Rect updatedBounds) { @@ -184,30 +189,32 @@ public class TvPipMenuView extends FrameLayout implements View.OnClickListener { if (DEBUG) { ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE, "%s: showMoveMenu()", TAG); } - showMenuButtons(false); + showButtonsMenu(false); showMovementHints(gravity); - showMenuFrame(true); + setFrameHighlighted(true); } - void showButtonMenu() { + void showButtonsMenu() { if (DEBUG) { - ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE, "%s: showButtonMenu()", TAG); + ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE, + "%s: showButtonsMenu()", TAG); } - showMenuButtons(true); + showButtonsMenu(true); hideMovementHints(); - showMenuFrame(true); + setFrameHighlighted(true); } /** * Hides all menu views, including the menu frame. */ - void hideAll() { + void hideAllUserControls() { if (DEBUG) { - ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE, "%s: hideAll()", TAG); + ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE, + "%s: hideAllUserControls()", TAG); } - showMenuButtons(false); + showButtonsMenu(false); hideMovementHints(); - showMenuFrame(false); + setFrameHighlighted(false); } private void animateAlphaTo(float alpha, View view) { @@ -217,7 +224,7 @@ public class TvPipMenuView extends FrameLayout implements View.OnClickListener { view.animate() .alpha(alpha) .setInterpolator(alpha == 0f ? TvPipInterpolators.EXIT : TvPipInterpolators.ENTER) - .setDuration(500) + .setDuration(mPipMenuFadeAnimationDuration) .withStartAction(() -> { if (alpha != 0) { view.setVisibility(VISIBLE); @@ -230,15 +237,6 @@ public class TvPipMenuView extends FrameLayout implements View.OnClickListener { }); } - boolean isVisible() { - return mMenuFrameView.getAlpha() != 0f - || mActionButtonsContainer.getAlpha() != 0f - || mArrowUp.getAlpha() != 0f - || mArrowRight.getAlpha() != 0f - || mArrowDown.getAlpha() != 0f - || mArrowLeft.getAlpha() != 0f; - } - void setAdditionalActions(List<RemoteAction> actions, RemoteAction closeAction, Handler mainHandler) { if (DEBUG) { @@ -423,18 +421,18 @@ public class TvPipMenuView extends FrameLayout implements View.OnClickListener { } /** - * Show or hide the pip user actions. + * Show or hide the pip buttons menu. */ - public void showMenuButtons(boolean show) { + public void showButtonsMenu(boolean show) { if (DEBUG) { ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE, - "%s: showMenuButtons: %b", TAG, show); + "%s: showUserActions: %b", TAG, show); } animateAlphaTo(show ? 1 : 0, mActionButtonsContainer); } - private void showMenuFrame(boolean show) { - animateAlphaTo(show ? 1 : 0, mMenuFrameView); + private void setFrameHighlighted(boolean highlighted) { + mMenuFrameView.setActivated(highlighted); } interface Listener { |