summaryrefslogtreecommitdiff
path: root/libs
diff options
context:
space:
mode:
Diffstat (limited to 'libs')
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java157
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java17
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java20
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java11
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBoundsState.java16
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipKeepClearAlgorithm.kt18
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java3
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/tv/TvPipKeepClearAlgorithmTest.kt59
-rw-r--r--libs/hwui/pipeline/skia/GLFunctorDrawable.cpp11
9 files changed, 268 insertions, 44 deletions
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
index 01f5feb9b13e..3ec8843838fe 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
@@ -16,6 +16,8 @@
package androidx.window.extensions.embedding;
+import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
+
import static androidx.window.extensions.embedding.SplitContainer.getFinishPrimaryWithSecondaryBehavior;
import static androidx.window.extensions.embedding.SplitContainer.getFinishSecondaryWithPrimaryBehavior;
import static androidx.window.extensions.embedding.SplitContainer.isStickyPlaceholderRule;
@@ -93,7 +95,7 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
mSplitRules.clear();
mSplitRules.addAll(rules);
for (int i = mTaskContainers.size() - 1; i >= 0; i--) {
- updateAnimationOverride(mTaskContainers.keyAt(i));
+ updateAnimationOverride(mTaskContainers.valueAt(i));
}
}
@@ -147,15 +149,31 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
return;
}
+ final boolean wasInPip = isInPictureInPicture(container);
container.setInfo(taskFragmentInfo);
+ final boolean isInPip = isInPictureInPicture(container);
// Check if there are no running activities - consider the container empty if there are no
// non-finishing activities left.
if (!taskFragmentInfo.hasRunningActivity()) {
+ // TODO(b/225371112): Don't finish dependent if the last activity is moved to the PIP
+ // Task.
// Do not finish the dependents if this TaskFragment was cleared due to launching
// activity in the Task.
final boolean shouldFinishDependent =
!taskFragmentInfo.isTaskClearedForReuse();
mPresenter.cleanupContainer(container, shouldFinishDependent);
+ } else if (wasInPip && isInPip) {
+ // No update until exit PIP.
+ return;
+ } else if (isInPip) {
+ // Enter PIP.
+ // All overrides will be cleanup.
+ container.setLastRequestedBounds(null /* bounds */);
+ cleanupForEnterPip(container);
+ } else if (wasInPip) {
+ // Exit PIP.
+ // Updates the presentation of the container. Expand or launch placeholder if needed.
+ mPresenter.updateContainer(container);
}
updateCallbackIfNecessary();
}
@@ -174,10 +192,13 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
@Override
public void onTaskFragmentParentInfoChanged(@NonNull IBinder fragmentToken,
@NonNull Configuration parentConfig) {
- TaskFragmentContainer container = getContainer(fragmentToken);
+ final TaskFragmentContainer container = getContainer(fragmentToken);
if (container != null) {
- onTaskBoundsMayChange(container.getTaskId(),
- parentConfig.windowConfiguration.getBounds());
+ onTaskConfigurationChanged(container.getTaskId(), parentConfig);
+ if (isInPictureInPicture(parentConfig)) {
+ // No need to update presentation in PIP until the Task exit PIP.
+ return;
+ }
mPresenter.updateContainer(container);
updateCallbackIfNecessary();
}
@@ -199,44 +220,70 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
}
}
- private void onTaskBoundsMayChange(int taskId, @NonNull Rect taskBounds) {
+ private void onTaskConfigurationChanged(int taskId, @NonNull Configuration config) {
final TaskContainer taskContainer = mTaskContainers.get(taskId);
- if (taskContainer != null && !taskBounds.isEmpty()
- && !taskContainer.mTaskBounds.equals(taskBounds)) {
+ if (taskContainer == null) {
+ return;
+ }
+ final boolean wasInPip = isInPictureInPicture(taskContainer.mConfiguration);
+ final boolean isInPIp = isInPictureInPicture(config);
+ taskContainer.mConfiguration = config;
+
+ // We need to check the animation override when enter/exit PIP or has bounds changed.
+ boolean shouldUpdateAnimationOverride = wasInPip != isInPIp;
+ if (onTaskBoundsMayChange(taskContainer, config.windowConfiguration.getBounds())
+ && !isInPIp) {
+ // We don't care the bounds change when it has already entered PIP.
+ shouldUpdateAnimationOverride = true;
+ }
+ if (shouldUpdateAnimationOverride) {
+ updateAnimationOverride(taskContainer);
+ }
+ }
+
+ /** Returns {@code true} if the bounds is changed. */
+ private boolean onTaskBoundsMayChange(@NonNull TaskContainer taskContainer,
+ @NonNull Rect taskBounds) {
+ if (!taskBounds.isEmpty() && !taskContainer.mTaskBounds.equals(taskBounds)) {
taskContainer.mTaskBounds.set(taskBounds);
- updateAnimationOverride(taskId);
+ return true;
}
+ return false;
}
/**
* Updates if we should override transition animation. We only want to override if the Task
* bounds is large enough for at least one split rule.
*/
- private void updateAnimationOverride(int taskId) {
- final TaskContainer taskContainer = mTaskContainers.get(taskId);
- if (taskContainer == null || !taskContainer.isTaskBoundsInitialized()) {
+ private void updateAnimationOverride(@NonNull TaskContainer taskContainer) {
+ if (!taskContainer.isTaskBoundsInitialized()) {
// We don't know about the Task bounds yet.
return;
}
+ // We only want to override if it supports split.
+ if (supportSplit(taskContainer)) {
+ mPresenter.startOverrideSplitAnimation(taskContainer.mTaskId);
+ } else {
+ mPresenter.stopOverrideSplitAnimation(taskContainer.mTaskId);
+ }
+ }
+
+ private boolean supportSplit(@NonNull TaskContainer taskContainer) {
+ // No split inside PIP.
+ if (isInPictureInPicture(taskContainer.mConfiguration)) {
+ return false;
+ }
// Check if the parent container bounds can support any split rule.
- boolean supportSplit = false;
for (EmbeddingRule rule : mSplitRules) {
if (!(rule instanceof SplitRule)) {
continue;
}
if (mPresenter.shouldShowSideBySide(taskContainer.mTaskBounds, (SplitRule) rule)) {
- supportSplit = true;
- break;
+ return true;
}
}
-
- // We only want to override if it supports split.
- if (supportSplit) {
- mPresenter.startOverrideSplitAnimation(taskId);
- } else {
- mPresenter.stopOverrideSplitAnimation(taskId);
- }
+ return false;
}
void onActivityCreated(@NonNull Activity launchedActivity) {
@@ -250,6 +297,10 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
*/
// TODO(b/190433398): Break down into smaller functions.
void handleActivityCreated(@NonNull Activity launchedActivity) {
+ if (isInPictureInPicture(launchedActivity)) {
+ // We don't embed activity when it is in PIP.
+ return;
+ }
final List<EmbeddingRule> splitRules = getSplitRules();
final TaskFragmentContainer currentContainer = getContainerWithActivity(
launchedActivity.getActivityToken());
@@ -324,6 +375,10 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
}
private void onActivityConfigurationChanged(@NonNull Activity activity) {
+ if (isInPictureInPicture(activity)) {
+ // We don't embed activity when it is in PIP.
+ return;
+ }
final TaskFragmentContainer currentContainer = getContainerWithActivity(
activity.getActivityToken());
@@ -365,9 +420,11 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
}
final TaskContainer taskContainer = mTaskContainers.get(taskId);
taskContainer.mContainers.add(container);
- if (activity != null && !taskContainer.isTaskBoundsInitialized()) {
+ if (activity != null && !taskContainer.isTaskBoundsInitialized()
+ && onTaskBoundsMayChange(taskContainer,
+ SplitPresenter.getTaskBoundsFromActivity(activity))) {
// Initial check before any TaskFragment has appeared.
- onTaskBoundsMayChange(taskId, SplitPresenter.getTaskBoundsFromActivity(activity));
+ updateAnimationOverride(taskContainer);
}
return container;
}
@@ -389,6 +446,40 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
mTaskContainers.get(primaryContainer.getTaskId()).mSplitContainers.add(splitContainer);
}
+ /** Cleanups all the dependencies when the TaskFragment is entering PIP. */
+ private void cleanupForEnterPip(@NonNull TaskFragmentContainer container) {
+ final int taskId = container.getTaskId();
+ final TaskContainer taskContainer = mTaskContainers.get(taskId);
+ if (taskContainer == null) {
+ return;
+ }
+ final List<SplitContainer> splitsToRemove = new ArrayList<>();
+ final Set<TaskFragmentContainer> containersToUpdate = new ArraySet<>();
+ for (SplitContainer splitContainer : taskContainer.mSplitContainers) {
+ if (splitContainer.getPrimaryContainer() != container
+ && splitContainer.getSecondaryContainer() != container) {
+ continue;
+ }
+ splitsToRemove.add(splitContainer);
+ final TaskFragmentContainer splitTf = splitContainer.getPrimaryContainer() == container
+ ? splitContainer.getSecondaryContainer()
+ : splitContainer.getPrimaryContainer();
+ containersToUpdate.add(splitTf);
+ // We don't want the PIP TaskFragment to be removed as a result of any of its dependents
+ // being removed.
+ splitTf.removeContainerToFinishOnExit(container);
+ if (container.getTopNonFinishingActivity() != null) {
+ splitTf.removeActivityToFinishOnExit(container.getTopNonFinishingActivity());
+ }
+ }
+ container.resetDependencies();
+ taskContainer.mSplitContainers.removeAll(splitsToRemove);
+ // If there is any TaskFragment split with the PIP TaskFragment, update their presentations
+ // since the split is dismissed.
+ // We don't want to close any of them even if they are dependencies of the PIP TaskFragment.
+ mPresenter.updateContainers(containersToUpdate);
+ }
+
/**
* Removes the container from bookkeeping records.
*/
@@ -916,6 +1007,10 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
return super.onStartActivity(who, intent, options);
}
final Activity launchingActivity = (Activity) who;
+ if (isInPictureInPicture(launchingActivity)) {
+ // We don't embed activity when it is in PIP.
+ return super.onStartActivity(who, intent, options);
+ }
if (shouldExpand(null, intent, getSplitRules())) {
setLaunchingInExpandedContainer(launchingActivity, options);
@@ -1079,6 +1174,19 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
return !pairRule.shouldClearTop();
}
+ private static boolean isInPictureInPicture(@NonNull Activity activity) {
+ return isInPictureInPicture(activity.getResources().getConfiguration());
+ }
+
+ private static boolean isInPictureInPicture(@NonNull TaskFragmentContainer tf) {
+ return isInPictureInPicture(tf.getInfo().getConfiguration());
+ }
+
+ private static boolean isInPictureInPicture(@Nullable Configuration configuration) {
+ return configuration != null
+ && configuration.windowConfiguration.getWindowingMode() == WINDOWING_MODE_PINNED;
+ }
+
/** Represents TaskFragments and split pairs below a Task. */
@VisibleForTesting
static class TaskContainer {
@@ -1095,6 +1203,9 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
final Set<IBinder> mFinishedContainer = new ArraySet<>();
/** Available window bounds of this Task. */
final Rect mTaskBounds = new Rect();
+ /** Configuration of the Task. */
+ @Nullable
+ Configuration mConfiguration;
TaskContainer(int taskId) {
mTaskId = taskId;
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java
index e4d9edeb4c6e..b55c16e3b45d 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java
@@ -36,6 +36,7 @@ import androidx.annotation.IntDef;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import java.util.Collection;
import java.util.concurrent.Executor;
/**
@@ -65,13 +66,27 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer {
/**
* Updates the presentation of the provided container.
*/
- void updateContainer(TaskFragmentContainer container) {
+ void updateContainer(@NonNull TaskFragmentContainer container) {
final WindowContainerTransaction wct = new WindowContainerTransaction();
mController.updateContainer(wct, container);
applyTransaction(wct);
}
/**
+ * Updates the presentation of the provided containers.
+ */
+ void updateContainers(@NonNull Collection<TaskFragmentContainer> containers) {
+ if (containers.isEmpty()) {
+ return;
+ }
+ final WindowContainerTransaction wct = new WindowContainerTransaction();
+ for (TaskFragmentContainer container : containers) {
+ mController.updateContainer(wct, container);
+ }
+ applyTransaction(wct);
+ }
+
+ /**
* Deletes the specified container and all other associated and dependent containers in the same
* transaction.
*/
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java
index 9a12669f078a..20c929b26acb 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java
@@ -192,6 +192,13 @@ class TaskFragmentContainer {
}
/**
+ * Removes a container that should be finished when this container is finished.
+ */
+ void removeContainerToFinishOnExit(@NonNull TaskFragmentContainer containerToRemove) {
+ mContainersToFinishOnExit.remove(containerToRemove);
+ }
+
+ /**
* Adds an activity that should be finished when this container is finished.
*/
void addActivityToFinishOnExit(@NonNull Activity activityToFinish) {
@@ -199,6 +206,19 @@ class TaskFragmentContainer {
}
/**
+ * Removes an activity that should be finished when this container is finished.
+ */
+ void removeActivityToFinishOnExit(@NonNull Activity activityToRemove) {
+ mActivitiesToFinishOnExit.remove(activityToRemove);
+ }
+
+ /** Removes all dependencies that should be finished when this container is finished. */
+ void resetDependencies() {
+ mContainersToFinishOnExit.clear();
+ mActivitiesToFinishOnExit.clear();
+ }
+
+ /**
* Removes all activities that belong to this process and finishes other containers/activities
* configured to finish together.
*/
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 1a1cd5b27c53..b6fb82852c2f 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
@@ -1225,12 +1225,6 @@ public class BubbleController {
mOverflowListener.applyUpdate(update);
}
- // Collapsing? Do this first before remaining steps.
- if (update.expandedChanged && !update.expanded) {
- mStackView.setExpanded(false);
- mSysuiProxy.requestNotificationShadeTopUi(false, TAG);
- }
-
// Do removals, if any.
ArrayList<Pair<Bubble, Integer>> removedBubbles =
new ArrayList<>(update.removedBubbles);
@@ -1307,6 +1301,11 @@ public class BubbleController {
mStackView.updateBubbleOrder(update.bubbles);
}
+ if (update.expandedChanged && !update.expanded) {
+ mStackView.setExpanded(false);
+ mSysuiProxy.requestNotificationShadeTopUi(false, TAG);
+ }
+
if (update.selectionChanged && mStackView != null) {
mStackView.setSelectedBubble(update.selectedBubble);
if (update.selectedBubble != null) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBoundsState.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBoundsState.java
index ea074993bae1..a3048bd8fabe 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBoundsState.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBoundsState.java
@@ -35,7 +35,7 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
- * TV specific values of the current state of the PIP bounds.
+ * TV specific values of the current state of the PiP bounds.
*/
public class TvPipBoundsState extends PipBoundsState {
@@ -86,7 +86,7 @@ public class TvPipBoundsState extends PipBoundsState {
mTvPipGravity = DEFAULT_TV_GRAVITY;
}
- /** Set the tv expanded bounds of PIP */
+ /** Set the tv expanded bounds of PiP */
public void setTvExpandedSize(@Nullable Size size) {
mTvExpandedSize = size;
}
@@ -97,20 +97,24 @@ public class TvPipBoundsState extends PipBoundsState {
return mTvExpandedSize;
}
- /** Set the PIP aspect ratio for the expanded PIP (TV) that is desired by the app. */
+ /** Set the PiP aspect ratio for the expanded PiP (TV) that is desired by the app. */
public void setDesiredTvExpandedAspectRatio(float aspectRatio, boolean override) {
- if (override || mTvFixedPipOrientation == ORIENTATION_UNDETERMINED || aspectRatio == 0) {
+ if (override || mTvFixedPipOrientation == ORIENTATION_UNDETERMINED) {
mDesiredTvExpandedAspectRatio = aspectRatio;
resetTvPipState();
return;
}
if ((aspectRatio > 1 && mTvFixedPipOrientation == ORIENTATION_HORIZONTAL)
- || (aspectRatio <= 1 && mTvFixedPipOrientation == ORIENTATION_VERTICAL)) {
+ || (aspectRatio <= 1 && mTvFixedPipOrientation == ORIENTATION_VERTICAL)
+ || aspectRatio == 0) {
mDesiredTvExpandedAspectRatio = aspectRatio;
}
}
- /** Get the PIP aspect ratio for the expanded PIP (TV) that is desired by the app. */
+ /**
+ * Get the aspect ratio for the expanded PiP (TV) that is desired, or {@code 0} if it is not
+ * enabled by the app.
+ */
public float getDesiredTvExpandedAspectRatio() {
return mDesiredTvExpandedAspectRatio;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipKeepClearAlgorithm.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipKeepClearAlgorithm.kt
index 4e8e71bd04c4..09d202abfbde 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipKeepClearAlgorithm.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipKeepClearAlgorithm.kt
@@ -133,7 +133,8 @@ class TvPipKeepClearAlgorithm(private val clock: () -> Long) {
val pipAnchorBoundsWithAllDecors =
getNormalPipAnchorBounds(pipSizeWithAllDecors, transformedMovementBounds)
- val pipAnchorBoundsWithPermanentDecors = removeTemporaryDecors(pipAnchorBoundsWithAllDecors)
+ val pipAnchorBoundsWithPermanentDecors =
+ removeTemporaryDecorsTransformed(pipAnchorBoundsWithAllDecors)
val result = calculatePipPositionTransformed(
pipAnchorBoundsWithPermanentDecors,
transformedRestrictedAreas,
@@ -471,12 +472,10 @@ class TvPipKeepClearAlgorithm(private val clock: () -> Long) {
}
fun setPipPermanentDecorInsets(insets: Insets) {
- if (pipPermanentDecorInsets == insets) return
pipPermanentDecorInsets = insets
}
fun setPipTemporaryDecorInsets(insets: Insets) {
- if (pipTemporaryDecorInsets == insets) return
pipTemporaryDecorInsets = insets
}
@@ -781,6 +780,7 @@ class TvPipKeepClearAlgorithm(private val clock: () -> Long) {
/**
* Removes the space that was reserved for permanent decorations around the pip
+ * @param bounds the bounds (in screen space) to remove the insets from
*/
private fun removePermanentDecors(bounds: Rect): Rect {
val pipDecorReverseInsets = Insets.subtract(Insets.NONE, pipPermanentDecorInsets)
@@ -790,11 +790,15 @@ class TvPipKeepClearAlgorithm(private val clock: () -> Long) {
/**
* Removes the space that was reserved for temporary decorations around the pip
+ * @param bounds the bounds (in base case) to remove the insets from
*/
- private fun removeTemporaryDecors(bounds: Rect): Rect {
- val pipDecorReverseInsets = Insets.subtract(Insets.NONE, pipTemporaryDecorInsets)
- bounds.inset(pipDecorReverseInsets)
- return bounds
+ private fun removeTemporaryDecorsTransformed(bounds: Rect): Rect {
+ if (pipTemporaryDecorInsets == Insets.NONE) return bounds
+
+ var reverseInsets = Insets.subtract(Insets.NONE, pipTemporaryDecorInsets)
+ var boundsInScreenSpace = fromTransformedSpace(bounds)
+ boundsInScreenSpace.inset(reverseInsets)
+ return toTransformedSpace(boundsInScreenSpace)
}
private fun Rect.offsetCopy(dx: Int, dy: Int) = Rect(this).apply { offset(dx, dy) }
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 3ea57b0520b7..9154226b7b22 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
@@ -417,7 +417,8 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler {
|| type == TRANSIT_TO_FRONT
|| type == TRANSIT_TO_BACK;
final boolean isTranslucent = (change.getFlags() & FLAG_TRANSLUCENT) != 0;
- if (isOpenOrCloseTransition && !isTranslucent) {
+ if (isOpenOrCloseTransition && !isTranslucent
+ && wallpaperTransit == WALLPAPER_TRANSITION_NONE) {
// Use the overview background as the background for the animation
final Context uiContext = ActivityThread.currentActivityThread()
.getSystemUiContext();
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/tv/TvPipKeepClearAlgorithmTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/tv/TvPipKeepClearAlgorithmTest.kt
index e6ba70e1b60e..9919214642fc 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/tv/TvPipKeepClearAlgorithmTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/tv/TvPipKeepClearAlgorithmTest.kt
@@ -16,6 +16,7 @@
package com.android.wm.shell.pip.tv
+import android.graphics.Insets
import android.graphics.Rect
import android.testing.AndroidTestingRunner
import android.util.Size
@@ -432,6 +433,64 @@ class TvPipKeepClearAlgorithmTest {
assertEquals(currentTime + algorithm.stashDuration, placement.unstashTime)
}
+ @Test
+ fun test_PipInsets() {
+ val permInsets = Insets.of(-1, -2, -3, -4)
+ algorithm.setPipPermanentDecorInsets(permInsets)
+ testInsetsForAllPositions(permInsets)
+
+ val tempInsets = Insets.of(-4, -3, -2, -1)
+ algorithm.setPipPermanentDecorInsets(Insets.NONE)
+ algorithm.setPipTemporaryDecorInsets(tempInsets)
+ testInsetsForAllPositions(tempInsets)
+
+ algorithm.setPipPermanentDecorInsets(permInsets)
+ algorithm.setPipTemporaryDecorInsets(tempInsets)
+ testInsetsForAllPositions(Insets.add(permInsets, tempInsets))
+ }
+
+ private fun testInsetsForAllPositions(insets: Insets) {
+ gravity = Gravity.BOTTOM or Gravity.RIGHT
+ testAnchorPositionWithInsets(insets)
+
+ gravity = Gravity.BOTTOM or Gravity.LEFT
+ testAnchorPositionWithInsets(insets)
+
+ gravity = Gravity.TOP or Gravity.LEFT
+ testAnchorPositionWithInsets(insets)
+
+ gravity = Gravity.TOP or Gravity.RIGHT
+ testAnchorPositionWithInsets(insets)
+
+ pipSize = EXPANDED_WIDE_PIP_SIZE
+
+ gravity = Gravity.BOTTOM
+ testAnchorPositionWithInsets(insets)
+
+ gravity = Gravity.TOP
+ testAnchorPositionWithInsets(insets)
+
+ pipSize = Size(pipSize.height, pipSize.width)
+
+ gravity = Gravity.LEFT
+ testAnchorPositionWithInsets(insets)
+
+ gravity = Gravity.RIGHT
+ testAnchorPositionWithInsets(insets)
+ }
+
+ private fun testAnchorPositionWithInsets(insets: Insets) {
+ var pipRect = Rect(0, 0, pipSize.width, pipSize.height)
+ pipRect.inset(insets)
+ var expectedBounds = Rect()
+ Gravity.apply(gravity, pipRect.width(), pipRect.height(), movementBounds, expectedBounds)
+ val reverseInsets = Insets.subtract(Insets.NONE, insets)
+ expectedBounds.inset(reverseInsets)
+
+ var placement = getActualPlacement()
+ assertEquals(expectedBounds, placement.bounds)
+ }
+
private fun makeSideBar(width: Int, @Gravity.GravityFlags side: Int): Rect {
val sidebar = Rect(0, 0, width, SCREEN_SIZE.height)
if (side == Gravity.RIGHT) {
diff --git a/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp b/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp
index ab00dd5a487c..dc72aead4873 100644
--- a/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp
+++ b/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp
@@ -61,6 +61,17 @@ void GLFunctorDrawable::onDraw(SkCanvas* canvas) {
return;
}
+ // canvas may be an AlphaFilterCanvas, which is intended to draw with a
+ // modified alpha. We do not have a way to do this without drawing into an
+ // extra layer, which would have a performance cost. Draw directly into the
+ // underlying gpu canvas. This matches prior behavior and the behavior in
+ // Vulkan.
+ {
+ auto* gpuCanvas = SkAndroidFrameworkUtils::getBaseWrappedCanvas(canvas);
+ LOG_ALWAYS_FATAL_IF(!gpuCanvas, "GLFunctorDrawable::onDraw is using an invalid canvas!");
+ canvas = gpuCanvas;
+ }
+
// flush will create a GrRenderTarget if not already present.
canvas->flush();