Merge "Add Tv Pip rounded corners tray" into tm-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
b26603d090
@@ -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>
|
||||||
@@ -14,9 +14,20 @@
|
|||||||
~ See the License for the specific language governing permissions and
|
~ See the License for the specific language governing permissions and
|
||||||
~ limitations under the License.
|
~ limitations under the License.
|
||||||
-->
|
-->
|
||||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
<selector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:shape="rectangle">
|
android:exitFadeDuration="@integer/pip_menu_fade_animation_duration">
|
||||||
<corners android:radius="@dimen/pip_menu_border_radius" />
|
<item android:state_activated="true">
|
||||||
<stroke android:width="@dimen/pip_menu_border_width"
|
<shape android:shape="rectangle">
|
||||||
android:color="@color/tv_pip_menu_focus_border" />
|
<corners android:radius="@dimen/pip_menu_border_corner_radius" />
|
||||||
</shape>
|
<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>
|
||||||
|
|||||||
@@ -16,9 +16,10 @@
|
|||||||
-->
|
-->
|
||||||
<!-- Layout for TvPipMenuView -->
|
<!-- Layout for TvPipMenuView -->
|
||||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:id="@+id/tv_pip_menu"
|
android:id="@+id/tv_pip_menu"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent">
|
android:layout_height="match_parent"
|
||||||
|
android:gravity="center|top">
|
||||||
|
|
||||||
<ScrollView
|
<ScrollView
|
||||||
android:id="@+id/tv_pip_menu_scroll"
|
android:id="@+id/tv_pip_menu_scroll"
|
||||||
@@ -92,7 +93,6 @@
|
|||||||
android:id="@+id/tv_pip_menu_frame"
|
android:id="@+id/tv_pip_menu_frame"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:alpha="0"
|
|
||||||
android:layout_margin="@dimen/pip_menu_outer_space_frame"
|
android:layout_margin="@dimen/pip_menu_outer_space_frame"
|
||||||
android:background="@drawable/tv_pip_menu_border"/>
|
android:background="@drawable/tv_pip_menu_border"/>
|
||||||
|
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|
||||||
@@ -22,7 +22,12 @@
|
|||||||
<dimen name="pip_menu_button_margin">4dp</dimen>
|
<dimen name="pip_menu_button_margin">4dp</dimen>
|
||||||
<dimen name="pip_menu_button_wrapper_margin">26dp</dimen>
|
<dimen name="pip_menu_button_wrapper_margin">26dp</dimen>
|
||||||
<dimen name="pip_menu_border_width">4dp</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>
|
<dimen name="pip_menu_outer_space">24dp</dimen>
|
||||||
|
|
||||||
<!-- outer space minus border width -->
|
<!-- outer space minus border width -->
|
||||||
@@ -30,5 +35,7 @@
|
|||||||
|
|
||||||
<dimen name="pip_menu_arrow_size">24dp</dimen>
|
<dimen name="pip_menu_arrow_size">24dp</dimen>
|
||||||
<dimen name="pip_menu_arrow_elevation">5dp</dimen>
|
<dimen name="pip_menu_arrow_elevation">5dp</dimen>
|
||||||
|
|
||||||
|
<dimen name="pip_menu_elevation">1dp</dimen>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
||||||
|
|||||||
@@ -23,4 +23,5 @@
|
|||||||
<color name="tv_pip_menu_icon_bg_focused">#E8EAED</color>
|
<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_icon_bg_unfocused">#990E0E0F</color>
|
||||||
<color name="tv_pip_menu_focus_border">#E8EAED</color>
|
<color name="tv_pip_menu_focus_border">#E8EAED</color>
|
||||||
</resources>
|
<color name="tv_pip_menu_background">#1E232C</color>
|
||||||
|
</resources>
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ import static com.android.wm.shell.pip.tv.TvPipBoundsState.ORIENTATION_VERTICAL;
|
|||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.res.Resources;
|
import android.content.res.Resources;
|
||||||
|
import android.graphics.Insets;
|
||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
import android.os.SystemClock;
|
import android.os.SystemClock;
|
||||||
import android.util.ArraySet;
|
import android.util.ArraySet;
|
||||||
@@ -150,6 +151,7 @@ public class TvPipBoundsAlgorithm extends PipBoundsAlgorithm {
|
|||||||
mKeepClearAlgorithm.setScreenSize(screenSize);
|
mKeepClearAlgorithm.setScreenSize(screenSize);
|
||||||
mKeepClearAlgorithm.setMovementBounds(insetBounds);
|
mKeepClearAlgorithm.setMovementBounds(insetBounds);
|
||||||
mKeepClearAlgorithm.setStashOffset(mTvPipBoundsState.getStashOffset());
|
mKeepClearAlgorithm.setStashOffset(mTvPipBoundsState.getStashOffset());
|
||||||
|
mKeepClearAlgorithm.setPipDecorInsets(mTvPipBoundsState.getPipMenuPermanentDecorInsets());
|
||||||
|
|
||||||
final Placement placement = mKeepClearAlgorithm.calculatePipPosition(
|
final Placement placement = mKeepClearAlgorithm.calculatePipPosition(
|
||||||
pipSize,
|
pipSize,
|
||||||
@@ -340,6 +342,7 @@ public class TvPipBoundsAlgorithm extends PipBoundsAlgorithm {
|
|||||||
final DisplayLayout displayLayout = mTvPipBoundsState.getDisplayLayout();
|
final DisplayLayout displayLayout = mTvPipBoundsState.getDisplayLayout();
|
||||||
final float expandedRatio =
|
final float expandedRatio =
|
||||||
mTvPipBoundsState.getDesiredTvExpandedAspectRatio(); // width / height
|
mTvPipBoundsState.getDesiredTvExpandedAspectRatio(); // width / height
|
||||||
|
final Insets pipDecorations = mTvPipBoundsState.getPipMenuPermanentDecorInsets();
|
||||||
|
|
||||||
final Size expandedSize;
|
final Size expandedSize;
|
||||||
if (expandedRatio == 0) {
|
if (expandedRatio == 0) {
|
||||||
@@ -352,7 +355,8 @@ public class TvPipBoundsAlgorithm extends PipBoundsAlgorithm {
|
|||||||
if (mTvPipBoundsState.getTvFixedPipOrientation() == ORIENTATION_HORIZONTAL) {
|
if (mTvPipBoundsState.getTvFixedPipOrientation() == ORIENTATION_HORIZONTAL) {
|
||||||
expandedSize = mTvPipBoundsState.getTvExpandedSize();
|
expandedSize = mTvPipBoundsState.getTvExpandedSize();
|
||||||
} else {
|
} else {
|
||||||
int maxHeight = displayLayout.height() - (2 * mScreenEdgeInsets.y);
|
int maxHeight = displayLayout.height() - (2 * mScreenEdgeInsets.y)
|
||||||
|
- pipDecorations.top - pipDecorations.bottom;
|
||||||
float aspectRatioHeight = mFixedExpandedWidthInPx / expandedRatio;
|
float aspectRatioHeight = mFixedExpandedWidthInPx / expandedRatio;
|
||||||
|
|
||||||
if (maxHeight > aspectRatioHeight) {
|
if (maxHeight > aspectRatioHeight) {
|
||||||
@@ -374,7 +378,8 @@ public class TvPipBoundsAlgorithm extends PipBoundsAlgorithm {
|
|||||||
if (mTvPipBoundsState.getTvFixedPipOrientation() == ORIENTATION_VERTICAL) {
|
if (mTvPipBoundsState.getTvFixedPipOrientation() == ORIENTATION_VERTICAL) {
|
||||||
expandedSize = mTvPipBoundsState.getTvExpandedSize();
|
expandedSize = mTvPipBoundsState.getTvExpandedSize();
|
||||||
} else {
|
} else {
|
||||||
int maxWidth = displayLayout.width() - (2 * mScreenEdgeInsets.x);
|
int maxWidth = displayLayout.width() - (2 * mScreenEdgeInsets.x)
|
||||||
|
- pipDecorations.left - pipDecorations.right;
|
||||||
float aspectRatioWidth = mFixedExpandedHeightInPx * expandedRatio;
|
float aspectRatioWidth = mFixedExpandedHeightInPx * expandedRatio;
|
||||||
if (maxWidth > aspectRatioWidth) {
|
if (maxWidth > aspectRatioWidth) {
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import android.content.ComponentName;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.pm.ActivityInfo;
|
import android.content.pm.ActivityInfo;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
|
import android.graphics.Insets;
|
||||||
import android.util.Size;
|
import android.util.Size;
|
||||||
import android.view.Gravity;
|
import android.view.Gravity;
|
||||||
|
|
||||||
@@ -60,7 +61,7 @@ public class TvPipBoundsState extends PipBoundsState {
|
|||||||
private @Orientation int mTvFixedPipOrientation;
|
private @Orientation int mTvFixedPipOrientation;
|
||||||
private int mTvPipGravity;
|
private int mTvPipGravity;
|
||||||
private @Nullable Size mTvExpandedSize;
|
private @Nullable Size mTvExpandedSize;
|
||||||
|
private @NonNull Insets mPipMenuPermanentDecorInsets = Insets.NONE;
|
||||||
|
|
||||||
public TvPipBoundsState(@NonNull Context context) {
|
public TvPipBoundsState(@NonNull Context context) {
|
||||||
super(context);
|
super(context);
|
||||||
@@ -159,4 +160,11 @@ public class TvPipBoundsState extends PipBoundsState {
|
|||||||
return mIsTvExpandedPipSupported;
|
return mIsTvExpandedPipSupported;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setPipMenuPermanentDecorInsets(@NonNull Insets permanentInsets) {
|
||||||
|
mPipMenuPermanentDecorInsets = permanentInsets;
|
||||||
|
}
|
||||||
|
|
||||||
|
public @NonNull Insets getPipMenuPermanentDecorInsets() {
|
||||||
|
return mPipMenuPermanentDecorInsets;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package com.android.wm.shell.pip.tv
|
package com.android.wm.shell.pip.tv
|
||||||
|
|
||||||
|
import android.graphics.Insets
|
||||||
import android.graphics.Point
|
import android.graphics.Point
|
||||||
import android.graphics.Rect
|
import android.graphics.Rect
|
||||||
import android.util.Size
|
import android.util.Size
|
||||||
@@ -94,6 +95,9 @@ class TvPipKeepClearAlgorithm(private val clock: () -> Long) {
|
|||||||
private var lastAreasOverlappingUnstashPosition: Set<Rect> = emptySet()
|
private var lastAreasOverlappingUnstashPosition: Set<Rect> = emptySet()
|
||||||
private var lastStashTime: Long = Long.MIN_VALUE
|
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
|
* Calculates the position the PiP should be placed at, taking into consideration the
|
||||||
* given keep clear areas.
|
* given keep clear areas.
|
||||||
@@ -120,7 +124,9 @@ class TvPipKeepClearAlgorithm(private val clock: () -> Long) {
|
|||||||
): Placement {
|
): Placement {
|
||||||
val transformedRestrictedAreas = transformAndFilterAreas(restrictedAreas)
|
val transformedRestrictedAreas = transformAndFilterAreas(restrictedAreas)
|
||||||
val transformedUnrestrictedAreas = transformAndFilterAreas(unrestrictedAreas)
|
val transformedUnrestrictedAreas = transformAndFilterAreas(unrestrictedAreas)
|
||||||
val pipAnchorBounds = getNormalPipAnchorBounds(pipSize, transformedMovementBounds)
|
|
||||||
|
val pipSizeWithDecors = addDecors(pipSize)
|
||||||
|
val pipAnchorBounds = getNormalPipAnchorBounds(pipSizeWithDecors, transformedMovementBounds)
|
||||||
|
|
||||||
val result = calculatePipPositionTransformed(
|
val result = calculatePipPositionTransformed(
|
||||||
pipAnchorBounds,
|
pipAnchorBounds,
|
||||||
@@ -128,12 +134,17 @@ class TvPipKeepClearAlgorithm(private val clock: () -> Long) {
|
|||||||
transformedUnrestrictedAreas
|
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(
|
return Placement(
|
||||||
screenSpaceBounds,
|
pipBounds,
|
||||||
fromTransformedSpace(result.anchorBounds),
|
anchorBounds,
|
||||||
getStashType(screenSpaceBounds, movementBounds),
|
getStashType(pipBounds, movementBounds),
|
||||||
result.unstashDestinationBounds?.let { fromTransformedSpace(it) },
|
unstashedDestBounds,
|
||||||
result.unstashTime
|
result.unstashTime
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -447,6 +458,11 @@ class TvPipKeepClearAlgorithm(private val clock: () -> Long) {
|
|||||||
transformedMovementBounds = toTransformedSpace(movementBounds)
|
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 open Whether this event marks the opening of an occupied segment
|
||||||
* @param pos The coordinate of this event
|
* @param pos The coordinate of this event
|
||||||
@@ -735,6 +751,25 @@ class TvPipKeepClearAlgorithm(private val clock: () -> Long) {
|
|||||||
return horizontal && vertical
|
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.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.intersectsY(other: Rect) = bottom >= other.top && top <= other.bottom
|
||||||
private fun Rect.intersectsX(other: Rect) = right >= other.left && left <= other.right
|
private fun Rect.intersectsX(other: Rect) = right >= other.left && left <= other.right
|
||||||
|
|||||||
@@ -25,13 +25,17 @@ import android.content.Context;
|
|||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.IntentFilter;
|
import android.content.IntentFilter;
|
||||||
import android.content.pm.ParceledListSlice;
|
import android.content.pm.ParceledListSlice;
|
||||||
|
import android.graphics.Insets;
|
||||||
import android.graphics.Matrix;
|
import android.graphics.Matrix;
|
||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
import android.graphics.RectF;
|
import android.graphics.RectF;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.RemoteException;
|
import android.os.RemoteException;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
import android.view.SurfaceControl;
|
import android.view.SurfaceControl;
|
||||||
import android.view.SyncRtSurfaceTransactionApplier;
|
import android.view.SyncRtSurfaceTransactionApplier;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewRootImpl;
|
||||||
import android.view.WindowManagerGlobal;
|
import android.view.WindowManagerGlobal;
|
||||||
|
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
@@ -53,6 +57,7 @@ import java.util.Objects;
|
|||||||
public class TvPipMenuController implements PipMenuController, TvPipMenuView.Listener {
|
public class TvPipMenuController implements PipMenuController, TvPipMenuView.Listener {
|
||||||
private static final String TAG = "TvPipMenuController";
|
private static final String TAG = "TvPipMenuController";
|
||||||
private static final boolean DEBUG = TvPipController.DEBUG;
|
private static final boolean DEBUG = TvPipController.DEBUG;
|
||||||
|
private static final String BACKGROUND_WINDOW_TITLE = "PipBackgroundView";
|
||||||
|
|
||||||
private final Context mContext;
|
private final Context mContext;
|
||||||
private final SystemWindows mSystemWindows;
|
private final SystemWindows mSystemWindows;
|
||||||
@@ -62,6 +67,7 @@ public class TvPipMenuController implements PipMenuController, TvPipMenuView.Lis
|
|||||||
private Delegate mDelegate;
|
private Delegate mDelegate;
|
||||||
private SurfaceControl mLeash;
|
private SurfaceControl mLeash;
|
||||||
private TvPipMenuView mPipMenuView;
|
private TvPipMenuView mPipMenuView;
|
||||||
|
private View mPipBackgroundView;
|
||||||
|
|
||||||
// User can actively move the PiP via the DPAD.
|
// User can actively move the PiP via the DPAD.
|
||||||
private boolean mInMoveMode;
|
private boolean mInMoveMode;
|
||||||
@@ -74,6 +80,7 @@ public class TvPipMenuController implements PipMenuController, TvPipMenuView.Lis
|
|||||||
private RemoteAction mCloseAction;
|
private RemoteAction mCloseAction;
|
||||||
|
|
||||||
private SyncRtSurfaceTransactionApplier mApplier;
|
private SyncRtSurfaceTransactionApplier mApplier;
|
||||||
|
private SyncRtSurfaceTransactionApplier mBackgroundApplier;
|
||||||
RectF mTmpSourceRectF = new RectF();
|
RectF mTmpSourceRectF = new RectF();
|
||||||
RectF mTmpDestinationRectF = new RectF();
|
RectF mTmpDestinationRectF = new RectF();
|
||||||
Matrix mMoveTransform = new Matrix();
|
Matrix mMoveTransform = new Matrix();
|
||||||
@@ -91,6 +98,7 @@ public class TvPipMenuController implements PipMenuController, TvPipMenuView.Lis
|
|||||||
if (DEBUG) e.printStackTrace();
|
if (DEBUG) e.printStackTrace();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
private final int mPipMenuSurfaceOuterSpace;
|
||||||
|
|
||||||
public TvPipMenuController(Context context, TvPipBoundsState tvPipBoundsState,
|
public TvPipMenuController(Context context, TvPipBoundsState tvPipBoundsState,
|
||||||
SystemWindows systemWindows, PipMediaController pipMediaController,
|
SystemWindows systemWindows, PipMediaController pipMediaController,
|
||||||
@@ -113,6 +121,14 @@ public class TvPipMenuController implements PipMenuController, TvPipMenuView.Lis
|
|||||||
mainHandler, Context.RECEIVER_EXPORTED);
|
mainHandler, Context.RECEIVER_EXPORTED);
|
||||||
|
|
||||||
pipMediaController.addActionListener(this::onMediaActionsChanged);
|
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) {
|
void setDelegate(Delegate delegate) {
|
||||||
@@ -138,24 +154,54 @@ public class TvPipMenuController implements PipMenuController, TvPipMenuView.Lis
|
|||||||
}
|
}
|
||||||
|
|
||||||
mLeash = leash;
|
mLeash = leash;
|
||||||
|
attachPipMenu();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void attachPipMenu() {
|
||||||
|
if (DEBUG) {
|
||||||
|
ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
|
||||||
|
"%s: attachPipMenu()", TAG);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mPipMenuView != null) {
|
||||||
|
detachPipMenu();
|
||||||
|
}
|
||||||
|
|
||||||
|
attachPipBackgroundView();
|
||||||
attachPipMenuView();
|
attachPipMenuView();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void attachPipMenuView() {
|
private void attachPipMenuView() {
|
||||||
if (DEBUG) {
|
|
||||||
ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
|
|
||||||
"%s: attachPipMenuView()", TAG);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mPipMenuView != null) {
|
|
||||||
detachPipMenuView();
|
|
||||||
}
|
|
||||||
|
|
||||||
mPipMenuView = new TvPipMenuView(mContext);
|
mPipMenuView = new TvPipMenuView(mContext);
|
||||||
mPipMenuView.setListener(this);
|
mPipMenuView.setListener(this);
|
||||||
mSystemWindows.addView(mPipMenuView,
|
setUpViewSurfaceZOrder(mPipMenuView, 1);
|
||||||
getPipMenuLayoutParams(MENU_WINDOW_TITLE, 0 /* width */, 0 /* height */),
|
addPipMenuViewToSystemWindows(mPipMenuView, MENU_WINDOW_TITLE);
|
||||||
0, SHELL_ROOT_LAYER_PIP);
|
}
|
||||||
|
|
||||||
|
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() {
|
void showMovementMenuOnly() {
|
||||||
@@ -171,8 +217,7 @@ public class TvPipMenuController implements PipMenuController, TvPipMenuView.Lis
|
|||||||
@Override
|
@Override
|
||||||
public void showMenu() {
|
public void showMenu() {
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
|
ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE, "%s: showMenu()", TAG);
|
||||||
"%s: showMenu()", TAG);
|
|
||||||
}
|
}
|
||||||
mInMoveMode = false;
|
mInMoveMode = false;
|
||||||
mCloseAfterExitMoveMenu = false;
|
mCloseAfterExitMoveMenu = false;
|
||||||
@@ -183,24 +228,14 @@ public class TvPipMenuController implements PipMenuController, TvPipMenuView.Lis
|
|||||||
if (mPipMenuView == null) {
|
if (mPipMenuView == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Rect menuBounds = getMenuBounds(mTvPipBoundsState.getBounds());
|
|
||||||
mSystemWindows.updateViewLayout(mPipMenuView, getPipMenuLayoutParams(
|
|
||||||
MENU_WINDOW_TITLE, menuBounds.width(), menuBounds.height()));
|
|
||||||
maybeUpdateMenuViewActions();
|
maybeUpdateMenuViewActions();
|
||||||
updateExpansionState();
|
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);
|
grantPipMenuFocus(true);
|
||||||
if (mInMoveMode) {
|
if (mInMoveMode) {
|
||||||
mPipMenuView.showMoveMenu(mDelegate.getPipGravity());
|
mPipMenuView.showMoveMenu(mDelegate.getPipGravity());
|
||||||
} else {
|
} else {
|
||||||
mPipMenuView.showButtonMenu();
|
mPipMenuView.showButtonsMenu();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -214,11 +249,9 @@ public class TvPipMenuController implements PipMenuController, TvPipMenuView.Lis
|
|||||||
mPipMenuView.setIsExpanded(mTvPipBoundsState.isTvPipExpanded());
|
mPipMenuView.setIsExpanded(mTvPipBoundsState.isTvPipExpanded());
|
||||||
}
|
}
|
||||||
|
|
||||||
private Rect getMenuBounds(Rect pipBounds) {
|
private Rect calculateMenuSurfaceBounds(Rect pipBounds) {
|
||||||
int extraSpaceInPx = mContext.getResources()
|
|
||||||
.getDimensionPixelSize(R.dimen.pip_menu_outer_space);
|
|
||||||
Rect menuBounds = new Rect(pipBounds);
|
Rect menuBounds = new Rect(pipBounds);
|
||||||
menuBounds.inset(-extraSpaceInPx, -extraSpaceInPx);
|
menuBounds.inset(-mPipMenuSurfaceOuterSpace, -mPipMenuSurfaceOuterSpace);
|
||||||
return menuBounds;
|
return menuBounds;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -227,11 +260,12 @@ public class TvPipMenuController implements PipMenuController, TvPipMenuView.Lis
|
|||||||
ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
|
ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
|
||||||
"%s: closeMenu()", TAG);
|
"%s: closeMenu()", TAG);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mPipMenuView == null) {
|
if (mPipMenuView == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
mPipMenuView.hideAll();
|
mPipMenuView.hideAllUserControls();
|
||||||
grantPipMenuFocus(false);
|
grantPipMenuFocus(false);
|
||||||
mDelegate.onMenuClosed();
|
mDelegate.onMenuClosed();
|
||||||
}
|
}
|
||||||
@@ -266,7 +300,7 @@ public class TvPipMenuController implements PipMenuController, TvPipMenuView.Lis
|
|||||||
}
|
}
|
||||||
if (mInMoveMode) {
|
if (mInMoveMode) {
|
||||||
mInMoveMode = false;
|
mInMoveMode = false;
|
||||||
mPipMenuView.showButtonMenu();
|
mPipMenuView.showButtonsMenu();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@@ -287,7 +321,7 @@ public class TvPipMenuController implements PipMenuController, TvPipMenuView.Lis
|
|||||||
@Override
|
@Override
|
||||||
public void detach() {
|
public void detach() {
|
||||||
closeMenu();
|
closeMenu();
|
||||||
detachPipMenuView();
|
detachPipMenu();
|
||||||
mLeash = null;
|
mLeash = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -346,20 +380,15 @@ public class TvPipMenuController implements PipMenuController, TvPipMenuView.Lis
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isMenuVisible() {
|
public boolean isMenuVisible() {
|
||||||
boolean isVisible = mPipMenuView != null && mPipMenuView.isVisible();
|
return true;
|
||||||
if (DEBUG) {
|
|
||||||
ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
|
|
||||||
"%s: isMenuVisible: %b", TAG, isVisible);
|
|
||||||
}
|
|
||||||
return isVisible;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Does an immediate window crop of the PiP menu.
|
* Does an immediate window crop of the PiP menu.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void resizePipMenu(@android.annotation.Nullable SurfaceControl pipLeash,
|
public void resizePipMenu(@Nullable SurfaceControl pipLeash,
|
||||||
@android.annotation.Nullable SurfaceControl.Transaction t,
|
@Nullable SurfaceControl.Transaction t,
|
||||||
Rect destinationBounds) {
|
Rect destinationBounds) {
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
|
ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
|
||||||
@@ -373,24 +402,36 @@ public class TvPipMenuController implements PipMenuController, TvPipMenuView.Lis
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
SurfaceControl surfaceControl = getSurfaceControl();
|
final Rect menuBounds = calculateMenuSurfaceBounds(destinationBounds);
|
||||||
SyncRtSurfaceTransactionApplier.SurfaceParams
|
|
||||||
params = new SyncRtSurfaceTransactionApplier.SurfaceParams.Builder(surfaceControl)
|
final SurfaceControl frontSurface = getSurfaceControl(mPipMenuView);
|
||||||
.withWindowCrop(getMenuBounds(destinationBounds))
|
final SyncRtSurfaceTransactionApplier.SurfaceParams frontParams =
|
||||||
|
new SyncRtSurfaceTransactionApplier.SurfaceParams.Builder(frontSurface)
|
||||||
|
.withWindowCrop(menuBounds)
|
||||||
.build();
|
.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) {
|
if (pipLeash != null && t != null) {
|
||||||
SyncRtSurfaceTransactionApplier.SurfaceParams
|
final SyncRtSurfaceTransactionApplier.SurfaceParams
|
||||||
pipParams = new SyncRtSurfaceTransactionApplier.SurfaceParams.Builder(pipLeash)
|
pipParams = new SyncRtSurfaceTransactionApplier.SurfaceParams.Builder(pipLeash)
|
||||||
.withMergeTransaction(t)
|
.withMergeTransaction(t)
|
||||||
.build();
|
.build();
|
||||||
mApplier.scheduleApply(params, pipParams);
|
mApplier.scheduleApply(frontParams, pipParams);
|
||||||
} else {
|
} else {
|
||||||
mApplier.scheduleApply(params);
|
mApplier.scheduleApply(frontParams);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private SurfaceControl getSurfaceControl() {
|
private SurfaceControl getSurfaceControl(View v) {
|
||||||
return mSystemWindows.getViewSurface(mPipMenuView);
|
return mSystemWindows.getViewSurface(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -412,44 +453,52 @@ public class TvPipMenuController implements PipMenuController, TvPipMenuView.Lis
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Rect menuDestBounds = getMenuBounds(pipDestBounds);
|
final Rect menuDestBounds = calculateMenuSurfaceBounds(pipDestBounds);
|
||||||
Rect mTmpSourceBounds = new Rect();
|
final Rect tmpSourceBounds = new Rect();
|
||||||
// If there is no pip leash supplied, that means the PiP leash is already finalized
|
// 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
|
// resizing and the PiP menu is also resized. We then want to do a scale from the current
|
||||||
// new menu bounds.
|
// new menu bounds.
|
||||||
if (pipLeash != null && transaction != null) {
|
if (pipLeash != null && transaction != null) {
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
|
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 {
|
} else {
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
|
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);
|
mTmpDestinationRectF.set(menuDestBounds);
|
||||||
mMoveTransform.setRectToRect(mTmpSourceRectF, mTmpDestinationRectF, Matrix.ScaleToFit.FILL);
|
mMoveTransform.setTranslate(mTmpDestinationRectF.left, mTmpDestinationRectF.top);
|
||||||
|
|
||||||
SurfaceControl surfaceControl = getSurfaceControl();
|
final SurfaceControl frontSurface = getSurfaceControl(mPipMenuView);
|
||||||
SyncRtSurfaceTransactionApplier.SurfaceParams params =
|
final SyncRtSurfaceTransactionApplier.SurfaceParams frontParams =
|
||||||
new SyncRtSurfaceTransactionApplier.SurfaceParams.Builder(
|
new SyncRtSurfaceTransactionApplier.SurfaceParams.Builder(frontSurface)
|
||||||
surfaceControl)
|
|
||||||
.withMatrix(mMoveTransform)
|
.withMatrix(mMoveTransform)
|
||||||
.build();
|
.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) {
|
if (pipLeash != null && transaction != null) {
|
||||||
SyncRtSurfaceTransactionApplier.SurfaceParams
|
final SyncRtSurfaceTransactionApplier.SurfaceParams pipParams =
|
||||||
pipParams = new SyncRtSurfaceTransactionApplier.SurfaceParams.Builder(pipLeash)
|
new SyncRtSurfaceTransactionApplier.SurfaceParams.Builder(pipLeash)
|
||||||
.withMergeTransaction(transaction)
|
.withMergeTransaction(transaction)
|
||||||
.build();
|
.build();
|
||||||
mApplier.scheduleApply(params, pipParams);
|
mApplier.scheduleApply(frontParams, pipParams);
|
||||||
} else {
|
} else {
|
||||||
mApplier.scheduleApply(params);
|
mApplier.scheduleApply(frontParams);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mPipMenuView.getViewRootImpl() != null) {
|
if (mPipMenuView.getViewRootImpl() != null) {
|
||||||
@@ -470,29 +519,40 @@ public class TvPipMenuController implements PipMenuController, TvPipMenuView.Lis
|
|||||||
if (mApplier == null) {
|
if (mApplier == null) {
|
||||||
mApplier = new SyncRtSurfaceTransactionApplier(mPipMenuView);
|
mApplier = new SyncRtSurfaceTransactionApplier(mPipMenuView);
|
||||||
}
|
}
|
||||||
|
if (mBackgroundApplier == null) {
|
||||||
|
mBackgroundApplier = new SyncRtSurfaceTransactionApplier(mPipBackgroundView);
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void detachPipMenuView() {
|
private void detachPipMenu() {
|
||||||
if (mPipMenuView == null) {
|
if (mPipMenuView != null) {
|
||||||
return;
|
mApplier = null;
|
||||||
|
mSystemWindows.removeView(mPipMenuView);
|
||||||
|
mPipMenuView = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
mApplier = null;
|
if (mPipBackgroundView != null) {
|
||||||
mSystemWindows.removeView(mPipMenuView);
|
mBackgroundApplier = null;
|
||||||
mPipMenuView = null;
|
mSystemWindows.removeView(mPipBackgroundView);
|
||||||
|
mPipBackgroundView = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updateMenuBounds(Rect destinationBounds) {
|
public void updateMenuBounds(Rect destinationBounds) {
|
||||||
Rect menuBounds = getMenuBounds(destinationBounds);
|
final Rect menuBounds = calculateMenuSurfaceBounds(destinationBounds);
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
|
ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
|
||||||
"%s: updateMenuBounds: %s", TAG, menuBounds.toShortString());
|
"%s: updateMenuBounds: %s", TAG, menuBounds.toShortString());
|
||||||
}
|
}
|
||||||
|
mSystemWindows.updateViewLayout(mPipBackgroundView,
|
||||||
|
getPipMenuLayoutParams(BACKGROUND_WINDOW_TITLE, menuBounds.width(),
|
||||||
|
menuBounds.height()));
|
||||||
mSystemWindows.updateViewLayout(mPipMenuView,
|
mSystemWindows.updateViewLayout(mPipMenuView,
|
||||||
getPipMenuLayoutParams(MENU_WINDOW_TITLE, menuBounds.width(),
|
getPipMenuLayoutParams(MENU_WINDOW_TITLE, menuBounds.width(),
|
||||||
menuBounds.height()));
|
menuBounds.height()));
|
||||||
|
|
||||||
if (mPipMenuView != null) {
|
if (mPipMenuView != null) {
|
||||||
mPipMenuView.updateLayout(destinationBounds);
|
mPipMenuView.updateLayout(destinationBounds);
|
||||||
}
|
}
|
||||||
@@ -555,4 +615,30 @@ public class TvPipMenuController implements PipMenuController, TvPipMenuView.Lis
|
|||||||
"%s: Unable to update focus, %s", TAG, e);
|
"%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() {
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -81,6 +81,8 @@ public class TvPipMenuView extends FrameLayout implements View.OnClickListener {
|
|||||||
private final TvPipMenuActionButton mExpandButton;
|
private final TvPipMenuActionButton mExpandButton;
|
||||||
private final TvPipMenuActionButton mCloseButton;
|
private final TvPipMenuActionButton mCloseButton;
|
||||||
|
|
||||||
|
private final int mPipMenuFadeAnimationDuration;
|
||||||
|
|
||||||
public TvPipMenuView(@NonNull Context context) {
|
public TvPipMenuView(@NonNull Context context) {
|
||||||
this(context, null);
|
this(context, null);
|
||||||
}
|
}
|
||||||
@@ -121,6 +123,9 @@ public class TvPipMenuView extends FrameLayout implements View.OnClickListener {
|
|||||||
mArrowRight = findViewById(R.id.tv_pip_menu_arrow_right);
|
mArrowRight = findViewById(R.id.tv_pip_menu_arrow_right);
|
||||||
mArrowDown = findViewById(R.id.tv_pip_menu_arrow_down);
|
mArrowDown = findViewById(R.id.tv_pip_menu_arrow_down);
|
||||||
mArrowLeft = findViewById(R.id.tv_pip_menu_arrow_left);
|
mArrowLeft = findViewById(R.id.tv_pip_menu_arrow_left);
|
||||||
|
|
||||||
|
mPipMenuFadeAnimationDuration = context.getResources()
|
||||||
|
.getInteger(R.integer.pip_menu_fade_animation_duration);
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateLayout(Rect updatedBounds) {
|
void updateLayout(Rect updatedBounds) {
|
||||||
@@ -184,30 +189,32 @@ public class TvPipMenuView extends FrameLayout implements View.OnClickListener {
|
|||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE, "%s: showMoveMenu()", TAG);
|
ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE, "%s: showMoveMenu()", TAG);
|
||||||
}
|
}
|
||||||
showMenuButtons(false);
|
showButtonsMenu(false);
|
||||||
showMovementHints(gravity);
|
showMovementHints(gravity);
|
||||||
showMenuFrame(true);
|
setFrameHighlighted(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void showButtonMenu() {
|
void showButtonsMenu() {
|
||||||
if (DEBUG) {
|
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();
|
hideMovementHints();
|
||||||
showMenuFrame(true);
|
setFrameHighlighted(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hides all menu views, including the menu frame.
|
* Hides all menu views, including the menu frame.
|
||||||
*/
|
*/
|
||||||
void hideAll() {
|
void hideAllUserControls() {
|
||||||
if (DEBUG) {
|
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();
|
hideMovementHints();
|
||||||
showMenuFrame(false);
|
setFrameHighlighted(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void animateAlphaTo(float alpha, View view) {
|
private void animateAlphaTo(float alpha, View view) {
|
||||||
@@ -217,7 +224,7 @@ public class TvPipMenuView extends FrameLayout implements View.OnClickListener {
|
|||||||
view.animate()
|
view.animate()
|
||||||
.alpha(alpha)
|
.alpha(alpha)
|
||||||
.setInterpolator(alpha == 0f ? TvPipInterpolators.EXIT : TvPipInterpolators.ENTER)
|
.setInterpolator(alpha == 0f ? TvPipInterpolators.EXIT : TvPipInterpolators.ENTER)
|
||||||
.setDuration(500)
|
.setDuration(mPipMenuFadeAnimationDuration)
|
||||||
.withStartAction(() -> {
|
.withStartAction(() -> {
|
||||||
if (alpha != 0) {
|
if (alpha != 0) {
|
||||||
view.setVisibility(VISIBLE);
|
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,
|
void setAdditionalActions(List<RemoteAction> actions, RemoteAction closeAction,
|
||||||
Handler mainHandler) {
|
Handler mainHandler) {
|
||||||
if (DEBUG) {
|
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) {
|
if (DEBUG) {
|
||||||
ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
|
ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
|
||||||
"%s: showMenuButtons: %b", TAG, show);
|
"%s: showUserActions: %b", TAG, show);
|
||||||
}
|
}
|
||||||
animateAlphaTo(show ? 1 : 0, mActionButtonsContainer);
|
animateAlphaTo(show ? 1 : 0, mActionButtonsContainer);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showMenuFrame(boolean show) {
|
private void setFrameHighlighted(boolean highlighted) {
|
||||||
animateAlphaTo(show ? 1 : 0, mMenuFrameView);
|
mMenuFrameView.setActivated(highlighted);
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Listener {
|
interface Listener {
|
||||||
|
|||||||
Reference in New Issue
Block a user