summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libs/WindowManager/Shell/res/drawable/tv_pip_menu_background.xml23
-rw-r--r--libs/WindowManager/Shell/res/drawable/tv_pip_menu_border.xml23
-rw-r--r--libs/WindowManager/Shell/res/layout/tv_pip_menu.xml8
-rw-r--r--libs/WindowManager/Shell/res/layout/tv_pip_menu_background.xml28
-rw-r--r--libs/WindowManager/Shell/res/values-tvdpi/dimen.xml9
-rw-r--r--libs/WindowManager/Shell/res/values/colors_tv.xml3
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBoundsAlgorithm.java9
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBoundsState.java10
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipKeepClearAlgorithm.kt47
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java220
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuView.java48
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 {