summaryrefslogtreecommitdiff
path: root/libs
diff options
context:
space:
mode:
Diffstat (limited to 'libs')
-rw-r--r--libs/WindowManager/Shell/res/values-television/config.xml36
-rw-r--r--libs/WindowManager/Shell/res/values/config.xml26
-rw-r--r--libs/WindowManager/Shell/res/values/dimen.xml17
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java34
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java73
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/DismissView.kt58
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java40
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsAlgorithm.java15
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipSurfaceTransactionHelper.java4
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java138
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipDismissTargetHandler.java70
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java17
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuView.java26
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java3
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java6
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTransition.kt7
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTest.kt38
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTestShellTransit.kt4
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsAlgorithmTest.java15
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTestUtils.java2
20 files changed, 403 insertions, 226 deletions
diff --git a/libs/WindowManager/Shell/res/values-television/config.xml b/libs/WindowManager/Shell/res/values-television/config.xml
new file mode 100644
index 000000000000..552048e8be9a
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-television/config.xml
@@ -0,0 +1,36 @@
+<?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.
+ -->
+
+<!-- These resources are around just to allow their values to be customized
+ for TV products. Do not translate. -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+ <!-- The percentage of the screen width to use for the default width or height of
+ picture-in-picture windows. Regardless of the percent set here, calculated size will never
+ be smaller than @dimen/default_minimal_size_pip_resizable_task. -->
+ <item name="config_pictureInPictureDefaultSizePercent" format="float" type="dimen">0.2</item>
+
+ <!-- Default insets [LEFT/RIGHTxTOP/BOTTOM] from the screen edge for picture-in-picture windows.
+ These values are in DPs and will be converted to pixel sizes internally. -->
+ <string translatable="false" name="config_defaultPictureInPictureScreenEdgeInsets">
+ 24x24
+ </string>
+
+ <!-- The default gravity for the picture-in-picture window.
+ Currently, this maps to Gravity.BOTTOM | Gravity.RIGHT -->
+ <integer name="config_defaultPictureInPictureGravity">0x55</integer>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values/config.xml b/libs/WindowManager/Shell/res/values/config.xml
index 1b8032b7077b..d416c060c86c 100644
--- a/libs/WindowManager/Shell/res/values/config.xml
+++ b/libs/WindowManager/Shell/res/values/config.xml
@@ -70,4 +70,30 @@
<!-- Animation duration when exit starting window: reveal app -->
<integer name="starting_window_app_reveal_anim_duration">266</integer>
+
+ <!-- Default insets [LEFT/RIGHTxTOP/BOTTOM] from the screen edge for picture-in-picture windows.
+ These values are in DPs and will be converted to pixel sizes internally. -->
+ <string translatable="false" name="config_defaultPictureInPictureScreenEdgeInsets">
+ 16x16
+ </string>
+
+ <!-- The percentage of the screen width to use for the default width or height of
+ picture-in-picture windows. Regardless of the percent set here, calculated size will never
+ be smaller than @dimen/default_minimal_size_pip_resizable_task. -->
+ <item name="config_pictureInPictureDefaultSizePercent" format="float" type="dimen">0.23</item>
+
+ <!-- The default aspect ratio for picture-in-picture windows. -->
+ <item name="config_pictureInPictureDefaultAspectRatio" format="float" type="dimen">
+ 1.777778
+ </item>
+
+ <!-- This is the limit for the max and min aspect ratio (1 / this value) at which the min size
+ will be used instead of an adaptive size based loosely on area. -->
+ <item name="config_pictureInPictureAspectRatioLimitForMinSize" format="float" type="dimen">
+ 1.777778
+ </item>
+
+ <!-- The default gravity for the picture-in-picture window.
+ Currently, this maps to Gravity.BOTTOM | Gravity.RIGHT -->
+ <integer name="config_defaultPictureInPictureGravity">0x55</integer>
</resources>
diff --git a/libs/WindowManager/Shell/res/values/dimen.xml b/libs/WindowManager/Shell/res/values/dimen.xml
index 8a8231d00195..2c96786bb521 100644
--- a/libs/WindowManager/Shell/res/values/dimen.xml
+++ b/libs/WindowManager/Shell/res/values/dimen.xml
@@ -18,8 +18,8 @@
<dimen name="dismiss_circle_size">96dp</dimen>
<dimen name="dismiss_circle_small">60dp</dimen>
- <!-- The height of the gradient indicating the dismiss edge when moving a PIP. -->
- <dimen name="floating_dismiss_gradient_height">250dp</dimen>
+ <!-- The height of the gradient indicating the dismiss edge when moving a PIP or bubble. -->
+ <dimen name="floating_dismiss_gradient_height">548dp</dimen>
<!-- The padding around a PiP actions. -->
<dimen name="pip_action_padding">16dp</dimen>
@@ -129,6 +129,9 @@
<dimen name="bubble_dismiss_encircle_size">52dp</dimen>
<!-- Padding around the view displayed when the bubble is expanded -->
<dimen name="bubble_expanded_view_padding">16dp</dimen>
+ <!-- Padding for the edge of the expanded view that is closest to the edge of the screen used
+ when displaying in landscape on a large screen. -->
+ <dimen name="bubble_expanded_view_largescreen_landscape_padding">128dp</dimen>
<!-- This should be at least the size of bubble_expanded_view_padding; it is used to include
a slight touch slop around the expanded view. -->
<dimen name="bubble_expanded_view_slop">8dp</dimen>
@@ -251,4 +254,14 @@
<!-- The distance of the shift icon when early exit starting window. -->
<dimen name="starting_surface_early_exit_icon_distance">32dp</dimen>
+
+ <!-- The default minimal size of a PiP task, in both dimensions. -->
+ <dimen name="default_minimal_size_pip_resizable_task">108dp</dimen>
+
+ <!--
+ The overridable minimal size of a PiP task, in both dimensions.
+ Different from default_minimal_size_pip_resizable_task, this is to limit the dimension
+ when the pinned stack size is overridden by app via minWidth/minHeight.
+ -->
+ <dimen name="overridable_minimal_size_pip_resizable_task">48dp</dimen>
</resources>
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
index 241f1a7d4d1c..d0138a488295 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
@@ -47,7 +47,10 @@ import android.app.ActivityManager;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
import android.content.pm.LauncherApps;
import android.content.pm.PackageManager;
@@ -131,6 +134,10 @@ public class BubbleController {
public static final String RIGHT_POSITION = "Right";
public static final String BOTTOM_POSITION = "Bottom";
+ // Should match with PhoneWindowManager
+ private static final String SYSTEM_DIALOG_REASON_KEY = "reason";
+ private static final String SYSTEM_DIALOG_REASON_GESTURE_NAV = "gestureNav";
+
private final Context mContext;
private final BubblesImpl mImpl = new BubblesImpl();
private Bubbles.BubbleExpandListener mExpandListener;
@@ -675,6 +682,7 @@ public class BubbleController {
try {
mAddedToWindowManager = true;
+ registerBroadcastReceiver();
mBubbleData.getOverflow().initialize(this);
mWindowManager.addView(mStackView, mWmLayoutParams);
mStackView.setOnApplyWindowInsetsListener((view, windowInsets) -> {
@@ -717,6 +725,7 @@ public class BubbleController {
try {
mAddedToWindowManager = false;
+ mContext.unregisterReceiver(mBroadcastReceiver);
if (mStackView != null) {
mWindowManager.removeView(mStackView);
mBubbleData.getOverflow().cleanUpExpandedState();
@@ -730,11 +739,34 @@ public class BubbleController {
}
}
+ private void registerBroadcastReceiver() {
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
+ filter.addAction(Intent.ACTION_SCREEN_OFF);
+ mContext.registerReceiver(mBroadcastReceiver, filter);
+ }
+
+ private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (!isStackExpanded()) return; // Nothing to do
+
+ String action = intent.getAction();
+ String reason = intent.getStringExtra(SYSTEM_DIALOG_REASON_KEY);
+ if ((Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)
+ && SYSTEM_DIALOG_REASON_GESTURE_NAV.equals(reason))
+ || Intent.ACTION_SCREEN_OFF.equals(action)) {
+ mMainExecutor.execute(() -> collapseStack());
+ }
+ }
+ };
+
/**
* Called by the BubbleStackView and whenever all bubbles have animated out, and none have been
* added in the meantime.
*/
- void onAllBubblesAnimatedOut() {
+ @VisibleForTesting
+ public void onAllBubblesAnimatedOut() {
if (mStackView != null) {
mStackView.setVisibility(INVISIBLE);
removeFromWindowManagerMaybe();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java
index 75b19fb03e73..bc0db3635e35 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java
@@ -67,7 +67,11 @@ public class BubblePositioner {
/** The max percent of screen width to use for the flyout on phone. */
public static final float FLYOUT_MAX_WIDTH_PERCENT = 0.6f;
/** The percent of screen width that should be used for the expanded view on a large screen. **/
- public static final float EXPANDED_VIEW_LARGE_SCREEN_WIDTH_PERCENT = 0.72f;
+ private static final float EXPANDED_VIEW_LARGE_SCREEN_LANDSCAPE_WIDTH_PERCENT = 0.48f;
+ /** The percent of screen width that should be used for the expanded view on a large screen. **/
+ private static final float EXPANDED_VIEW_LARGE_SCREEN_PORTRAIT_WIDTH_PERCENT = 0.70f;
+ /** The percent of screen width that should be used for the expanded view on a small tablet. **/
+ private static final float EXPANDED_VIEW_SMALL_TABLET_WIDTH_PERCENT = 0.72f;
private Context mContext;
private WindowManager mWindowManager;
@@ -77,6 +81,7 @@ public class BubblePositioner {
private boolean mImeVisible;
private int mImeHeight;
private boolean mIsLargeScreen;
+ private boolean mIsSmallTablet;
private Rect mPositionRect;
private int mDefaultMaxBubbles;
@@ -86,7 +91,8 @@ public class BubblePositioner {
private int mExpandedViewMinHeight;
private int mExpandedViewLargeScreenWidth;
- private int mExpandedViewLargeScreenInset;
+ private int mExpandedViewLargeScreenInsetClosestEdge;
+ private int mExpandedViewLargeScreenInsetFurthestEdge;
private int mOverflowWidth;
private int mExpandedViewPadding;
@@ -127,17 +133,26 @@ public class BubblePositioner {
| WindowInsets.Type.statusBars()
| WindowInsets.Type.displayCutout());
- mIsLargeScreen = mContext.getResources().getConfiguration().smallestScreenWidthDp >= 600;
+ final Rect bounds = windowMetrics.getBounds();
+ Configuration config = mContext.getResources().getConfiguration();
+ mIsLargeScreen = config.smallestScreenWidthDp >= 600;
+ if (mIsLargeScreen) {
+ float largestEdgeDp = Math.max(config.screenWidthDp, config.screenHeightDp);
+ mIsSmallTablet = largestEdgeDp < 960;
+ } else {
+ mIsSmallTablet = false;
+ }
if (BubbleDebugConfig.DEBUG_POSITIONER) {
Log.w(TAG, "update positioner:"
+ " rotation: " + mRotation
+ " insets: " + insets
+ " isLargeScreen: " + mIsLargeScreen
- + " bounds: " + windowMetrics.getBounds()
+ + " isSmallTablet: " + mIsSmallTablet
+ + " bounds: " + bounds
+ " showingInTaskbar: " + mShowingInTaskbar);
}
- updateInternal(mRotation, insets, windowMetrics.getBounds());
+ updateInternal(mRotation, insets, bounds);
}
/**
@@ -172,11 +187,31 @@ public class BubblePositioner {
mSpacingBetweenBubbles = res.getDimensionPixelSize(R.dimen.bubble_spacing);
mDefaultMaxBubbles = res.getInteger(R.integer.bubbles_max_rendered);
mExpandedViewPadding = res.getDimensionPixelSize(R.dimen.bubble_expanded_view_padding);
- mExpandedViewLargeScreenWidth = (int) (bounds.width()
- * EXPANDED_VIEW_LARGE_SCREEN_WIDTH_PERCENT);
- mExpandedViewLargeScreenInset = mIsLargeScreen
- ? (bounds.width() - mExpandedViewLargeScreenWidth) / 2
- : mExpandedViewPadding;
+ if (mIsSmallTablet) {
+ mExpandedViewLargeScreenWidth = (int) (bounds.width()
+ * EXPANDED_VIEW_SMALL_TABLET_WIDTH_PERCENT);
+ } else {
+ mExpandedViewLargeScreenWidth = isLandscape()
+ ? (int) (bounds.width() * EXPANDED_VIEW_LARGE_SCREEN_LANDSCAPE_WIDTH_PERCENT)
+ : (int) (bounds.width() * EXPANDED_VIEW_LARGE_SCREEN_PORTRAIT_WIDTH_PERCENT);
+ }
+ if (mIsLargeScreen) {
+ if (isLandscape() && !mIsSmallTablet) {
+ mExpandedViewLargeScreenInsetClosestEdge = res.getDimensionPixelSize(
+ R.dimen.bubble_expanded_view_largescreen_landscape_padding);
+ mExpandedViewLargeScreenInsetFurthestEdge = bounds.width()
+ - mExpandedViewLargeScreenInsetClosestEdge
+ - mExpandedViewLargeScreenWidth;
+ } else {
+ final int centeredInset = (bounds.width() - mExpandedViewLargeScreenWidth) / 2;
+ mExpandedViewLargeScreenInsetClosestEdge = centeredInset;
+ mExpandedViewLargeScreenInsetFurthestEdge = centeredInset;
+ }
+ } else {
+ mExpandedViewLargeScreenInsetClosestEdge = mExpandedViewPadding;
+ mExpandedViewLargeScreenInsetFurthestEdge = mExpandedViewPadding;
+ }
+
mOverflowWidth = mIsLargeScreen
? mExpandedViewLargeScreenWidth
: res.getDimensionPixelSize(
@@ -328,15 +363,18 @@ public class BubblePositioner {
public int[] getExpandedViewContainerPadding(boolean onLeft, boolean isOverflow) {
final int pointerTotalHeight = mPointerHeight - mPointerOverlap;
if (mIsLargeScreen) {
+ // Note:
+ // If we're in portrait OR if we're a small tablet, then the two insets values will
+ // be equal. If we're landscape and a large tablet, the two values will be different.
// [left, top, right, bottom]
mPaddings[0] = onLeft
- ? mExpandedViewLargeScreenInset - pointerTotalHeight
- : mExpandedViewLargeScreenInset;
+ ? mExpandedViewLargeScreenInsetClosestEdge - pointerTotalHeight
+ : mExpandedViewLargeScreenInsetFurthestEdge;
mPaddings[1] = 0;
mPaddings[2] = onLeft
- ? mExpandedViewLargeScreenInset
- : mExpandedViewLargeScreenInset - pointerTotalHeight;
- // Overflow doesn't show manage button / get padding from it so add padding here for it
+ ? mExpandedViewLargeScreenInsetFurthestEdge
+ : mExpandedViewLargeScreenInsetClosestEdge - pointerTotalHeight;
+ // Overflow doesn't show manage button / get padding from it so add padding here
mPaddings[3] = isOverflow ? mExpandedViewPadding : 0;
return mPaddings;
} else {
@@ -494,12 +532,13 @@ public class BubblePositioner {
float x;
float y;
if (showBubblesVertically()) {
+ int inset = mExpandedViewLargeScreenInsetClosestEdge;
y = rowStart + positionInRow;
int left = mIsLargeScreen
- ? mExpandedViewLargeScreenInset - mExpandedViewPadding - mBubbleSize
+ ? inset - mExpandedViewPadding - mBubbleSize
: mPositionRect.left;
int right = mIsLargeScreen
- ? mPositionRect.right - mExpandedViewLargeScreenInset + mExpandedViewPadding
+ ? mPositionRect.right - inset + mExpandedViewPadding
: mPositionRect.right - mBubbleSize;
x = state.onLeft
? left
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/DismissView.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/DismissView.kt
index 74672a336161..063dac3d4109 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/DismissView.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/DismissView.kt
@@ -16,11 +16,16 @@
package com.android.wm.shell.bubbles
+import android.animation.ObjectAnimator
import android.content.Context
-import android.graphics.drawable.TransitionDrawable
+import android.graphics.Color
+import android.graphics.drawable.GradientDrawable
+import android.util.IntProperty
import android.view.Gravity
import android.view.View
import android.view.ViewGroup
+import android.view.WindowManager
+import android.view.WindowInsets
import android.widget.FrameLayout
import androidx.dynamicanimation.animation.DynamicAnimation
import androidx.dynamicanimation.animation.SpringForce.DAMPING_RATIO_LOW_BOUNCY
@@ -28,8 +33,6 @@ import androidx.dynamicanimation.animation.SpringForce.STIFFNESS_LOW
import com.android.wm.shell.R
import com.android.wm.shell.animation.PhysicsAnimator
import com.android.wm.shell.common.DismissCircleView
-import android.view.WindowInsets
-import android.view.WindowManager
/*
* View that handles interactions between DismissCircleView and BubbleStackView.
@@ -41,9 +44,21 @@ class DismissView(context: Context) : FrameLayout(context) {
private val animator = PhysicsAnimator.getInstance(circle)
private val spring = PhysicsAnimator.SpringConfig(STIFFNESS_LOW, DAMPING_RATIO_LOW_BOUNCY)
- private val DISMISS_SCRIM_FADE_MS = 200
+ private val DISMISS_SCRIM_FADE_MS = 200L
private var wm: WindowManager =
context.getSystemService(Context.WINDOW_SERVICE) as WindowManager
+ private var gradientDrawable = createGradient()
+
+ private val GRADIENT_ALPHA: IntProperty<GradientDrawable> =
+ object : IntProperty<GradientDrawable>("alpha") {
+ override fun setValue(d: GradientDrawable, percent: Int) {
+ d.alpha = percent
+ }
+ override fun get(d: GradientDrawable): Int {
+ return d.alpha
+ }
+ }
+
init {
setLayoutParams(LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
@@ -53,8 +68,7 @@ class DismissView(context: Context) : FrameLayout(context) {
setClipToPadding(false)
setClipChildren(false)
setVisibility(View.INVISIBLE)
- setBackgroundResource(
- R.drawable.floating_dismiss_gradient_transition)
+ setBackgroundDrawable(gradientDrawable)
val targetSize: Int = resources.getDimensionPixelSize(R.dimen.dismiss_circle_size)
addView(circle, LayoutParams(targetSize, targetSize,
@@ -71,7 +85,11 @@ class DismissView(context: Context) : FrameLayout(context) {
if (isShowing) return
isShowing = true
setVisibility(View.VISIBLE)
- (getBackground() as TransitionDrawable).startTransition(DISMISS_SCRIM_FADE_MS)
+ val alphaAnim = ObjectAnimator.ofInt(gradientDrawable, GRADIENT_ALPHA,
+ gradientDrawable.alpha, 255)
+ alphaAnim.setDuration(DISMISS_SCRIM_FADE_MS)
+ alphaAnim.start()
+
animator.cancel()
animator
.spring(DynamicAnimation.TRANSLATION_Y, 0f, spring)
@@ -85,7 +103,10 @@ class DismissView(context: Context) : FrameLayout(context) {
fun hide() {
if (!isShowing) return
isShowing = false
- (getBackground() as TransitionDrawable).reverseTransition(DISMISS_SCRIM_FADE_MS)
+ val alphaAnim = ObjectAnimator.ofInt(gradientDrawable, GRADIENT_ALPHA,
+ gradientDrawable.alpha, 0)
+ alphaAnim.setDuration(DISMISS_SCRIM_FADE_MS)
+ alphaAnim.start()
animator
.spring(DynamicAnimation.TRANSLATION_Y, height.toFloat(),
spring)
@@ -93,6 +114,13 @@ class DismissView(context: Context) : FrameLayout(context) {
.start()
}
+ /**
+ * Cancels the animator for the dismiss target.
+ */
+ fun cancelAnimators() {
+ animator.cancel()
+ }
+
fun updateResources() {
updatePadding()
layoutParams.height = resources.getDimensionPixelSize(
@@ -104,6 +132,20 @@ class DismissView(context: Context) : FrameLayout(context) {
circle.requestLayout()
}
+ private fun createGradient(): GradientDrawable {
+ val gradientColor = context.resources.getColor(android.R.color.system_neutral1_900)
+ val alpha = 0.7f * 255
+ val gradientColorWithAlpha = Color.argb(alpha.toInt(),
+ Color.red(gradientColor),
+ Color.green(gradientColor),
+ Color.blue(gradientColor))
+ val gd = GradientDrawable(
+ GradientDrawable.Orientation.BOTTOM_TOP,
+ intArrayOf(gradientColorWithAlpha, Color.TRANSPARENT))
+ gd.setAlpha(0)
+ return gd
+ }
+
private fun updatePadding() {
val insets: WindowInsets = wm.getCurrentWindowMetrics().getWindowInsets()
val navInset = insets.getInsetsIgnoringVisibility(
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
index f7c92fed5522..8a482fbfa1c4 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
@@ -144,21 +144,42 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange
return Math.max(dividerInset, radius);
}
- /** Gets bounds of the primary split. */
+ /** Gets bounds of the primary split with screen based coordinate. */
public Rect getBounds1() {
return new Rect(mBounds1);
}
- /** Gets bounds of the secondary split. */
+ /** Gets bounds of the primary split with parent based coordinate. */
+ public Rect getRefBounds1() {
+ Rect outBounds = getBounds1();
+ outBounds.offset(-mRootBounds.left, -mRootBounds.top);
+ return outBounds;
+ }
+
+ /** Gets bounds of the secondary split with screen based coordinate. */
public Rect getBounds2() {
return new Rect(mBounds2);
}
- /** Gets bounds of divider window. */
+ /** Gets bounds of the secondary split with parent based coordinate. */
+ public Rect getRefBounds2() {
+ final Rect outBounds = getBounds2();
+ outBounds.offset(-mRootBounds.left, -mRootBounds.top);
+ return outBounds;
+ }
+
+ /** Gets bounds of divider window with screen based coordinate. */
public Rect getDividerBounds() {
return new Rect(mDividerBounds);
}
+ /** Gets bounds of divider window with parent based coordinate. */
+ public Rect getRefDividerBounds() {
+ final Rect outBounds = getDividerBounds();
+ outBounds.offset(-mRootBounds.left, -mRootBounds.top);
+ return outBounds;
+ }
+
/** Returns leash of the current divider bar. */
@Nullable
public SurfaceControl getDividerLeash() {
@@ -452,14 +473,17 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange
SurfaceControl leash2, SurfaceControl dimLayer1, SurfaceControl dimLayer2) {
final SurfaceControl dividerLeash = getDividerLeash();
if (dividerLeash != null) {
- t.setPosition(dividerLeash, mDividerBounds.left, mDividerBounds.top);
+ mTempRect.set(getRefDividerBounds());
+ t.setPosition(dividerLeash, mTempRect.left, mTempRect.top);
// Resets layer of divider bar to make sure it is always on top.
t.setLayer(dividerLeash, SPLIT_DIVIDER_LAYER);
}
- t.setPosition(leash1, mBounds1.left, mBounds1.top)
- .setWindowCrop(leash1, mBounds1.width(), mBounds1.height());
- t.setPosition(leash2, mBounds2.left, mBounds2.top)
- .setWindowCrop(leash2, mBounds2.width(), mBounds2.height());
+ mTempRect.set(getRefBounds1());
+ t.setPosition(leash1, mTempRect.left, mTempRect.top)
+ .setWindowCrop(leash1, mTempRect.width(), mTempRect.height());
+ mTempRect.set(getRefBounds2());
+ t.setPosition(leash2, mTempRect.left, mTempRect.top)
+ .setWindowCrop(leash2, mTempRect.width(), mTempRect.height());
if (mImePositionProcessor.adjustSurfaceLayoutForIme(
t, dividerLeash, leash1, leash2, dimLayer1, dimLayer2)) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsAlgorithm.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsAlgorithm.java
index e29dde2726e3..797df413d262 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsAlgorithm.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsAlgorithm.java
@@ -32,6 +32,7 @@ import android.util.Size;
import android.util.TypedValue;
import android.view.Gravity;
+import com.android.wm.shell.R;
import com.android.wm.shell.common.DisplayLayout;
import java.io.PrintWriter;
@@ -76,15 +77,15 @@ public class PipBoundsAlgorithm {
protected void reloadResources(Context context) {
final Resources res = context.getResources();
mDefaultAspectRatio = res.getFloat(
- com.android.internal.R.dimen.config_pictureInPictureDefaultAspectRatio);
+ R.dimen.config_pictureInPictureDefaultAspectRatio);
mDefaultStackGravity = res.getInteger(
- com.android.internal.R.integer.config_defaultPictureInPictureGravity);
+ R.integer.config_defaultPictureInPictureGravity);
mDefaultMinSize = res.getDimensionPixelSize(
- com.android.internal.R.dimen.default_minimal_size_pip_resizable_task);
+ R.dimen.default_minimal_size_pip_resizable_task);
mOverridableMinSize = res.getDimensionPixelSize(
- com.android.internal.R.dimen.overridable_minimal_size_pip_resizable_task);
+ R.dimen.overridable_minimal_size_pip_resizable_task);
final String screenEdgeInsetsDpString = res.getString(
- com.android.internal.R.string.config_defaultPictureInPictureScreenEdgeInsets);
+ R.string.config_defaultPictureInPictureScreenEdgeInsets);
final Size screenEdgeInsetsDp = !screenEdgeInsetsDpString.isEmpty()
? Size.parseSize(screenEdgeInsetsDpString)
: null;
@@ -96,9 +97,9 @@ public class PipBoundsAlgorithm {
mMaxAspectRatio = res.getFloat(
com.android.internal.R.dimen.config_pictureInPictureMaxAspectRatio);
mDefaultSizePercent = res.getFloat(
- com.android.internal.R.dimen.config_pictureInPictureDefaultSizePercent);
+ R.dimen.config_pictureInPictureDefaultSizePercent);
mMaxAspectRatioForMinSize = res.getFloat(
- com.android.internal.R.dimen.config_pictureInPictureAspectRatioLimitForMinSize);
+ R.dimen.config_pictureInPictureAspectRatioLimitForMinSize);
mMinAspectRatioForMinSize = 1f / mMaxAspectRatioForMinSize;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipSurfaceTransactionHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipSurfaceTransactionHelper.java
index 180e3fb48c9d..d7322ce7beda 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipSurfaceTransactionHelper.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipSurfaceTransactionHelper.java
@@ -138,8 +138,8 @@ public class PipSurfaceTransactionHelper {
// destination are different.
final float scale = srcW <= srcH ? (float) destW / srcW : (float) destH / srcH;
final Rect crop = mTmpDestinationRect;
- crop.set(0, 0, Transitions.ENABLE_SHELL_TRANSITIONS ? destH
- : destW, Transitions.ENABLE_SHELL_TRANSITIONS ? destW : destH);
+ crop.set(0, 0, Transitions.SHELL_TRANSITIONS_ROTATION ? destH
+ : destW, Transitions.SHELL_TRANSITIONS_ROTATION ? destW : destH);
// Inverse scale for crop to fit in screen coordinates.
crop.scale(1 / scale);
crop.offset(insets.left, insets.top);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
index 60aac6806623..91615fe05417 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
@@ -97,7 +97,7 @@ public class PipTransition extends PipTransitionController {
* meaningful if {@link #mInFixedRotation} is true.
*/
@Surface.Rotation
- private int mFixedRotation;
+ private int mEndFixedRotation;
/** Whether the PIP window has fade out for fixed rotation. */
private boolean mHasFadeOut;
@@ -153,7 +153,7 @@ public class PipTransition extends PipTransitionController {
final TransitionInfo.Change currentPipChange = findCurrentPipChange(info);
final TransitionInfo.Change fixedRotationChange = findFixedRotationChange(info);
mInFixedRotation = fixedRotationChange != null;
- mFixedRotation = mInFixedRotation
+ mEndFixedRotation = mInFixedRotation
? fixedRotationChange.getEndFixedRotation()
: ROTATION_UNDEFINED;
@@ -257,7 +257,7 @@ public class PipTransition extends PipTransitionController {
final ActivityManager.RunningTaskInfo taskInfo = mPipOrganizer.getTaskInfo();
if (taskInfo != null) {
startExpandAnimation(taskInfo, mPipOrganizer.getSurfaceControl(),
- new Rect(mExitDestinationBounds));
+ new Rect(mExitDestinationBounds), Surface.ROTATION_0);
}
mExitDestinationBounds.setEmpty();
mCurrentPipTaskToken = null;
@@ -332,30 +332,31 @@ public class PipTransition extends PipTransitionController {
@NonNull SurfaceControl.Transaction finishTransaction,
@NonNull Transitions.TransitionFinishCallback finishCallback,
@NonNull TransitionInfo.Change pipChange) {
- TransitionInfo.Change displayRotationChange = null;
- for (int i = info.getChanges().size() - 1; i >= 0; --i) {
- final TransitionInfo.Change change = info.getChanges().get(i);
- if (change.getMode() == TRANSIT_CHANGE
- && (change.getFlags() & FLAG_IS_DISPLAY) != 0
- && change.getStartRotation() != change.getEndRotation()) {
- displayRotationChange = change;
- break;
- }
- }
-
- if (displayRotationChange != null) {
- // Exiting PIP to fullscreen with orientation change.
- startExpandAndRotationAnimation(info, startTransaction, finishTransaction,
- finishCallback, displayRotationChange, pipChange);
- return;
- }
-
- // When there is no rotation, we can simply expand the PIP window.
mFinishCallback = (wct, wctCB) -> {
mPipOrganizer.onExitPipFinished(pipChange.getTaskInfo());
finishCallback.onTransitionFinished(wct, wctCB);
};
+ // Check if it is Shell rotation.
+ if (Transitions.SHELL_TRANSITIONS_ROTATION) {
+ TransitionInfo.Change displayRotationChange = null;
+ for (int i = info.getChanges().size() - 1; i >= 0; --i) {
+ final TransitionInfo.Change change = info.getChanges().get(i);
+ if (change.getMode() == TRANSIT_CHANGE
+ && (change.getFlags() & FLAG_IS_DISPLAY) != 0
+ && change.getStartRotation() != change.getEndRotation()) {
+ displayRotationChange = change;
+ break;
+ }
+ }
+ if (displayRotationChange != null) {
+ // Exiting PIP to fullscreen with orientation change.
+ startExpandAndRotationAnimation(info, startTransaction, finishTransaction,
+ displayRotationChange, pipChange);
+ return;
+ }
+ }
+
// Set the initial frame as scaling the end to the start.
final Rect destinationBounds = new Rect(pipChange.getEndAbsBounds());
final Point offset = pipChange.getEndRelOffset();
@@ -364,13 +365,41 @@ public class PipTransition extends PipTransitionController {
mSurfaceTransactionHelper.scale(startTransaction, pipChange.getLeash(),
destinationBounds, mPipBoundsState.getBounds());
startTransaction.apply();
- startExpandAnimation(pipChange.getTaskInfo(), pipChange.getLeash(), destinationBounds);
+
+ // Check if it is fixed rotation.
+ final int rotationDelta;
+ if (mInFixedRotation) {
+ final int startRotation = pipChange.getStartRotation();
+ final int endRotation = mEndFixedRotation;
+ rotationDelta = deltaRotation(startRotation, endRotation);
+ final Rect endBounds = new Rect(destinationBounds);
+
+ // Set the end frame since the display won't rotate until fixed rotation is finished
+ // in the next display change transition.
+ rotateBounds(endBounds, destinationBounds, rotationDelta);
+ final int degree, x, y;
+ if (rotationDelta == ROTATION_90) {
+ degree = 90;
+ x = destinationBounds.right;
+ y = destinationBounds.top;
+ } else {
+ degree = -90;
+ x = destinationBounds.left;
+ y = destinationBounds.bottom;
+ }
+ mSurfaceTransactionHelper.rotateAndScaleWithCrop(finishTransaction,
+ pipChange.getLeash(), endBounds, endBounds, new Rect(), degree, x, y,
+ true /* isExpanding */, rotationDelta == ROTATION_270 /* clockwise */);
+ } else {
+ rotationDelta = Surface.ROTATION_0;
+ }
+ startExpandAnimation(pipChange.getTaskInfo(), pipChange.getLeash(), destinationBounds,
+ rotationDelta);
}
private void startExpandAndRotationAnimation(@NonNull TransitionInfo info,
@NonNull SurfaceControl.Transaction startTransaction,
@NonNull SurfaceControl.Transaction finishTransaction,
- @NonNull Transitions.TransitionFinishCallback finishCallback,
@NonNull TransitionInfo.Change displayRotationChange,
@NonNull TransitionInfo.Change pipChange) {
final int rotateDelta = deltaRotation(displayRotationChange.getStartRotation(),
@@ -380,11 +409,6 @@ public class PipTransition extends PipTransitionController {
final CounterRotatorHelper rotator = new CounterRotatorHelper();
rotator.handleClosingChanges(info, startTransaction, displayRotationChange);
- mFinishCallback = (wct, wctCB) -> {
- mPipOrganizer.onExitPipFinished(pipChange.getTaskInfo());
- finishCallback.onTransitionFinished(wct, wctCB);
- };
-
// Get the start bounds in new orientation.
final Rect startBounds = new Rect(pipChange.getStartAbsBounds());
rotateBounds(startBounds, displayRotationChange.getStartAbsBounds(), rotateDelta);
@@ -425,12 +449,11 @@ public class PipTransition extends PipTransitionController {
}
private void startExpandAnimation(final TaskInfo taskInfo, final SurfaceControl leash,
- final Rect destinationBounds) {
- PipAnimationController.PipTransitionAnimator animator =
+ final Rect destinationBounds, final int rotationDelta) {
+ final PipAnimationController.PipTransitionAnimator animator =
mPipAnimationController.getAnimator(taskInfo, leash, mPipBoundsState.getBounds(),
mPipBoundsState.getBounds(), destinationBounds, null,
- TRANSITION_DIRECTION_LEAVE_PIP, 0 /* startingAngle */, Surface.ROTATION_0);
-
+ TRANSITION_DIRECTION_LEAVE_PIP, 0 /* startingAngle */, rotationDelta);
animator.setTransitionDirection(TRANSITION_DIRECTION_LEAVE_PIP)
.setPipAnimationCallback(mPipAnimationCallback)
.setDuration(mEnterExitAnimationDuration)
@@ -526,7 +549,7 @@ public class PipTransition extends PipTransitionController {
mPipTransitionState.setTransitionState(PipTransitionState.ENTERING_PIP);
mFinishCallback = finishCallback;
- final int endRotation = mInFixedRotation ? mFixedRotation : enterPip.getEndRotation();
+ final int endRotation = mInFixedRotation ? mEndFixedRotation : enterPip.getEndRotation();
return startEnterAnimation(enterPip.getTaskInfo(), enterPip.getLeash(),
startTransaction, finishTransaction, enterPip.getStartRotation(),
endRotation);
@@ -545,8 +568,8 @@ public class PipTransition extends PipTransitionController {
taskInfo.pictureInPictureParams, currentBounds);
if (rotationDelta != Surface.ROTATION_0 && mInFixedRotation) {
// Need to get the bounds of new rotation in old rotation for fixed rotation,
- sourceHintRect = computeRotatedBounds(rotationDelta, startRotation, endRotation,
- taskInfo, TRANSITION_DIRECTION_TO_PIP, destinationBounds, sourceHintRect);
+ computeEnterPipRotatedBounds(rotationDelta, startRotation, endRotation, taskInfo,
+ destinationBounds, sourceHintRect);
}
PipAnimationController.PipTransitionAnimator animator;
// Set corner radius for entering pip.
@@ -583,8 +606,6 @@ public class PipTransition extends PipTransitionController {
startTransaction.setMatrix(leash, tmpTransform, new float[9]);
}
if (mOneShotAnimationType == ANIM_TYPE_BOUNDS) {
- // Reverse the rotation for Shell transition animation.
- rotationDelta = deltaRotation(rotationDelta, 0);
animator = mPipAnimationController.getAnimator(taskInfo, leash, currentBounds,
currentBounds, destinationBounds, sourceHintRect, TRANSITION_DIRECTION_TO_PIP,
0 /* startingAngle */, rotationDelta);
@@ -617,33 +638,22 @@ public class PipTransition extends PipTransitionController {
return true;
}
- /** Computes destination bounds in old rotation and returns source hint rect if available. */
- @Nullable
- private Rect computeRotatedBounds(int rotationDelta, int startRotation, int endRotation,
- TaskInfo taskInfo, int direction, Rect outDestinationBounds,
- @Nullable Rect sourceHintRect) {
- if (direction == TRANSITION_DIRECTION_TO_PIP) {
- mPipBoundsState.getDisplayLayout().rotateTo(mContext.getResources(), endRotation);
- final Rect displayBounds = mPipBoundsState.getDisplayBounds();
- outDestinationBounds.set(mPipBoundsAlgorithm.getEntryDestinationBounds());
- // Transform the destination bounds to current display coordinates.
- rotateBounds(outDestinationBounds, displayBounds, endRotation, startRotation);
- // When entering PiP (from button navigation mode), adjust the source rect hint by
- // display cutout if applicable.
- if (sourceHintRect != null && taskInfo.displayCutoutInsets != null) {
- if (rotationDelta == Surface.ROTATION_270) {
- sourceHintRect.offset(taskInfo.displayCutoutInsets.left,
- taskInfo.displayCutoutInsets.top);
- }
+ /** Computes destination bounds in old rotation and updates source hint rect if available. */
+ private void computeEnterPipRotatedBounds(int rotationDelta, int startRotation, int endRotation,
+ TaskInfo taskInfo, Rect outDestinationBounds, @Nullable Rect outSourceHintRect) {
+ mPipBoundsState.getDisplayLayout().rotateTo(mContext.getResources(), endRotation);
+ final Rect displayBounds = mPipBoundsState.getDisplayBounds();
+ outDestinationBounds.set(mPipBoundsAlgorithm.getEntryDestinationBounds());
+ // Transform the destination bounds to current display coordinates.
+ rotateBounds(outDestinationBounds, displayBounds, endRotation, startRotation);
+ // When entering PiP (from button navigation mode), adjust the source rect hint by
+ // display cutout if applicable.
+ if (outSourceHintRect != null && taskInfo.displayCutoutInsets != null) {
+ if (rotationDelta == Surface.ROTATION_270) {
+ outSourceHintRect.offset(taskInfo.displayCutoutInsets.left,
+ taskInfo.displayCutoutInsets.top);
}
- } else if (direction == TRANSITION_DIRECTION_LEAVE_PIP) {
- final Rect rotatedDestinationBounds = new Rect(outDestinationBounds);
- rotateBounds(rotatedDestinationBounds, mPipBoundsState.getDisplayBounds(),
- rotationDelta);
- return PipBoundsAlgorithm.getValidSourceHintRect(taskInfo.pictureInPictureParams,
- rotatedDestinationBounds);
- }
- return sourceHintRect;
+ }
}
private void startExitToSplitAnimation(TransitionInfo info,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipDismissTargetHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipDismissTargetHandler.java
index 915c5939c34b..3115f8afde3b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipDismissTargetHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipDismissTargetHandler.java
@@ -20,27 +20,20 @@ import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_M
import android.content.Context;
import android.content.res.Resources;
-import android.graphics.Insets;
import android.graphics.PixelFormat;
import android.graphics.Point;
import android.graphics.Rect;
-import android.graphics.drawable.TransitionDrawable;
-import android.view.Gravity;
import android.view.MotionEvent;
import android.view.SurfaceControl;
import android.view.View;
-import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.view.WindowInsets;
import android.view.WindowManager;
-import android.widget.FrameLayout;
import androidx.annotation.NonNull;
-import androidx.dynamicanimation.animation.DynamicAnimation;
-import androidx.dynamicanimation.animation.SpringForce;
import com.android.wm.shell.R;
-import com.android.wm.shell.animation.PhysicsAnimator;
+import com.android.wm.shell.bubbles.DismissView;
import com.android.wm.shell.common.DismissCircleView;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.magnetictarget.MagnetizedObject;
@@ -56,9 +49,6 @@ public class PipDismissTargetHandler implements ViewTreeObserver.OnPreDrawListen
/* The multiplier to apply scale the target size by when applying the magnetic field radius */
private static final float MAGNETIC_FIELD_RADIUS_MULTIPLIER = 1.25f;
- /** Duration of the dismiss scrim fading in/out. */
- private static final int DISMISS_TRANSITION_DURATION_MS = 200;
-
/**
* MagnetizedObject wrapper for PIP. This allows the magnetic target library to locate and move
* PIP.
@@ -69,7 +59,7 @@ public class PipDismissTargetHandler implements ViewTreeObserver.OnPreDrawListen
* Container for the dismiss circle, so that it can be animated within the container via
* translation rather than within the WindowManager via slow layout animations.
*/
- private ViewGroup mTargetViewContainer;
+ private DismissView mTargetViewContainer;
/** Circle view used to render the dismiss target. */
private DismissCircleView mTargetView;
@@ -79,16 +69,6 @@ public class PipDismissTargetHandler implements ViewTreeObserver.OnPreDrawListen
*/
private MagnetizedObject.MagneticTarget mMagneticTarget;
- /**
- * PhysicsAnimator instance for animating the dismiss target in/out.
- */
- private PhysicsAnimator<View> mMagneticTargetAnimator;
-
- /** Default configuration to use for springing the dismiss target in/out. */
- private final PhysicsAnimator.SpringConfig mTargetSpringConfig =
- new PhysicsAnimator.SpringConfig(
- SpringForce.STIFFNESS_LOW, SpringForce.DAMPING_RATIO_LOW_BOUNCY);
-
// Allow dragging the PIP to a location to close it
private boolean mEnableDismissDragToEdge;
@@ -125,12 +105,8 @@ public class PipDismissTargetHandler implements ViewTreeObserver.OnPreDrawListen
cleanUpDismissTarget();
}
- mTargetView = new DismissCircleView(mContext);
- mTargetViewContainer = new FrameLayout(mContext);
- mTargetViewContainer.setBackgroundDrawable(
- mContext.getDrawable(R.drawable.floating_dismiss_gradient_transition));
- mTargetViewContainer.setClipChildren(false);
- mTargetViewContainer.addView(mTargetView);
+ mTargetViewContainer = new DismissView(mContext);
+ mTargetView = mTargetViewContainer.getCircle();
mTargetViewContainer.setOnApplyWindowInsetsListener((view, windowInsets) -> {
if (!windowInsets.equals(mWindowInsets)) {
mWindowInsets = windowInsets;
@@ -187,7 +163,6 @@ public class PipDismissTargetHandler implements ViewTreeObserver.OnPreDrawListen
}
});
- mMagneticTargetAnimator = PhysicsAnimator.getInstance(mTargetView);
}
@Override
@@ -213,19 +188,13 @@ public class PipDismissTargetHandler implements ViewTreeObserver.OnPreDrawListen
if (mTargetView == null) {
return;
}
+ if (mTargetViewContainer != null) {
+ mTargetViewContainer.updateResources();
+ }
final Resources res = mContext.getResources();
mTargetSize = res.getDimensionPixelSize(R.dimen.dismiss_circle_size);
mDismissAreaHeight = res.getDimensionPixelSize(R.dimen.floating_dismiss_gradient_height);
- final WindowInsets insets = mWindowManager.getCurrentWindowMetrics().getWindowInsets();
- final Insets navInset = insets.getInsetsIgnoringVisibility(
- WindowInsets.Type.navigationBars());
- final FrameLayout.LayoutParams newParams =
- new FrameLayout.LayoutParams(mTargetSize, mTargetSize);
- newParams.gravity = Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM;
- newParams.bottomMargin = navInset.bottom + mContext.getResources().getDimensionPixelSize(
- R.dimen.floating_dismiss_bottom_margin);
- mTargetView.setLayoutParams(newParams);
// Set the magnetic field radius equal to the target size from the center of the target
setMagneticFieldRadiusPercent(mMagneticFieldRadiusPercent);
@@ -261,7 +230,7 @@ public class PipDismissTargetHandler implements ViewTreeObserver.OnPreDrawListen
/** Adds the magnetic target view to the WindowManager so it's ready to be animated in. */
public void createOrUpdateDismissTarget() {
if (!mTargetViewContainer.isAttachedToWindow()) {
- mMagneticTargetAnimator.cancel();
+ mTargetViewContainer.cancelAnimators();
mTargetViewContainer.setVisibility(View.INVISIBLE);
mTargetViewContainer.getViewTreeObserver().removeOnPreDrawListener(this);
@@ -312,18 +281,8 @@ public class PipDismissTargetHandler implements ViewTreeObserver.OnPreDrawListen
createOrUpdateDismissTarget();
if (mTargetViewContainer.getVisibility() != View.VISIBLE) {
- mTargetView.setTranslationY(mTargetViewContainer.getHeight());
- mTargetViewContainer.setVisibility(View.VISIBLE);
mTargetViewContainer.getViewTreeObserver().addOnPreDrawListener(this);
-
- // Cancel in case we were in the middle of animating it out.
- mMagneticTargetAnimator.cancel();
- mMagneticTargetAnimator
- .spring(DynamicAnimation.TRANSLATION_Y, 0f, mTargetSpringConfig)
- .start();
-
- ((TransitionDrawable) mTargetViewContainer.getBackground()).startTransition(
- DISMISS_TRANSITION_DURATION_MS);
+ mTargetViewContainer.show();
}
}
@@ -332,16 +291,7 @@ public class PipDismissTargetHandler implements ViewTreeObserver.OnPreDrawListen
if (!mEnableDismissDragToEdge) {
return;
}
-
- mMagneticTargetAnimator
- .spring(DynamicAnimation.TRANSLATION_Y,
- mTargetViewContainer.getHeight(),
- mTargetSpringConfig)
- .withEndActions(() -> mTargetViewContainer.setVisibility(View.GONE))
- .start();
-
- ((TransitionDrawable) mTargetViewContainer.getBackground()).reverseTransition(
- DISMISS_TRANSITION_DURATION_MS);
+ mTargetViewContainer.hide();
}
/**
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 69d6c9e0c3bd..32ebe2d6aecf 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
@@ -33,6 +33,7 @@ import android.os.RemoteException;
import android.util.Log;
import android.view.SurfaceControl;
import android.view.SyncRtSurfaceTransactionApplier;
+import android.view.WindowManagerGlobal;
import androidx.annotation.Nullable;
@@ -143,7 +144,6 @@ public class TvPipMenuController implements PipMenuController, TvPipMenuView.Lis
mSystemWindows.addView(mPipMenuView,
getPipMenuLayoutParams(MENU_WINDOW_TITLE, 0 /* width */, 0 /* height */),
0, SHELL_ROOT_LAYER_PIP);
- mPipMenuView.setFocusGrantToken(mSystemWindows.getFocusGrantToken(mPipMenuView));
}
@Override
@@ -164,6 +164,7 @@ public class TvPipMenuController implements PipMenuController, TvPipMenuView.Lis
t.setPosition(menuSurfaceControl, menuBounds.left, menuBounds.top);
t.apply();
}
+ grantPipMenuFocus(true);
mPipMenuView.show(mInMoveMode, mDelegate.getPipGravity());
}
}
@@ -194,8 +195,9 @@ public class TvPipMenuController implements PipMenuController, TvPipMenuView.Lis
if (DEBUG) Log.d(TAG, "hideMenu()");
}
- mPipMenuView.hide(mInMoveMode);
+ mPipMenuView.hide();
if (!mInMoveMode) {
+ grantPipMenuFocus(false);
mDelegate.closeMenu();
}
}
@@ -453,4 +455,15 @@ public class TvPipMenuController implements PipMenuController, TvPipMenuView.Lis
void closePip();
}
+
+ private void grantPipMenuFocus(boolean grantFocus) {
+ if (DEBUG) Log.d(TAG, "grantWindowFocus(" + grantFocus + ")");
+
+ try {
+ WindowManagerGlobal.getWindowSession().grantEmbeddedWindowFocus(null /* window */,
+ mSystemWindows.getFocusGrantToken(mPipMenuView), grantFocus);
+ } catch (Exception e) {
+ Log.e(TAG, "Unable to update focus", e);
+ }
+ }
}
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 773e9bfa8977..3090139f6db9 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
@@ -30,7 +30,6 @@ import android.app.RemoteAction;
import android.content.Context;
import android.graphics.Rect;
import android.os.Handler;
-import android.os.IBinder;
import android.util.AttributeSet;
import android.util.Log;
import android.view.Gravity;
@@ -39,7 +38,6 @@ import android.view.SurfaceControl;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewRootImpl;
-import android.view.WindowManagerGlobal;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
@@ -72,7 +70,6 @@ public class TvPipMenuView extends FrameLayout implements View.OnClickListener {
private final ImageView mArrowRight;
private final ImageView mArrowDown;
private final ImageView mArrowLeft;
- private IBinder mFocusGrantToken = null;
private final ViewGroup mScrollView;
private final ViewGroup mHorizontalScrollView;
@@ -152,10 +149,6 @@ public class TvPipMenuView extends FrameLayout implements View.OnClickListener {
mListener = listener;
}
- void setFocusGrantToken(IBinder token) {
- mFocusGrantToken = token;
- }
-
void setExpandedModeEnabled(boolean enabled) {
mExpandButton.setVisibility(enabled ? VISIBLE : GONE);
}
@@ -170,8 +163,6 @@ public class TvPipMenuView extends FrameLayout implements View.OnClickListener {
void show(boolean inMoveMode, int gravity) {
if (DEBUG) Log.d(TAG, "show(), inMoveMode: " + inMoveMode);
- grantWindowFocus(true);
-
if (inMoveMode) {
showMovementHints(gravity);
} else {
@@ -180,15 +171,11 @@ public class TvPipMenuView extends FrameLayout implements View.OnClickListener {
animateAlphaTo(1, mMenuFrameView);
}
- void hide(boolean isInMoveMode) {
+ void hide() {
if (DEBUG) Log.d(TAG, "hide()");
animateAlphaTo(0, mActionButtonsContainer);
animateAlphaTo(0, mMenuFrameView);
hideMovementHints();
-
- if (!isInMoveMode) {
- grantWindowFocus(false);
- }
}
private void animateAlphaTo(float alpha, View view) {
@@ -217,17 +204,6 @@ public class TvPipMenuView extends FrameLayout implements View.OnClickListener {
|| mArrowLeft.getAlpha() != 0f;
}
- private void grantWindowFocus(boolean grantFocus) {
- if (DEBUG) Log.d(TAG, "grantWindowFocus(" + grantFocus + ")");
-
- try {
- WindowManagerGlobal.getWindowSession().grantEmbeddedWindowFocus(null /* window */,
- mFocusGrantToken, grantFocus);
- } catch (Exception e) {
- Log.e(TAG, "Unable to update focus", e);
- }
- }
-
void setAdditionalActions(List<RemoteAction> actions, Handler mainHandler) {
if (DEBUG) Log.d(TAG, "setAdditionalActions()");
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
index 81dacdb753a7..76641f0e6c21 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
@@ -979,7 +979,8 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
t.setAlpha(dividerLeash, 1);
t.setLayer(dividerLeash, SPLIT_DIVIDER_LAYER);
t.setPosition(dividerLeash,
- mSplitLayout.getDividerBounds().left, mSplitLayout.getDividerBounds().top);
+ mSplitLayout.getRefDividerBounds().left,
+ mSplitLayout.getRefDividerBounds().top);
} else {
t.hide(dividerLeash);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
index 5af15300d10b..4bc5850cd293 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
@@ -26,6 +26,7 @@ import static android.app.ActivityOptions.ANIM_THUMBNAIL_SCALE_DOWN;
import static android.app.ActivityOptions.ANIM_THUMBNAIL_SCALE_UP;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.app.admin.DevicePolicyManager.ACTION_DEVICE_POLICY_RESOURCE_UPDATED;
+import static android.app.admin.DevicePolicyManager.EXTRA_RESOURCE_TYPE;
import static android.app.admin.DevicePolicyManager.EXTRA_RESOURCE_TYPE_DRAWABLE;
import static android.app.admin.DevicePolicyResources.Drawables.Source.PROFILE_SWITCH_ANIMATION;
import static android.app.admin.DevicePolicyResources.Drawables.Style.OUTLINE;
@@ -156,9 +157,8 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler {
private BroadcastReceiver mEnterpriseResourceUpdatedReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
- boolean isDrawable = intent.getBooleanExtra(
- EXTRA_RESOURCE_TYPE_DRAWABLE, /* default= */ false);
- if (!isDrawable) {
+ if (intent.getIntExtra(EXTRA_RESOURCE_TYPE, /* default= */ -1)
+ != EXTRA_RESOURCE_TYPE_DRAWABLE) {
return;
}
updateEnterpriseThumbnailDrawable();
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTransition.kt
index 654fa4ec9446..8d542c8ec9e6 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTransition.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTransition.kt
@@ -56,13 +56,6 @@ abstract class PipTransition(protected val testSpec: FlickerTestParameter) {
.sendBroadcast(createIntentWithAction(broadcastAction))
}
- fun requestOrientationForPip(orientation: Int) {
- instrumentation.context.sendBroadcast(
- createIntentWithAction(Components.PipActivity.ACTION_SET_REQUESTED_ORIENTATION)
- .putExtra(Components.PipActivity.EXTRA_PIP_ORIENTATION, orientation.toString())
- )
- }
-
companion object {
// Corresponds to ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
@JvmStatic
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTest.kt
index d65388bd8cc5..f7384e742a04 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTest.kt
@@ -25,11 +25,14 @@ import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.FlickerTestParameterFactory
import com.android.server.wm.flicker.annotation.Group4
import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.helpers.setRotation
+import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
import com.android.server.wm.flicker.helpers.WindowUtils
import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
+import com.android.server.wm.flicker.rules.RemoveAllTasksButHomeRule.Companion.removeAllTasksButHome
import com.android.wm.shell.flicker.pip.PipTransition.BroadcastActionTrigger.Companion.ORIENTATION_LANDSCAPE
+import com.android.wm.shell.flicker.testapp.Components
import com.android.wm.shell.flicker.testapp.Components.FixedActivity.EXTRA_FIXED_ORIENTATION
-import com.android.wm.shell.flicker.testapp.Components.PipActivity.EXTRA_ENTER_PIP
import org.junit.Assume
import org.junit.Before
import org.junit.FixMethodOrder
@@ -39,7 +42,7 @@ import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
/**
- * Test Pip with orientation changes.
+ * Test exiting Pip with orientation changes.
* To run this test: `atest WMShellFlickerTests:SetRequestedOrientationWhilePinnedTest`
*/
@RequiresDevice
@@ -61,30 +64,41 @@ open class SetRequestedOrientationWhilePinnedTest(
override val transition: FlickerBuilder.() -> Unit
get() = {
- setupAndTeardown(this)
-
setup {
+ test {
+ removeAllTasksButHome()
+ device.wakeUpAndGoToHomeScreen()
+ }
eachRun {
- // Launch the PiP activity fixed as landscape
+ // Launch the PiP activity fixed as landscape.
pipApp.launchViaIntent(wmHelper, stringExtras = mapOf(
- EXTRA_FIXED_ORIENTATION to ORIENTATION_LANDSCAPE.toString(),
- EXTRA_ENTER_PIP to "true"))
+ EXTRA_FIXED_ORIENTATION to ORIENTATION_LANDSCAPE.toString()))
+ // Enter PiP.
+ broadcastActionTrigger.doAction(Components.PipActivity.ACTION_ENTER_PIP)
+ wmHelper.waitPipShown()
+ wmHelper.waitForRotation(Surface.ROTATION_0)
+ wmHelper.waitForAppTransitionIdle()
+ // System bar may fade out during fixed rotation.
+ wmHelper.waitForNavBarStatusBarVisible()
}
}
teardown {
eachRun {
pipApp.exit(wmHelper)
+ setRotation(Surface.ROTATION_0)
+ }
+ test {
+ removeAllTasksButHome()
}
}
transitions {
- // Request that the orientation is set to landscape
- broadcastActionTrigger.requestOrientationForPip(ORIENTATION_LANDSCAPE)
-
- // Launch the activity back into fullscreen and
- // ensure that it is now in landscape
+ // Launch the activity back into fullscreen and ensure that it is now in landscape
pipApp.launchViaIntent(wmHelper)
wmHelper.waitForFullScreenApp(pipApp.component)
wmHelper.waitForRotation(Surface.ROTATION_90)
+ wmHelper.waitForAppTransitionIdle()
+ // System bar may fade out during fixed rotation.
+ wmHelper.waitForNavBarStatusBarVisible()
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTestShellTransit.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTestShellTransit.kt
index 36e28049864f..8d764a8d0e69 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTestShellTransit.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTestShellTransit.kt
@@ -29,6 +29,10 @@ import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
+/**
+ * Test exiting Pip with orientation changes.
+ * To run this test: `atest WMShellFlickerTests:SetRequestedOrientationWhilePinnedTestShellTransit`
+ */
@RequiresDevice
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsAlgorithmTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsAlgorithmTest.java
index 90f898aa09da..0059846c6055 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsAlgorithmTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsAlgorithmTest.java
@@ -29,6 +29,7 @@ import android.view.Gravity;
import androidx.test.filters.SmallTest;
+import com.android.wm.shell.R;
import com.android.wm.shell.ShellTestCase;
import com.android.wm.shell.common.DisplayLayout;
@@ -72,16 +73,16 @@ public class PipBoundsAlgorithmTest extends ShellTestCase {
private void initializeMockResources() {
final TestableResources res = mContext.getOrCreateTestableResources();
res.addOverride(
- com.android.internal.R.dimen.config_pictureInPictureDefaultAspectRatio,
+ R.dimen.config_pictureInPictureDefaultAspectRatio,
DEFAULT_ASPECT_RATIO);
res.addOverride(
- com.android.internal.R.integer.config_defaultPictureInPictureGravity,
+ R.integer.config_defaultPictureInPictureGravity,
Gravity.END | Gravity.BOTTOM);
res.addOverride(
- com.android.internal.R.dimen.default_minimal_size_pip_resizable_task,
+ R.dimen.default_minimal_size_pip_resizable_task,
DEFAULT_MIN_EDGE_SIZE);
res.addOverride(
- com.android.internal.R.string.config_defaultPictureInPictureScreenEdgeInsets,
+ R.string.config_defaultPictureInPictureScreenEdgeInsets,
"16x16");
res.addOverride(
com.android.internal.R.dimen.config_pictureInPictureMinAspectRatio,
@@ -107,7 +108,7 @@ public class PipBoundsAlgorithmTest extends ShellTestCase {
public void onConfigurationChanged_reloadResources() {
final float newDefaultAspectRatio = (DEFAULT_ASPECT_RATIO + MAX_ASPECT_RATIO) / 2;
final TestableResources res = mContext.getOrCreateTestableResources();
- res.addOverride(com.android.internal.R.dimen.config_pictureInPictureDefaultAspectRatio,
+ res.addOverride(R.dimen.config_pictureInPictureDefaultAspectRatio,
newDefaultAspectRatio);
mPipBoundsAlgorithm.onConfigurationChanged(mContext);
@@ -463,7 +464,7 @@ public class PipBoundsAlgorithmTest extends ShellTestCase {
private void overrideDefaultAspectRatio(float aspectRatio) {
final TestableResources res = mContext.getOrCreateTestableResources();
res.addOverride(
- com.android.internal.R.dimen.config_pictureInPictureDefaultAspectRatio,
+ R.dimen.config_pictureInPictureDefaultAspectRatio,
aspectRatio);
mPipBoundsAlgorithm.onConfigurationChanged(mContext);
}
@@ -471,7 +472,7 @@ public class PipBoundsAlgorithmTest extends ShellTestCase {
private void overrideDefaultStackGravity(int stackGravity) {
final TestableResources res = mContext.getOrCreateTestableResources();
res.addOverride(
- com.android.internal.R.integer.config_defaultPictureInPictureGravity,
+ R.integer.config_defaultPictureInPictureGravity,
stackGravity);
mPipBoundsAlgorithm.onConfigurationChanged(mContext);
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTestUtils.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTestUtils.java
index dda1a8295e51..85527c81ad9e 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTestUtils.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTestUtils.java
@@ -18,6 +18,7 @@ package com.android.wm.shell.splitscreen;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.window.DisplayAreaOrganizer.FEATURE_DEFAULT_TASK_CONTAINER;
+
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
@@ -51,6 +52,7 @@ public class SplitTestUtils {
final SurfaceControl leash = createMockSurface();
SplitLayout out = mock(SplitLayout.class);
doReturn(dividerBounds).when(out).getDividerBounds();
+ doReturn(dividerBounds).when(out).getRefDividerBounds();
doReturn(leash).when(out).getDividerLeash();
return out;
}