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.java51
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java85
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationRunner.java4
-rw-r--r--libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/EmbeddingTestUtils.java27
-rw-r--r--libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java116
-rw-r--r--libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitPresenterTest.java54
-rw-r--r--libs/WindowManager/Shell/res/values-television/config.xml9
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipSurfaceTransactionHelper.java8
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java21
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java4
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java4
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/tv/OWNERS2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java6
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/transition/LegacyTransitions.java2
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/BaseBubbleScreen.kt6
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/LaunchBubbleFromLockScreen.kt15
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/AppPairsHelper.kt36
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/BaseAppHelper.kt2
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/ImeAppHelper.kt32
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/PipAppHelper.kt37
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipOnUserLeaveHintTest.kt4
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt10
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationTest.kt12
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipTransition.kt8
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipViaExpandButtonClickTest.kt6
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipViaIntentTest.kt6
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipWithSwipeDownTest.kt13
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt6
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTransition.kt6
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTest.kt23
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipBasicTest.kt4
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipMenuTests.kt4
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipNotificationTests.kt14
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipTestBase.kt4
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromAllApps.kt5
-rw-r--r--libs/input/SpriteController.cpp32
-rw-r--r--libs/input/SpriteController.h2
-rw-r--r--libs/protoutil/Android.bp3
40 files changed, 474 insertions, 213 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 b15dce7f3f17..41791afa45a3 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
@@ -24,9 +24,9 @@ import static androidx.window.extensions.embedding.SplitContainer.getFinishSecon
import static androidx.window.extensions.embedding.SplitContainer.isStickyPlaceholderRule;
import static androidx.window.extensions.embedding.SplitContainer.shouldFinishAssociatedContainerWhenAdjacent;
import static androidx.window.extensions.embedding.SplitContainer.shouldFinishAssociatedContainerWhenStacked;
-import static androidx.window.extensions.embedding.SplitPresenter.boundsSmallerThanMinDimensions;
+import static androidx.window.extensions.embedding.SplitPresenter.RESULT_EXPAND_FAILED_NO_TF_INFO;
import static androidx.window.extensions.embedding.SplitPresenter.getActivityIntentMinDimensionsPair;
-import static androidx.window.extensions.embedding.SplitPresenter.getMinDimensions;
+import static androidx.window.extensions.embedding.SplitPresenter.getNonEmbeddedActivityBounds;
import static androidx.window.extensions.embedding.SplitPresenter.shouldShowSideBySide;
import android.app.Activity;
@@ -381,6 +381,7 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
* in a state that the caller shouldn't handle.
*/
@VisibleForTesting
+ @GuardedBy("mLock")
boolean resolveActivityToContainer(@NonNull Activity activity, boolean isOnReparent) {
if (isInPictureInPicture(activity) || activity.isFinishing()) {
// We don't embed activity when it is in PIP, or finishing. Return true since we don't
@@ -581,8 +582,9 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
}
/** Finds the activity below the given activity. */
+ @VisibleForTesting
@Nullable
- private Activity findActivityBelow(@NonNull Activity activity) {
+ Activity findActivityBelow(@NonNull Activity activity) {
Activity activityBelow = null;
final TaskFragmentContainer container = getContainerWithActivity(activity);
if (container != null) {
@@ -606,6 +608,7 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
* Checks if there is a rule to split the two activities. If there is one, puts them into split
* and returns {@code true}. Otherwise, returns {@code false}.
*/
+ @GuardedBy("mLock")
private boolean putActivitiesIntoSplitIfNecessary(@NonNull Activity primaryActivity,
@NonNull Activity secondaryActivity) {
final SplitPairRule splitRule = getSplitRule(primaryActivity, secondaryActivity);
@@ -616,25 +619,25 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
primaryActivity);
final SplitContainer splitContainer = getActiveSplitForContainer(primaryContainer);
if (splitContainer != null && primaryContainer == splitContainer.getPrimaryContainer()
- && canReuseContainer(splitRule, splitContainer.getSplitRule())
- && !boundsSmallerThanMinDimensions(primaryContainer.getLastRequestedBounds(),
- getMinDimensions(primaryActivity))) {
+ && canReuseContainer(splitRule, splitContainer.getSplitRule())) {
// Can launch in the existing secondary container if the rules share the same
// presentation.
final TaskFragmentContainer secondaryContainer = splitContainer.getSecondaryContainer();
- if (secondaryContainer == getContainerWithActivity(secondaryActivity)
- && !boundsSmallerThanMinDimensions(secondaryContainer.getLastRequestedBounds(),
- getMinDimensions(secondaryActivity))) {
+ if (secondaryContainer == getContainerWithActivity(secondaryActivity)) {
// The activity is already in the target TaskFragment.
return true;
}
secondaryContainer.addPendingAppearedActivity(secondaryActivity);
final WindowContainerTransaction wct = new WindowContainerTransaction();
- wct.reparentActivityToTaskFragment(
- secondaryContainer.getTaskFragmentToken(),
- secondaryActivity.getActivityToken());
- mPresenter.applyTransaction(wct);
- return true;
+ if (mPresenter.expandSplitContainerIfNeeded(wct, splitContainer, primaryActivity,
+ secondaryActivity, null /* secondaryIntent */)
+ != RESULT_EXPAND_FAILED_NO_TF_INFO) {
+ wct.reparentActivityToTaskFragment(
+ secondaryContainer.getTaskFragmentToken(),
+ secondaryActivity.getActivityToken());
+ mPresenter.applyTransaction(wct);
+ return true;
+ }
}
// Create new split pair.
mPresenter.createNewSplitContainer(primaryActivity, secondaryActivity, splitRule);
@@ -792,6 +795,7 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
* Returns a container for the new activity intent to launch into as splitting with the primary
* activity.
*/
+ @GuardedBy("mLock")
@Nullable
private TaskFragmentContainer getSecondaryContainerForSplitIfAny(
@NonNull WindowContainerTransaction wct, @NonNull Activity primaryActivity,
@@ -805,16 +809,12 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
if (splitContainer != null && existingContainer == splitContainer.getPrimaryContainer()
&& (canReuseContainer(splitRule, splitContainer.getSplitRule())
// TODO(b/231845476) we should always respect clearTop.
- || !respectClearTop)) {
- final Rect secondaryBounds = splitContainer.getSecondaryContainer()
- .getLastRequestedBounds();
- if (secondaryBounds.isEmpty()
- || !boundsSmallerThanMinDimensions(secondaryBounds,
- getMinDimensions(intent))) {
- // Can launch in the existing secondary container if the rules share the same
- // presentation.
- return splitContainer.getSecondaryContainer();
- }
+ || !respectClearTop)
+ && mPresenter.expandSplitContainerIfNeeded(wct, splitContainer, primaryActivity,
+ null /* secondaryActivity */, intent) != RESULT_EXPAND_FAILED_NO_TF_INFO) {
+ // Can launch in the existing secondary container if the rules share the same
+ // presentation.
+ return splitContainer.getSecondaryContainer();
}
// Create a new TaskFragment to split with the primary activity for the new activity.
return mPresenter.createNewSplitWithEmptySideContainer(wct, primaryActivity, intent,
@@ -868,6 +868,7 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
* if needed.
* @param taskId parent Task of the new TaskFragment.
*/
+ @GuardedBy("mLock")
TaskFragmentContainer newContainer(@Nullable Activity pendingAppearedActivity,
@Nullable Intent pendingAppearedIntent, @NonNull Activity activityInTask, int taskId) {
if (activityInTask == null) {
@@ -881,7 +882,7 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
pendingAppearedIntent, taskContainer, this);
if (!taskContainer.isTaskBoundsInitialized()) {
// Get the initial bounds before the TaskFragment has appeared.
- final Rect taskBounds = SplitPresenter.getTaskBoundsFromActivity(activityInTask);
+ final Rect taskBounds = getNonEmbeddedActivityBounds(activityInTask);
if (!taskContainer.setTaskBounds(taskBounds)) {
Log.w(TAG, "Can't find bounds from activity=" + activityInTask);
}
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 1b79ad999435..a89847a30d20 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java
@@ -65,6 +65,41 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer {
})
private @interface Position {}
+ /**
+ * Result of {@link #expandSplitContainerIfNeeded(WindowContainerTransaction, SplitContainer,
+ * Activity, Activity, Intent)}.
+ * No need to expand the splitContainer because screen is big enough to
+ * {@link #shouldShowSideBySide(Rect, SplitRule, Pair)} and minimum dimensions is satisfied.
+ */
+ static final int RESULT_NOT_EXPANDED = 0;
+ /**
+ * Result of {@link #expandSplitContainerIfNeeded(WindowContainerTransaction, SplitContainer,
+ * Activity, Activity, Intent)}.
+ * The splitContainer should be expanded. It is usually because minimum dimensions is not
+ * satisfied.
+ * @see #shouldShowSideBySide(Rect, SplitRule, Pair)
+ */
+ static final int RESULT_EXPANDED = 1;
+ /**
+ * Result of {@link #expandSplitContainerIfNeeded(WindowContainerTransaction, SplitContainer,
+ * Activity, Activity, Intent)}.
+ * The splitContainer should be expanded, but the client side hasn't received
+ * {@link android.window.TaskFragmentInfo} yet. Fallback to create new expanded SplitContainer
+ * instead.
+ */
+ static final int RESULT_EXPAND_FAILED_NO_TF_INFO = 2;
+
+ /**
+ * Result of {@link #expandSplitContainerIfNeeded(WindowContainerTransaction, SplitContainer,
+ * Activity, Activity, Intent)}
+ */
+ @IntDef(value = {
+ RESULT_NOT_EXPANDED,
+ RESULT_EXPANDED,
+ RESULT_EXPAND_FAILED_NO_TF_INFO,
+ })
+ private @interface ResultCode {}
+
private final SplitController mController;
SplitPresenter(@NonNull Executor executor, SplitController controller) {
@@ -396,6 +431,44 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer {
super.updateWindowingMode(wct, fragmentToken, windowingMode);
}
+ /**
+ * Expands the split container if the current split bounds are smaller than the Activity or
+ * Intent that is added to the container.
+ *
+ * @return the {@link ResultCode} based on {@link #shouldShowSideBySide(Rect, SplitRule, Pair)}
+ * and if {@link android.window.TaskFragmentInfo} has reported to the client side.
+ */
+ @ResultCode
+ int expandSplitContainerIfNeeded(@NonNull WindowContainerTransaction wct,
+ @NonNull SplitContainer splitContainer, @NonNull Activity primaryActivity,
+ @Nullable Activity secondaryActivity, @Nullable Intent secondaryIntent) {
+ if (secondaryActivity == null && secondaryIntent == null) {
+ throw new IllegalArgumentException("Either secondaryActivity or secondaryIntent must be"
+ + " non-null.");
+ }
+ final Rect taskBounds = getParentContainerBounds(primaryActivity);
+ final Pair<Size, Size> minDimensionsPair;
+ if (secondaryActivity != null) {
+ minDimensionsPair = getActivitiesMinDimensionsPair(primaryActivity, secondaryActivity);
+ } else {
+ minDimensionsPair = getActivityIntentMinDimensionsPair(primaryActivity,
+ secondaryIntent);
+ }
+ // Expand the splitContainer if minimum dimensions are not satisfied.
+ if (!shouldShowSideBySide(taskBounds, splitContainer.getSplitRule(), minDimensionsPair)) {
+ // If the client side hasn't received TaskFragmentInfo yet, we can't change TaskFragment
+ // bounds. Return failure to create a new SplitContainer which fills task bounds.
+ if (splitContainer.getPrimaryContainer().getInfo() == null
+ || splitContainer.getSecondaryContainer().getInfo() == null) {
+ return RESULT_EXPAND_FAILED_NO_TF_INFO;
+ }
+ expandTaskFragment(wct, splitContainer.getPrimaryContainer().getTaskFragmentToken());
+ expandTaskFragment(wct, splitContainer.getSecondaryContainer().getTaskFragmentToken());
+ return RESULT_EXPANDED;
+ }
+ return RESULT_NOT_EXPANDED;
+ }
+
static boolean shouldShowSideBySide(@NonNull Rect parentBounds, @NonNull SplitRule rule) {
return shouldShowSideBySide(parentBounds, rule, null /* minimumDimensionPair */);
}
@@ -565,11 +638,19 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer {
if (container != null) {
return getParentContainerBounds(container);
}
- return getTaskBoundsFromActivity(activity);
+ // Obtain bounds from Activity instead because the Activity hasn't been embedded yet.
+ return getNonEmbeddedActivityBounds(activity);
}
+ /**
+ * Obtains the bounds from a non-embedded Activity.
+ * <p>
+ * Note that callers should use {@link #getParentContainerBounds(Activity)} instead for most
+ * cases unless we want to obtain task bounds before
+ * {@link TaskContainer#isTaskBoundsInitialized()}.
+ */
@NonNull
- static Rect getTaskBoundsFromActivity(@NonNull Activity activity) {
+ static Rect getNonEmbeddedActivityBounds(@NonNull Activity activity) {
final WindowConfiguration windowConfiguration =
activity.getResources().getConfiguration().windowConfiguration;
if (!activity.isInMultiWindowMode()) {
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationRunner.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationRunner.java
index 1ac33173668b..c4f37091a491 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationRunner.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationRunner.java
@@ -83,9 +83,9 @@ class TaskFragmentAnimationRunner extends IRemoteAnimationRunner.Stub {
}
@Override
- public void onAnimationCancelled() {
+ public void onAnimationCancelled(boolean isKeyguardOccluded) {
if (TaskFragmentAnimationController.DEBUG) {
- Log.v(TAG, "onAnimationCancelled");
+ Log.v(TAG, "onAnimationCancelled: isKeyguardOccluded=" + isKeyguardOccluded);
}
mHandler.post(this::cancelAnimation);
}
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/EmbeddingTestUtils.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/EmbeddingTestUtils.java
index 835c40365cda..effc1a3ef3ea 100644
--- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/EmbeddingTestUtils.java
+++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/EmbeddingTestUtils.java
@@ -24,6 +24,7 @@ import static org.mockito.Mockito.mock;
import android.annotation.NonNull;
import android.app.Activity;
import android.content.Intent;
+import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.graphics.Point;
import android.graphics.Rect;
@@ -57,13 +58,21 @@ public class EmbeddingTestUtils {
/** Creates a rule to always split the given activity and the given intent. */
static SplitRule createSplitRule(@NonNull Activity primaryActivity,
@NonNull Intent secondaryIntent) {
+ return createSplitRule(primaryActivity, secondaryIntent, true /* clearTop */);
+ }
+
+ /** Creates a rule to always split the given activity and the given intent. */
+ static SplitRule createSplitRule(@NonNull Activity primaryActivity,
+ @NonNull Intent secondaryIntent, boolean clearTop) {
final Pair<Activity, Intent> targetPair = new Pair<>(primaryActivity, secondaryIntent);
return new SplitPairRule.Builder(
activityPair -> false,
targetPair::equals,
w -> true)
.setSplitRatio(SPLIT_RATIO)
- .setShouldClearTop(true)
+ .setShouldClearTop(clearTop)
+ .setFinishPrimaryWithSecondary(DEFAULT_FINISH_PRIMARY_WITH_SECONDARY)
+ .setFinishSecondaryWithPrimary(DEFAULT_FINISH_SECONDARY_WITH_PRIMARY)
.build();
}
@@ -75,6 +84,14 @@ public class EmbeddingTestUtils {
true /* clearTop */);
}
+ /** Creates a rule to always split the given activities. */
+ static SplitRule createSplitRule(@NonNull Activity primaryActivity,
+ @NonNull Activity secondaryActivity, boolean clearTop) {
+ return createSplitRule(primaryActivity, secondaryActivity,
+ DEFAULT_FINISH_PRIMARY_WITH_SECONDARY, DEFAULT_FINISH_SECONDARY_WITH_PRIMARY,
+ clearTop);
+ }
+
/** Creates a rule to always split the given activities with the given finish behaviors. */
static SplitRule createSplitRule(@NonNull Activity primaryActivity,
@NonNull Activity secondaryActivity, int finishPrimaryWithSecondary,
@@ -105,4 +122,12 @@ public class EmbeddingTestUtils {
false /* isTaskFragmentClearedForPip */,
new Point());
}
+
+ static ActivityInfo createActivityInfoWithMinDimensions() {
+ ActivityInfo aInfo = new ActivityInfo();
+ final Rect primaryBounds = getSplitBounds(true /* isPrimary */);
+ aInfo.windowLayout = new ActivityInfo.WindowLayout(0, 0, 0, 0, 0,
+ primaryBounds.width() + 1, primaryBounds.height() + 1);
+ return aInfo;
+ }
}
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java
index ef7728cec387..042547fd30f2 100644
--- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java
+++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java
@@ -22,6 +22,7 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static androidx.window.extensions.embedding.EmbeddingTestUtils.SPLIT_RATIO;
import static androidx.window.extensions.embedding.EmbeddingTestUtils.TASK_BOUNDS;
import static androidx.window.extensions.embedding.EmbeddingTestUtils.TASK_ID;
+import static androidx.window.extensions.embedding.EmbeddingTestUtils.createActivityInfoWithMinDimensions;
import static androidx.window.extensions.embedding.EmbeddingTestUtils.createMockTaskFragmentInfo;
import static androidx.window.extensions.embedding.EmbeddingTestUtils.createSplitRule;
import static androidx.window.extensions.embedding.EmbeddingTestUtils.getSplitBounds;
@@ -34,6 +35,7 @@ import static com.google.common.truth.Truth.assertWithMessage;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThrows;
@@ -436,6 +438,50 @@ public class SplitControllerTest {
}
@Test
+ public void testResolveStartActivityIntent_shouldExpandSplitContainer() {
+ final Intent intent = new Intent().setComponent(
+ new ComponentName(ApplicationProvider.getApplicationContext(),
+ MinimumDimensionActivity.class));
+ setupSplitRule(mActivity, intent, false /* clearTop */);
+ final Activity secondaryActivity = createMockActivity();
+ addSplitTaskFragments(mActivity, secondaryActivity, false /* clearTop */);
+
+ final TaskFragmentContainer container = mSplitController.resolveStartActivityIntent(
+ mTransaction, TASK_ID, intent, mActivity);
+ final TaskFragmentContainer primaryContainer = mSplitController.getContainerWithActivity(
+ mActivity);
+
+ assertNotNull(mSplitController.getActiveSplitForContainers(primaryContainer, container));
+ assertTrue(primaryContainer.areLastRequestedBoundsEqual(null));
+ assertTrue(container.areLastRequestedBoundsEqual(null));
+ assertEquals(container, mSplitController.getContainerWithActivity(secondaryActivity));
+ }
+
+ @Test
+ public void testResolveStartActivityIntent_noInfo_shouldCreateSplitContainer() {
+ final Intent intent = new Intent().setComponent(
+ new ComponentName(ApplicationProvider.getApplicationContext(),
+ MinimumDimensionActivity.class));
+ setupSplitRule(mActivity, intent, false /* clearTop */);
+ final Activity secondaryActivity = createMockActivity();
+ addSplitTaskFragments(mActivity, secondaryActivity, false /* clearTop */);
+
+ final TaskFragmentContainer secondaryContainer = mSplitController
+ .getContainerWithActivity(secondaryActivity);
+ secondaryContainer.mInfo = null;
+
+ final TaskFragmentContainer container = mSplitController.resolveStartActivityIntent(
+ mTransaction, TASK_ID, intent, mActivity);
+ final TaskFragmentContainer primaryContainer = mSplitController.getContainerWithActivity(
+ mActivity);
+
+ assertNotNull(mSplitController.getActiveSplitForContainers(primaryContainer, container));
+ assertTrue(primaryContainer.areLastRequestedBoundsEqual(null));
+ assertTrue(container.areLastRequestedBoundsEqual(null));
+ assertNotEquals(container, secondaryContainer);
+ }
+
+ @Test
public void testPlaceActivityInTopContainer() {
mSplitController.placeActivityInTopContainer(mActivity);
@@ -787,11 +833,7 @@ public class SplitControllerTest {
final Activity activityBelow = createMockActivity();
setupSplitRule(mActivity, activityBelow);
- ActivityInfo aInfo = new ActivityInfo();
- final Rect primaryBounds = getSplitBounds(true /* isPrimary */);
- aInfo.windowLayout = new ActivityInfo.WindowLayout(0, 0, 0, 0, 0,
- primaryBounds.width() + 1, primaryBounds.height() + 1);
- doReturn(aInfo).when(mActivity).getActivityInfo();
+ doReturn(createActivityInfoWithMinDimensions()).when(mActivity).getActivityInfo();
final TaskFragmentContainer container = mSplitController.newContainer(activityBelow,
TASK_ID);
@@ -810,17 +852,12 @@ public class SplitControllerTest {
final Activity activityBelow = createMockActivity();
setupSplitRule(activityBelow, mActivity);
- ActivityInfo aInfo = new ActivityInfo();
- final Rect secondaryBounds = getSplitBounds(false /* isPrimary */);
- aInfo.windowLayout = new ActivityInfo.WindowLayout(0, 0, 0, 0, 0,
- secondaryBounds.width() + 1, secondaryBounds.height() + 1);
- doReturn(aInfo).when(mActivity).getActivityInfo();
+ doReturn(createActivityInfoWithMinDimensions()).when(mActivity).getActivityInfo();
final TaskFragmentContainer container = mSplitController.newContainer(activityBelow,
TASK_ID);
container.addPendingAppearedActivity(mActivity);
- // Allow to split as primary.
boolean result = mSplitController.resolveActivityToContainer(mActivity,
false /* isOnReparent */);
@@ -828,6 +865,29 @@ public class SplitControllerTest {
assertSplitPair(activityBelow, mActivity, true /* matchParentBounds */);
}
+ // Suppress GuardedBy warning on unit tests
+ @SuppressWarnings("GuardedBy")
+ @Test
+ public void testResolveActivityToContainer_minDimensions_shouldExpandSplitContainer() {
+ final Activity primaryActivity = createMockActivity();
+ final Activity secondaryActivity = createMockActivity();
+ addSplitTaskFragments(primaryActivity, secondaryActivity, false /* clearTop */);
+
+ setupSplitRule(primaryActivity, mActivity, false /* clearTop */);
+ doReturn(createActivityInfoWithMinDimensions()).when(mActivity).getActivityInfo();
+ doReturn(secondaryActivity).when(mSplitController).findActivityBelow(eq(mActivity));
+
+ clearInvocations(mSplitPresenter);
+ boolean result = mSplitController.resolveActivityToContainer(mActivity,
+ false /* isOnReparent */);
+
+ assertTrue(result);
+ assertSplitPair(primaryActivity, mActivity, true /* matchParentBounds */);
+ assertEquals(mSplitController.getContainerWithActivity(secondaryActivity),
+ mSplitController.getContainerWithActivity(mActivity));
+ verify(mSplitPresenter, never()).createNewSplitContainer(any(), any(), any());
+ }
+
@Test
public void testResolveActivityToContainer_inUnknownTaskFragment() {
doReturn(new Binder()).when(mSplitController).getInitialTaskFragmentToken(mActivity);
@@ -944,23 +1004,41 @@ public class SplitControllerTest {
/** Setups a rule to always split the given activities. */
private void setupSplitRule(@NonNull Activity primaryActivity,
@NonNull Intent secondaryIntent) {
- final SplitRule splitRule = createSplitRule(primaryActivity, secondaryIntent);
+ setupSplitRule(primaryActivity, secondaryIntent, true /* clearTop */);
+ }
+
+ /** Setups a rule to always split the given activities. */
+ private void setupSplitRule(@NonNull Activity primaryActivity,
+ @NonNull Intent secondaryIntent, boolean clearTop) {
+ final SplitRule splitRule = createSplitRule(primaryActivity, secondaryIntent, clearTop);
mSplitController.setEmbeddingRules(Collections.singleton(splitRule));
}
/** Setups a rule to always split the given activities. */
private void setupSplitRule(@NonNull Activity primaryActivity,
@NonNull Activity secondaryActivity) {
- final SplitRule splitRule = createSplitRule(primaryActivity, secondaryActivity);
+ setupSplitRule(primaryActivity, secondaryActivity, true /* clearTop */);
+ }
+
+ /** Setups a rule to always split the given activities. */
+ private void setupSplitRule(@NonNull Activity primaryActivity,
+ @NonNull Activity secondaryActivity, boolean clearTop) {
+ final SplitRule splitRule = createSplitRule(primaryActivity, secondaryActivity, clearTop);
mSplitController.setEmbeddingRules(Collections.singleton(splitRule));
}
/** Adds a pair of TaskFragments as split for the given activities. */
private void addSplitTaskFragments(@NonNull Activity primaryActivity,
@NonNull Activity secondaryActivity) {
+ addSplitTaskFragments(primaryActivity, secondaryActivity, true /* clearTop */);
+ }
+
+ /** Adds a pair of TaskFragments as split for the given activities. */
+ private void addSplitTaskFragments(@NonNull Activity primaryActivity,
+ @NonNull Activity secondaryActivity, boolean clearTop) {
registerSplitPair(createMockTaskFragmentContainer(primaryActivity),
createMockTaskFragmentContainer(secondaryActivity),
- createSplitRule(primaryActivity, secondaryActivity));
+ createSplitRule(primaryActivity, secondaryActivity, clearTop));
}
/** Registers the two given TaskFragments as split pair. */
@@ -1011,16 +1089,18 @@ public class SplitControllerTest {
if (primaryContainer.mInfo != null) {
final Rect primaryBounds = matchParentBounds ? new Rect()
: getSplitBounds(true /* isPrimary */);
+ final int windowingMode = matchParentBounds ? WINDOWING_MODE_UNDEFINED
+ : WINDOWING_MODE_MULTI_WINDOW;
assertTrue(primaryContainer.areLastRequestedBoundsEqual(primaryBounds));
- assertTrue(primaryContainer.isLastRequestedWindowingModeEqual(
- WINDOWING_MODE_MULTI_WINDOW));
+ assertTrue(primaryContainer.isLastRequestedWindowingModeEqual(windowingMode));
}
if (secondaryContainer.mInfo != null) {
final Rect secondaryBounds = matchParentBounds ? new Rect()
: getSplitBounds(false /* isPrimary */);
+ final int windowingMode = matchParentBounds ? WINDOWING_MODE_UNDEFINED
+ : WINDOWING_MODE_MULTI_WINDOW;
assertTrue(secondaryContainer.areLastRequestedBoundsEqual(secondaryBounds));
- assertTrue(secondaryContainer.isLastRequestedWindowingModeEqual(
- WINDOWING_MODE_MULTI_WINDOW));
+ assertTrue(secondaryContainer.isLastRequestedWindowingModeEqual(windowingMode));
}
}
}
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitPresenterTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitPresenterTest.java
index acc398a27baf..d79319666c01 100644
--- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitPresenterTest.java
+++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitPresenterTest.java
@@ -20,11 +20,16 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
import static androidx.window.extensions.embedding.EmbeddingTestUtils.TASK_BOUNDS;
import static androidx.window.extensions.embedding.EmbeddingTestUtils.TASK_ID;
+import static androidx.window.extensions.embedding.EmbeddingTestUtils.createActivityInfoWithMinDimensions;
+import static androidx.window.extensions.embedding.EmbeddingTestUtils.createMockTaskFragmentInfo;
import static androidx.window.extensions.embedding.EmbeddingTestUtils.createSplitRule;
import static androidx.window.extensions.embedding.EmbeddingTestUtils.getSplitBounds;
import static androidx.window.extensions.embedding.SplitPresenter.POSITION_END;
import static androidx.window.extensions.embedding.SplitPresenter.POSITION_FILL;
import static androidx.window.extensions.embedding.SplitPresenter.POSITION_START;
+import static androidx.window.extensions.embedding.SplitPresenter.RESULT_EXPANDED;
+import static androidx.window.extensions.embedding.SplitPresenter.RESULT_EXPAND_FAILED_NO_TF_INFO;
+import static androidx.window.extensions.embedding.SplitPresenter.RESULT_NOT_EXPANDED;
import static androidx.window.extensions.embedding.SplitPresenter.getBoundsForPosition;
import static androidx.window.extensions.embedding.SplitPresenter.getMinDimensions;
import static androidx.window.extensions.embedding.SplitPresenter.shouldShowSideBySide;
@@ -34,6 +39,7 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
@@ -49,6 +55,7 @@ import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Rect;
+import android.os.IBinder;
import android.platform.test.annotations.Presubmit;
import android.util.Pair;
import android.util.Size;
@@ -195,6 +202,52 @@ public class SplitPresenterTest {
splitRule, mActivity, minDimensionsPair));
}
+ @Test
+ public void testExpandSplitContainerIfNeeded() {
+ SplitContainer splitContainer = mock(SplitContainer.class);
+ Activity secondaryActivity = createMockActivity();
+ SplitRule splitRule = createSplitRule(mActivity, secondaryActivity);
+ TaskFragmentContainer primaryTf = mController.newContainer(mActivity, TASK_ID);
+ TaskFragmentContainer secondaryTf = mController.newContainer(secondaryActivity, TASK_ID);
+ doReturn(splitRule).when(splitContainer).getSplitRule();
+ doReturn(primaryTf).when(splitContainer).getPrimaryContainer();
+ doReturn(secondaryTf).when(splitContainer).getSecondaryContainer();
+
+ assertThrows(IllegalArgumentException.class, () ->
+ mPresenter.expandSplitContainerIfNeeded(mTransaction, splitContainer, mActivity,
+ null /* secondaryActivity */, null /* secondaryIntent */));
+
+ assertEquals(RESULT_NOT_EXPANDED, mPresenter.expandSplitContainerIfNeeded(mTransaction,
+ splitContainer, mActivity, secondaryActivity, null /* secondaryIntent */));
+ verify(mPresenter, never()).expandTaskFragment(any(), any());
+
+ doReturn(createActivityInfoWithMinDimensions()).when(secondaryActivity).getActivityInfo();
+ assertEquals(RESULT_EXPAND_FAILED_NO_TF_INFO, mPresenter.expandSplitContainerIfNeeded(
+ mTransaction, splitContainer, mActivity, secondaryActivity,
+ null /* secondaryIntent */));
+
+ primaryTf.setInfo(createMockTaskFragmentInfo(primaryTf, mActivity));
+ secondaryTf.setInfo(createMockTaskFragmentInfo(secondaryTf, secondaryActivity));
+
+ assertEquals(RESULT_EXPANDED, mPresenter.expandSplitContainerIfNeeded(mTransaction,
+ splitContainer, mActivity, secondaryActivity, null /* secondaryIntent */));
+ verify(mPresenter).expandTaskFragment(eq(mTransaction),
+ eq(primaryTf.getTaskFragmentToken()));
+ verify(mPresenter).expandTaskFragment(eq(mTransaction),
+ eq(secondaryTf.getTaskFragmentToken()));
+
+ clearInvocations(mPresenter);
+
+ assertEquals(RESULT_EXPANDED, mPresenter.expandSplitContainerIfNeeded(mTransaction,
+ splitContainer, mActivity, null /* secondaryActivity */,
+ new Intent(ApplicationProvider.getApplicationContext(),
+ MinimumDimensionActivity.class)));
+ verify(mPresenter).expandTaskFragment(eq(mTransaction),
+ eq(primaryTf.getTaskFragmentToken()));
+ verify(mPresenter).expandTaskFragment(eq(mTransaction),
+ eq(secondaryTf.getTaskFragmentToken()));
+ }
+
private Activity createMockActivity() {
final Activity activity = mock(Activity.class);
final Configuration activityConfig = new Configuration();
@@ -203,6 +256,7 @@ public class SplitPresenterTest {
doReturn(mActivityResources).when(activity).getResources();
doReturn(activityConfig).when(mActivityResources).getConfiguration();
doReturn(new ActivityInfo()).when(activity).getActivityInfo();
+ doReturn(mock(IBinder.class)).when(activity).getActivityToken();
return activity;
}
}
diff --git a/libs/WindowManager/Shell/res/values-television/config.xml b/libs/WindowManager/Shell/res/values-television/config.xml
index 86ca65526336..cc0333efd82b 100644
--- a/libs/WindowManager/Shell/res/values-television/config.xml
+++ b/libs/WindowManager/Shell/res/values-television/config.xml
@@ -43,4 +43,13 @@
<!-- Time (duration in milliseconds) that the shell waits for an app to close the PiP by itself
if a custom action is present before closing it. -->
<integer name="config_pipForceCloseDelay">5000</integer>
+
+ <!-- Animation duration when exit starting window: fade out icon -->
+ <integer name="starting_window_app_reveal_icon_fade_out_duration">0</integer>
+
+ <!-- Animation duration when exit starting window: reveal app -->
+ <integer name="starting_window_app_reveal_anim_delay">0</integer>
+
+ <!-- Animation duration when exit starting window: reveal app -->
+ <integer name="starting_window_app_reveal_anim_duration">0</integer>
</resources>
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java
index 4eba1697b595..cf2734c375f2 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java
@@ -591,7 +591,7 @@ public class PipAnimationController {
final Rect insets = computeInsets(fraction);
getSurfaceTransactionHelper().scaleAndCrop(tx, leash,
sourceHintRect, initialSourceValue, bounds, insets,
- isInPipDirection);
+ isInPipDirection, fraction);
if (shouldApplyCornerRadius()) {
final Rect sourceBounds = new Rect(initialContainerRect);
sourceBounds.inset(insets);
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 a017a2674359..c0bc108baada 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
@@ -104,7 +104,7 @@ public class PipSurfaceTransactionHelper {
public PipSurfaceTransactionHelper scaleAndCrop(SurfaceControl.Transaction tx,
SurfaceControl leash, Rect sourceRectHint,
Rect sourceBounds, Rect destinationBounds, Rect insets,
- boolean isInPipDirection) {
+ boolean isInPipDirection, float fraction) {
mTmpDestinationRect.set(sourceBounds);
// Similar to {@link #scale}, we want to position the surface relative to the screen
// coordinates so offset the bounds to 0,0
@@ -116,9 +116,13 @@ public class PipSurfaceTransactionHelper {
if (isInPipDirection
&& sourceRectHint != null && sourceRectHint.width() < sourceBounds.width()) {
// scale by sourceRectHint if it's not edge-to-edge, for entering PiP transition only.
- scale = sourceBounds.width() <= sourceBounds.height()
+ final float endScale = sourceBounds.width() <= sourceBounds.height()
? (float) destinationBounds.width() / sourceRectHint.width()
: (float) destinationBounds.height() / sourceRectHint.height();
+ final float startScale = sourceBounds.width() <= sourceBounds.height()
+ ? (float) destinationBounds.width() / sourceBounds.width()
+ : (float) destinationBounds.height() / sourceBounds.height();
+ scale = (1 - fraction) * startScale + fraction * endScale;
} else {
scale = sourceBounds.width() <= sourceBounds.height()
? (float) destinationBounds.width() / sourceBounds.width()
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
index bd386b5681d8..22b0ccbc8488 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
@@ -942,7 +942,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
// Re-set the PIP bounds to none.
mPipBoundsState.setBounds(new Rect());
mPipUiEventLoggerLogger.setTaskInfo(null);
- mPipMenuController.detach();
+ mMainExecutor.executeDelayed(() -> mPipMenuController.detach(), 0);
if (info.displayId != Display.DEFAULT_DISPLAY && mOnDisplayIdChangeCallback != null) {
mOnDisplayIdChangeCallback.accept(Display.DEFAULT_DISPLAY);
@@ -1472,6 +1472,11 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
"%s: Abort animation, invalid leash", TAG);
return null;
}
+ if (isInPipDirection(direction)
+ && !isSourceRectHintValidForEnterPip(sourceHintRect, destinationBounds)) {
+ // The given source rect hint is too small for enter PiP animation, reset it to null.
+ sourceHintRect = null;
+ }
final int rotationDelta = mWaitForFixedRotation
? deltaRotation(mCurrentRotation, mNextRotation)
: Surface.ROTATION_0;
@@ -1546,6 +1551,20 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
}
/**
+ * This is a situation in which the source rect hint on at least one axis is smaller
+ * than the destination bounds, which represents a problem because we would have to scale
+ * up that axis to fit the bounds. So instead, just fallback to the non-source hint
+ * animation in this case.
+ *
+ * @return {@code false} if the given source is too small to use for the entering animation.
+ */
+ private boolean isSourceRectHintValidForEnterPip(Rect sourceRectHint, Rect destinationBounds) {
+ return sourceRectHint != null
+ && sourceRectHint.width() > destinationBounds.width()
+ && sourceRectHint.height() > destinationBounds.height();
+ }
+
+ /**
* Sync with {@link SplitScreenController} on destination bounds if PiP is going to
* split screen.
*
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 c80c14f353d0..05a890fc65ed 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
@@ -715,7 +715,7 @@ public class PipTransition extends PipTransitionController {
mSurfaceTransactionHelper
.crop(finishTransaction, leash, destinationBounds)
.round(finishTransaction, leash, true /* applyCornerRadius */);
- mPipMenuController.attach(leash);
+ mTransitions.getMainExecutor().executeDelayed(() -> mPipMenuController.attach(leash), 0);
if (taskInfo.pictureInPictureParams != null
&& taskInfo.pictureInPictureParams.isAutoEnterEnabled()
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java
index a43b6043908b..90a2695bdf90 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java
@@ -28,9 +28,7 @@ import android.app.TaskInfo;
import android.content.ComponentName;
import android.content.pm.ActivityInfo;
import android.graphics.Rect;
-import android.os.Handler;
import android.os.IBinder;
-import android.os.Looper;
import android.view.SurfaceControl;
import android.view.WindowManager;
import android.window.TransitionInfo;
@@ -56,7 +54,6 @@ public abstract class PipTransitionController implements Transitions.TransitionH
protected final ShellTaskOrganizer mShellTaskOrganizer;
protected final PipMenuController mPipMenuController;
protected final Transitions mTransitions;
- private final Handler mMainHandler;
private final List<PipTransitionCallback> mPipTransitionCallbacks = new ArrayList<>();
protected PipTaskOrganizer mPipOrganizer;
@@ -144,7 +141,6 @@ public abstract class PipTransitionController implements Transitions.TransitionH
mPipBoundsAlgorithm = pipBoundsAlgorithm;
mPipAnimationController = pipAnimationController;
mTransitions = transitions;
- mMainHandler = new Handler(Looper.getMainLooper());
if (Transitions.ENABLE_SHELL_TRANSITIONS) {
transitions.addHandler(this);
}
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 4e7b20e3ae84..59b0afe22acb 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
@@ -457,10 +457,10 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
}
@Override
- public void onAnimationCancelled() {
+ public void onAnimationCancelled(boolean isKeyguardOccluded) {
onRemoteAnimationFinishedOrCancelled(evictWct);
try {
- adapter.getRunner().onAnimationCancelled();
+ adapter.getRunner().onAnimationCancelled(isKeyguardOccluded);
} catch (RemoteException e) {
Slog.e(TAG, "Error starting remote animation", e);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/tv/OWNERS b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/tv/OWNERS
new file mode 100644
index 000000000000..d325d161ac53
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/tv/OWNERS
@@ -0,0 +1,2 @@
+# WM shell sub-module TV splitscreen owner
+galinap@google.com
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 05e5b8e66a00..dcd6277966dd 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
@@ -866,13 +866,19 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler {
});
};
va.addListener(new AnimatorListenerAdapter() {
+ private boolean mFinished = false;
+
@Override
public void onAnimationEnd(Animator animation) {
+ if (mFinished) return;
+ mFinished = true;
finisher.run();
}
@Override
public void onAnimationCancel(Animator animation) {
+ if (mFinished) return;
+ mFinished = true;
finisher.run();
}
});
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/LegacyTransitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/LegacyTransitions.java
index 61e11e877b90..61e92f355dc2 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/LegacyTransitions.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/LegacyTransitions.java
@@ -107,7 +107,7 @@ public class LegacyTransitions {
}
@Override
- public void onAnimationCancelled() throws RemoteException {
+ public void onAnimationCancelled(boolean isKeyguardOccluded) throws RemoteException {
mCancelled = true;
mApps = mWallpapers = mNonApps = null;
checkApply();
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/BaseBubbleScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/BaseBubbleScreen.kt
index 278ba9b0f4db..5b073038059c 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/BaseBubbleScreen.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/BaseBubbleScreen.kt
@@ -48,7 +48,7 @@ abstract class BaseBubbleScreen(protected val testSpec: FlickerTestParameter) {
ServiceManager.getService(Context.NOTIFICATION_SERVICE))
protected val uid = context.packageManager.getApplicationInfo(
- testApp.component.packageName, 0).uid
+ testApp.`package`, 0).uid
protected abstract val transition: FlickerBuilder.() -> Unit
@@ -59,7 +59,7 @@ abstract class BaseBubbleScreen(protected val testSpec: FlickerTestParameter) {
return {
setup {
test {
- notifyManager.setBubblesAllowed(testApp.component.packageName,
+ notifyManager.setBubblesAllowed(testApp.`package`,
uid, NotificationManager.BUBBLE_PREFERENCE_ALL)
testApp.launchViaIntent(wmHelper)
waitAndGetAddBubbleBtn()
@@ -69,7 +69,7 @@ abstract class BaseBubbleScreen(protected val testSpec: FlickerTestParameter) {
teardown {
test {
- notifyManager.setBubblesAllowed(testApp.component.packageName,
+ notifyManager.setBubblesAllowed(testApp.`package`,
uid, NotificationManager.BUBBLE_PREFERENCE_NONE)
testApp.exit()
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/LaunchBubbleFromLockScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/LaunchBubbleFromLockScreen.kt
index 27d65648dbb7..e2b19ea22b3b 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/LaunchBubbleFromLockScreen.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/LaunchBubbleFromLockScreen.kt
@@ -16,10 +16,10 @@
package com.android.wm.shell.flicker.bubble
+import android.platform.test.annotations.FlakyTest
import android.platform.test.annotations.Presubmit
import android.view.WindowInsets
import android.view.WindowManager
-import android.platform.test.annotations.FlakyTest
import androidx.test.filters.RequiresDevice
import androidx.test.uiautomator.By
import androidx.test.uiautomator.Until
@@ -29,8 +29,8 @@ import com.android.server.wm.flicker.annotation.Group4
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
import org.junit.Assume
-import org.junit.runner.RunWith
import org.junit.Test
+import org.junit.runner.RunWith
import org.junit.runners.Parameterized
/**
@@ -54,20 +54,21 @@ class LaunchBubbleFromLockScreen(testSpec: FlickerTestParameter) : BaseBubbleScr
val addBubbleBtn = waitAndGetAddBubbleBtn()
addBubbleBtn?.click() ?: error("Bubble widget not found")
device.sleep()
- wmHelper.waitFor("noAppWindowsOnTop") {
- it.wmState.topVisibleAppWindow.isEmpty()
- }
+ wmHelper.StateSyncBuilder()
+ .withoutTopVisibleAppWindows()
+ .waitForAndVerify()
device.wakeUp()
}
}
transitions {
// Swipe & wait for the notification shade to expand so all can be seen
val wm = context.getSystemService(WindowManager::class.java)
- val metricInsets = wm.getCurrentWindowMetrics().windowInsets
+ ?: error("Unable to obtain WM service")
+ val metricInsets = wm.currentWindowMetrics.windowInsets
val insets = metricInsets.getInsetsIgnoringVisibility(
WindowInsets.Type.statusBars()
or WindowInsets.Type.displayCutout())
- device.swipe(100, insets.top + 100, 100, device.getDisplayHeight() / 2, 4)
+ device.swipe(100, insets.top + 100, 100, device.displayHeight / 2, 4)
device.waitForIdle(2000)
instrumentation.uiAutomation.syncInputTransactions()
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/AppPairsHelper.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/AppPairsHelper.kt
index 41cd31aabf05..f4305ed19824 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/AppPairsHelper.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/AppPairsHelper.kt
@@ -17,44 +17,10 @@
package com.android.wm.shell.flicker.helpers
import android.app.Instrumentation
-import com.android.server.wm.flicker.Flicker
-import com.android.server.wm.flicker.helpers.WindowUtils
import com.android.server.wm.traces.common.FlickerComponentName
-import com.android.server.wm.traces.common.region.Region
class AppPairsHelper(
instrumentation: Instrumentation,
activityLabel: String,
component: FlickerComponentName
-) : BaseAppHelper(instrumentation, activityLabel, component) {
- fun getPrimaryBounds(dividerBounds: Region): Region {
- val primaryAppBounds = Region.from(0, 0, dividerBounds.bounds.right,
- dividerBounds.bounds.bottom + WindowUtils.dockedStackDividerInset)
- return primaryAppBounds
- }
-
- fun getSecondaryBounds(dividerBounds: Region): Region {
- val displayBounds = WindowUtils.displayBounds
- val secondaryAppBounds = Region.from(0,
- dividerBounds.bounds.bottom - WindowUtils.dockedStackDividerInset,
- displayBounds.right, displayBounds.bottom - WindowUtils.navigationBarFrameHeight)
- return secondaryAppBounds
- }
-
- companion object {
- const val TEST_REPETITIONS = 1
- const val TIMEOUT_MS = 3_000L
-
- fun Flicker.waitAppsShown(app1: SplitScreenHelper?, app2: SplitScreenHelper?) {
- wmHelper.waitFor("primaryAndSecondaryAppsVisible") { dump ->
- val primaryAppVisible = app1?.let {
- dump.wmState.isWindowSurfaceShown(app1.defaultWindowName)
- } ?: false
- val secondaryAppVisible = app2?.let {
- dump.wmState.isWindowSurfaceShown(app2.defaultWindowName)
- } ?: false
- primaryAppVisible && secondaryAppVisible
- }
- }
- }
-}
+) : BaseAppHelper(instrumentation, activityLabel, component)
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/BaseAppHelper.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/BaseAppHelper.kt
index 3dd9e0572947..912ba67285f7 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/BaseAppHelper.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/BaseAppHelper.kt
@@ -40,7 +40,7 @@ abstract class BaseAppHelper(
component,
LauncherStrategyFactory.getInstance(instrumentation).launcherStrategy
) {
- private val appSelector = By.pkg(component.packageName).depth(0)
+ private val appSelector = By.pkg(`package`).depth(0)
protected val isTelevision: Boolean
get() = context.packageManager.run {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/ImeAppHelper.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/ImeAppHelper.kt
index cc5b9f9eb26d..2e690de666f4 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/ImeAppHelper.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/ImeAppHelper.kt
@@ -18,7 +18,6 @@ package com.android.wm.shell.flicker.helpers
import android.app.Instrumentation
import androidx.test.uiautomator.By
-import androidx.test.uiautomator.UiDevice
import androidx.test.uiautomator.Until
import com.android.server.wm.flicker.helpers.FIND_TIMEOUT
import com.android.server.wm.traces.parser.toFlickerComponent
@@ -35,8 +34,7 @@ open class ImeAppHelper(instrumentation: Instrumentation) : BaseAppHelper(
*
* @param wmHelper Helper used to wait for WindowManager states
*/
- @JvmOverloads
- open fun openIME(wmHelper: WindowManagerStateHelper? = null) {
+ open fun openIME(wmHelper: WindowManagerStateHelper) {
if (!isTelevision) {
val editText = uiDevice.wait(
Until.findObject(By.res(getPackage(), "plain_text_input")),
@@ -47,7 +45,9 @@ open class ImeAppHelper(instrumentation: Instrumentation) : BaseAppHelper(
"was left in an unknown state (e.g. in split screen)"
}
editText.click()
- waitAndAssertIMEShown(uiDevice, wmHelper)
+ wmHelper.StateSyncBuilder()
+ .withImeShown()
+ .waitForAndVerify()
} else {
// If we do the same thing as above - editText.click() - on TV, that's going to force TV
// into the touch mode. We really don't want that.
@@ -55,36 +55,22 @@ open class ImeAppHelper(instrumentation: Instrumentation) : BaseAppHelper(
}
}
- protected fun waitAndAssertIMEShown(
- device: UiDevice,
- wmHelper: WindowManagerStateHelper? = null
- ) {
- if (wmHelper == null) {
- device.waitForIdle()
- } else {
- wmHelper.waitImeShown()
- }
- }
-
/**
* Opens the IME and wait for it to be gone
*
* @param wmHelper Helper used to wait for WindowManager states
*/
- @JvmOverloads
- open fun closeIME(wmHelper: WindowManagerStateHelper? = null) {
+ open fun closeIME(wmHelper: WindowManagerStateHelper) {
if (!isTelevision) {
uiDevice.pressBack()
// Using only the AccessibilityInfo it is not possible to identify if the IME is active
- if (wmHelper == null) {
- uiDevice.waitForIdle()
- } else {
- wmHelper.waitImeGone()
- }
+ wmHelper.StateSyncBuilder()
+ .withImeGone()
+ .waitForAndVerify()
} else {
// While pressing the back button should close the IME on TV as well, it may also lead
// to the app closing. So let's instead just ask the app to close the IME.
launchViaIntent(action = Components.ImeActivity.ACTION_CLOSE_IME)
}
}
-} \ No newline at end of file
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/PipAppHelper.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/PipAppHelper.kt
index f73d191b1917..216445fe9356 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/PipAppHelper.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/PipAppHelper.kt
@@ -19,13 +19,13 @@ package com.android.wm.shell.flicker.helpers
import android.app.Instrumentation
import android.media.session.MediaController
import android.media.session.MediaSessionManager
-import android.os.SystemClock
import androidx.test.uiautomator.By
import androidx.test.uiautomator.BySelector
import androidx.test.uiautomator.Until
import com.android.server.wm.flicker.helpers.FIND_TIMEOUT
import com.android.server.wm.flicker.helpers.SYSTEMUI_PACKAGE
import com.android.server.wm.traces.common.Rect
+import com.android.server.wm.traces.common.WindowManagerConditionsFactory
import com.android.server.wm.traces.parser.toFlickerComponent
import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
import com.android.wm.shell.flicker.pip.tv.closeTvPipWindow
@@ -43,11 +43,11 @@ class PipAppHelper(instrumentation: Instrumentation) : BaseAppHelper(
private val mediaController: MediaController?
get() = mediaSessionManager.getActiveSessions(null).firstOrNull {
- it.packageName == component.packageName
+ it.packageName == `package`
}
fun clickObject(resId: String) {
- val selector = By.res(component.packageName, resId)
+ val selector = By.res(`package`, resId)
val obj = uiDevice.findObject(selector) ?: error("Could not find `$resId` object")
if (!isTelevision) {
@@ -71,8 +71,12 @@ class PipAppHelper(instrumentation: Instrumentation) : BaseAppHelper(
) {
launchViaIntentAndWaitShown(
wmHelper, expectedWindowName, action, stringExtras,
- waitConditions = arrayOf(WindowManagerStateHelper.pipShownCondition)
+ waitConditions = arrayOf(WindowManagerConditionsFactory.hasPipWindow())
)
+
+ wmHelper.StateSyncBuilder()
+ .withPipShown()
+ .waitForAndVerify()
}
/**
@@ -95,12 +99,13 @@ class PipAppHelper(instrumentation: Instrumentation) : BaseAppHelper(
return false
}
- @JvmOverloads
- fun clickEnterPipButton(wmHelper: WindowManagerStateHelper? = null) {
+ fun clickEnterPipButton(wmHelper: WindowManagerStateHelper) {
clickObject(ENTER_PIP_BUTTON_ID)
// Wait on WMHelper or simply wait for 3 seconds
- wmHelper?.waitPipShown() ?: SystemClock.sleep(3_000)
+ wmHelper.StateSyncBuilder()
+ .withPipShown()
+ .waitForAndVerify()
// when entering pip, the dismiss button is visible at the start. to ensure the pip
// animation is complete, wait until the pip dismiss button is no longer visible.
// b/176822698: dismiss-only state will be removed in the future
@@ -116,7 +121,7 @@ class PipAppHelper(instrumentation: Instrumentation) : BaseAppHelper(
}
fun checkWithCustomActionsCheckbox() = uiDevice
- .findObject(By.res(component.packageName, WITH_CUSTOM_ACTIONS_BUTTON_ID))
+ .findObject(By.res(`package`, WITH_CUSTOM_ACTIONS_BUTTON_ID))
?.takeIf { it.isCheckable }
?.apply { if (!isChecked) clickObject(WITH_CUSTOM_ACTIONS_BUTTON_ID) }
?: error("'With custom actions' checkbox not found")
@@ -166,8 +171,10 @@ class PipAppHelper(instrumentation: Instrumentation) : BaseAppHelper(
}
// Wait for animation to complete.
- wmHelper.waitPipGone()
- wmHelper.waitForHomeActivityVisible()
+ wmHelper.StateSyncBuilder()
+ .withPipGone()
+ .withHomeActivityVisible()
+ .waitForAndVerify()
}
/**
@@ -183,8 +190,10 @@ class PipAppHelper(instrumentation: Instrumentation) : BaseAppHelper(
?: error("PIP window expand button not found")
val expandButtonBounds = expandPipObject.visibleBounds
uiDevice.click(expandButtonBounds.centerX(), expandButtonBounds.centerY())
- wmHelper.waitPipGone()
- wmHelper.waitForAppTransitionIdle()
+ wmHelper.StateSyncBuilder()
+ .withPipGone()
+ .withFullScreenApp(component)
+ .waitForAndVerify()
}
/**
@@ -194,7 +203,9 @@ class PipAppHelper(instrumentation: Instrumentation) : BaseAppHelper(
val windowRect = getWindowRect(wmHelper)
uiDevice.click(windowRect.centerX(), windowRect.centerY())
uiDevice.click(windowRect.centerX(), windowRect.centerY())
- wmHelper.waitForAppTransitionIdle()
+ wmHelper.StateSyncBuilder()
+ .withAppTransitionIdle()
+ .waitForAndVerify()
}
companion object {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipOnUserLeaveHintTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipOnUserLeaveHintTest.kt
index e7d641e9c66e..cb84fc441f75 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipOnUserLeaveHintTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipOnUserLeaveHintTest.kt
@@ -17,7 +17,6 @@
package com.android.wm.shell.flicker.pip
import androidx.test.filters.RequiresDevice
-import com.android.launcher3.tapl.LauncherInstrumentation
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.annotation.Group3
@@ -51,7 +50,6 @@ import org.junit.runners.Parameterized
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@Group3
class EnterPipOnUserLeaveHintTest(testSpec: FlickerTestParameter) : EnterPipTest(testSpec) {
- protected val taplInstrumentation = LauncherInstrumentation()
/**
* Defines the transition used to run the test
*/
@@ -70,7 +68,7 @@ class EnterPipOnUserLeaveHintTest(testSpec: FlickerTestParameter) : EnterPipTest
}
}
transitions {
- taplInstrumentation.goHome()
+ tapl.goHome()
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt
index eb318fb256c9..c18c8ce345fc 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt
@@ -16,16 +16,16 @@
package com.android.wm.shell.flicker.pip
+import android.platform.test.annotations.FlakyTest
import android.platform.test.annotations.Presubmit
import android.view.Surface
-import android.platform.test.annotations.FlakyTest
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.FlickerTestParameterFactory
-import com.android.server.wm.flicker.LAUNCHER_COMPONENT
import com.android.server.wm.flicker.annotation.Group3
import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.traces.common.FlickerComponentName.Companion.LAUNCHER
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -157,15 +157,15 @@ open class EnterPipTest(testSpec: FlickerTestParameter) : PipTransition(testSpec
}
/**
- * Checks [LAUNCHER_COMPONENT] layer remains visible throughout the animation
+ * Checks [LAUNCHER] layer remains visible throughout the animation
*/
@Presubmit
@Test
fun launcherLayerBecomesVisible() {
testSpec.assertLayers {
- isInvisible(LAUNCHER_COMPONENT)
+ isInvisible(LAUNCHER)
.then()
- .isVisible(LAUNCHER_COMPONENT)
+ .isVisible(LAUNCHER)
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationTest.kt
index 75481f2199c2..0333577b0d2a 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationTest.kt
@@ -16,9 +16,9 @@
package com.android.wm.shell.flicker.pip
+import android.platform.test.annotations.FlakyTest
import android.platform.test.annotations.Presubmit
import android.view.Surface
-import android.platform.test.annotations.FlakyTest
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
@@ -33,8 +33,8 @@ import com.android.server.wm.traces.common.FlickerComponentName
import com.android.wm.shell.flicker.helpers.FixedAppHelper
import com.android.wm.shell.flicker.pip.PipTransition.BroadcastActionTrigger.Companion.ORIENTATION_LANDSCAPE
import com.android.wm.shell.flicker.pip.PipTransition.BroadcastActionTrigger.Companion.ORIENTATION_PORTRAIT
-import com.android.wm.shell.flicker.testapp.Components.PipActivity.ACTION_ENTER_PIP
import com.android.wm.shell.flicker.testapp.Components.FixedActivity.EXTRA_FIXED_ORIENTATION
+import com.android.wm.shell.flicker.testapp.Components.PipActivity.ACTION_ENTER_PIP
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -98,10 +98,12 @@ class EnterPipToOtherOrientationTest(
// Enter PiP, and assert that the PiP is within bounds now that the device is back
// in portrait
broadcastActionTrigger.doAction(ACTION_ENTER_PIP)
- wmHelper.waitPipShown()
- wmHelper.waitForAppTransitionIdle()
// during rotation the status bar becomes invisible and reappears at the end
- wmHelper.waitForNavBarStatusBarVisible()
+ wmHelper.StateSyncBuilder()
+ .withPipShown()
+ .withAppTransitionIdle()
+ .withNavBarStatusBarVisible()
+ .waitForAndVerify()
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipTransition.kt
index 0b4bc761838d..47215b9fb883 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipTransition.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipTransition.kt
@@ -19,10 +19,10 @@ package com.android.wm.shell.flicker.pip
import android.platform.test.annotations.Presubmit
import android.view.Surface
import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.LAUNCHER_COMPONENT
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
import com.android.server.wm.flicker.helpers.setRotation
+import com.android.server.wm.traces.common.FlickerComponentName.Companion.LAUNCHER
import org.junit.Test
/**
@@ -78,7 +78,7 @@ abstract class ExitPipTransition(testSpec: FlickerTestParameter) : PipTransition
}
/**
- * Checks that [pipApp] and [LAUNCHER_COMPONENT] layers are visible at the start
+ * Checks that [pipApp] and [LAUNCHER] layers are visible at the start
* of the transition. Then [pipApp] layer becomes invisible, and remains invisible
* until the end of the transition
*/
@@ -87,10 +87,10 @@ abstract class ExitPipTransition(testSpec: FlickerTestParameter) : PipTransition
open fun pipLayerBecomesInvisible() {
testSpec.assertLayers {
this.isVisible(pipApp.component)
- .isVisible(LAUNCHER_COMPONENT)
+ .isVisible(LAUNCHER)
.then()
.isInvisible(pipApp.component)
- .isVisible(LAUNCHER_COMPONENT)
+ .isVisible(LAUNCHER)
}
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipViaExpandButtonClickTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipViaExpandButtonClickTest.kt
index 46424a768408..32022ad5f018 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipViaExpandButtonClickTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipViaExpandButtonClickTest.kt
@@ -16,8 +16,8 @@
package com.android.wm.shell.flicker.pip
-import android.view.Surface
import android.platform.test.annotations.FlakyTest
+import android.view.Surface
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
@@ -74,7 +74,9 @@ class ExitPipViaExpandButtonClickTest(
// This will bring PipApp to fullscreen
pipApp.expandPipWindowToApp(wmHelper)
// Wait until the other app is no longer visible
- wmHelper.waitForWindowSurfaceDisappeared(testApp.component)
+ wmHelper.StateSyncBuilder()
+ .withWindowSurfaceDisappeared(testApp.component)
+ .waitForAndVerify()
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipViaIntentTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipViaIntentTest.kt
index 18711d8fd3c6..3fbea488d091 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipViaIntentTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipViaIntentTest.kt
@@ -16,9 +16,9 @@
package com.android.wm.shell.flicker.pip
+import android.platform.test.annotations.FlakyTest
import android.platform.test.annotations.Presubmit
import android.view.Surface
-import android.platform.test.annotations.FlakyTest
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
@@ -73,7 +73,9 @@ class ExitPipViaIntentTest(testSpec: FlickerTestParameter) : ExitPipToAppTransit
// This will bring PipApp to fullscreen
pipApp.exitPipToFullScreenViaIntent(wmHelper)
// Wait until the other app is no longer visible
- wmHelper.waitForWindowSurfaceDisappeared(testApp.component)
+ wmHelper.StateSyncBuilder()
+ .withWindowSurfaceDisappeared(testApp.component)
+ .waitForAndVerify()
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipWithSwipeDownTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipWithSwipeDownTest.kt
index 9aae7f324269..210b1968b2da 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipWithSwipeDownTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipWithSwipeDownTest.kt
@@ -16,9 +16,9 @@
package com.android.wm.shell.flicker.pip
+import android.platform.test.annotations.FlakyTest
import android.platform.test.annotations.Presubmit
import android.view.Surface
-import android.platform.test.annotations.FlakyTest
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
@@ -64,9 +64,12 @@ class ExitPipWithSwipeDownTest(testSpec: FlickerTestParameter) : ExitPipTransiti
val pipCenterY = pipRegion.centerY()
val displayCenterX = device.displayWidth / 2
device.swipe(pipCenterX, pipCenterY, displayCenterX, device.displayHeight, 10)
- wmHelper.waitPipGone()
- wmHelper.waitForWindowSurfaceDisappeared(pipApp.component)
- wmHelper.waitForAppTransitionIdle()
+ // Wait until the other app is no longer visible
+ wmHelper.StateSyncBuilder()
+ .withPipGone()
+ .withWindowSurfaceDisappeared(pipApp.component)
+ .withAppTransitionIdle()
+ .waitForAndVerify()
}
}
@@ -108,4 +111,4 @@ class ExitPipWithSwipeDownTest(testSpec: FlickerTestParameter) : ExitPipTransiti
repetitions = 3)
}
}
-} \ No newline at end of file
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt
index ffbb89ee8f6b..dc1fdde18d1b 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt
@@ -23,9 +23,9 @@ import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.FlickerTestParameterFactory
-import com.android.server.wm.flicker.LAUNCHER_COMPONENT
import com.android.server.wm.flicker.annotation.Group3
import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.traces.common.FlickerComponentName.Companion.LAUNCHER
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -147,13 +147,13 @@ class ExpandPipOnDoubleClickTest(testSpec: FlickerTestParameter) : PipTransition
}
/**
- * Checks [pipApp] layer remains visible throughout the animation
+ * Checks [LAUNCHER] layer remains visible throughout the animation
*/
@Presubmit
@Test
fun launcherIsAlwaysVisible() {
testSpec.assertLayers {
- isVisible(LAUNCHER_COMPONENT)
+ isVisible(LAUNCHER)
}
}
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 8d542c8ec9e6..fe5dd8b83cfb 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
@@ -21,6 +21,7 @@ import android.content.Intent
import android.platform.test.annotations.Presubmit
import android.view.Surface
import androidx.test.platform.app.InstrumentationRegistry
+import com.android.launcher3.tapl.LauncherInstrumentation
import com.android.server.wm.flicker.FlickerBuilderProvider
import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.dsl.FlickerBuilder
@@ -41,6 +42,7 @@ import org.junit.Test
abstract class PipTransition(protected val testSpec: FlickerTestParameter) {
protected val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+ protected val tapl = LauncherInstrumentation()
protected val pipApp = PipAppHelper(instrumentation)
protected val displayBounds = WindowUtils.getDisplayBounds(testSpec.startRotation)
protected val broadcastActionTrigger = BroadcastActionTrigger(instrumentation)
@@ -117,13 +119,11 @@ abstract class PipTransition(protected val testSpec: FlickerTestParameter) {
test {
if (!eachRun) {
pipApp.launchViaIntentAndWaitForPip(wmHelper, stringExtras = stringExtras)
- wmHelper.waitPipShown()
}
}
eachRun {
if (eachRun) {
pipApp.launchViaIntentAndWaitForPip(wmHelper, stringExtras = stringExtras)
- wmHelper.waitPipShown()
}
}
}
@@ -171,4 +171,4 @@ abstract class PipTransition(protected val testSpec: FlickerTestParameter) {
@Presubmit
@Test
open fun entireScreenCovered() = testSpec.entireScreenCovered()
-} \ No newline at end of file
+}
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 e44cf3866a09..83d3fe260928 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
@@ -16,18 +16,18 @@
package com.android.wm.shell.flicker.pip
+import android.platform.test.annotations.FlakyTest
import android.platform.test.annotations.Presubmit
import android.view.Surface
-import android.platform.test.annotations.FlakyTest
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
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.WindowUtils
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.rules.RemoveAllTasksButHomeRule.Companion.removeAllTasksButHome
import com.android.wm.shell.flicker.pip.PipTransition.BroadcastActionTrigger.Companion.ORIENTATION_LANDSCAPE
import com.android.wm.shell.flicker.testapp.Components
@@ -66,11 +66,12 @@ open class SetRequestedOrientationWhilePinnedTest(
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()
+ wmHelper.StateSyncBuilder()
+ .withPipShown()
+ .withRotation(Surface.ROTATION_0)
+ .withNavBarStatusBarVisible()
+ .waitForAndVerify()
}
}
teardown {
@@ -85,11 +86,13 @@ open class SetRequestedOrientationWhilePinnedTest(
transitions {
// 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()
+ wmHelper.StateSyncBuilder()
+ .withFullScreenApp(pipApp.component)
+ .withRotation(Surface.ROTATION_90)
+ .withAppTransitionIdle()
+ .withNavBarStatusBarVisible()
+ .waitForAndVerify()
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipBasicTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipBasicTest.kt
index 49094e609fbc..31fb16ffbd3e 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipBasicTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipBasicTest.kt
@@ -43,7 +43,7 @@ class TvPipBasicTest(
// Set up ratio and enter Pip
testApp.clickObject(radioButtonId)
- testApp.clickEnterPipButton()
+ testApp.clickEnterPipButton(wmHelper)
val actualRatio: Float = testApp.ui?.visibleBounds?.ratio
?: fail("Application UI not found")
@@ -84,4 +84,4 @@ class TvPipBasicTest(
)
}
}
-} \ No newline at end of file
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipMenuTests.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipMenuTests.kt
index 061218a015e4..4be19d61278b 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipMenuTests.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipMenuTests.kt
@@ -244,7 +244,7 @@ class TvPipMenuTests : TvPipTestBase() {
}
private fun enterPip_openMenu_assertShown(): UiObject2 {
- testApp.clickEnterPipButton()
+ testApp.clickEnterPipButton(wmHelper)
// Pressing the Window key should bring up Pip menu
uiDevice.pressWindowKey()
return uiDevice.waitForTvPipMenu() ?: fail("Pip menu should have been shown")
@@ -256,4 +256,4 @@ class TvPipMenuTests : TvPipTestBase() {
uiDevice.findTvPipMenuFullscreenButton()
?: fail("\"Full screen\" button should be shown in Pip menu")
}
-} \ No newline at end of file
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipNotificationTests.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipNotificationTests.kt
index bcf38d340867..134e97bd46e7 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipNotificationTests.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipNotificationTests.kt
@@ -56,7 +56,7 @@ class TvPipNotificationTests : TvPipTestBase() {
@Test
fun pipNotification_postedAndDismissed() {
testApp.launchViaIntent()
- testApp.clickEnterPipButton()
+ testApp.clickEnterPipButton(wmHelper)
assertNotNull("Pip notification should have been posted",
waitForNotificationToAppear { it.isPipNotificationWithTitle(testApp.appName) })
@@ -70,7 +70,7 @@ class TvPipNotificationTests : TvPipTestBase() {
@Test
fun pipNotification_closeIntent() {
testApp.launchViaIntent()
- testApp.clickEnterPipButton()
+ testApp.clickEnterPipButton(wmHelper)
val notification: StatusBarNotification = waitForNotificationToAppear {
it.isPipNotificationWithTitle(testApp.appName)
@@ -87,8 +87,8 @@ class TvPipNotificationTests : TvPipTestBase() {
@Test
fun pipNotification_menuIntent() {
- testApp.launchViaIntent()
- testApp.clickEnterPipButton()
+ testApp.launchViaIntent(wmHelper)
+ testApp.clickEnterPipButton(wmHelper)
val notification: StatusBarNotification = waitForNotificationToAppear {
it.isPipNotificationWithTitle(testApp.appName)
@@ -106,10 +106,10 @@ class TvPipNotificationTests : TvPipTestBase() {
@Test
fun pipNotification_mediaSessionTitle_isDisplayed() {
- testApp.launchViaIntent()
+ testApp.launchViaIntent(wmHelper)
// Start media session and to PiP
testApp.clickStartMediaSessionButton()
- testApp.clickEnterPipButton()
+ testApp.clickEnterPipButton(wmHelper)
// Wait for the correct notification to show up...
waitForNotificationToAppear {
@@ -170,4 +170,4 @@ private val StatusBarNotification.deleteIntent: PendingIntent?
get() = tvExtensions?.getParcelable("delete_intent")
private fun StatusBarNotification.isPipNotificationWithTitle(expectedTitle: String): Boolean =
- tag == "TvPip" && title == expectedTitle \ No newline at end of file
+ tag == "TvPip" && title == expectedTitle
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipTestBase.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipTestBase.kt
index 9c3b0fa183b6..a97994e7d6c3 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipTestBase.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipTestBase.kt
@@ -23,6 +23,7 @@ import android.os.SystemClock
import android.view.Surface.ROTATION_0
import android.view.Surface.rotationToString
import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
+import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
import com.android.wm.shell.flicker.SYSTEM_UI_PACKAGE_NAME
import com.android.wm.shell.flicker.pip.PipTestBase
import org.junit.After
@@ -33,6 +34,7 @@ import org.junit.Before
abstract class TvPipTestBase : PipTestBase(rotationToString(ROTATION_0), ROTATION_0) {
private val systemUiProcessObserver = SystemUiProcessObserver()
+ protected val wmHelper = WindowManagerStateHelper()
@Before
final override fun televisionSetUp() {
@@ -88,4 +90,4 @@ abstract class TvPipTestBase : PipTestBase(rotationToString(ROTATION_0), ROTATIO
companion object {
private const val AFTER_TEXT_PROCESS_CHECK_DELAY = 1_000L // 1 sec
}
-} \ No newline at end of file
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromAllApps.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromAllApps.kt
index 702710caded7..cfba3387825c 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromAllApps.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromAllApps.kt
@@ -56,7 +56,7 @@ class EnterSplitScreenByDragFromAllApps(
) : SplitScreenBase(testSpec) {
@Before
- open fun before() {
+ fun before() {
Assume.assumeTrue(taplInstrumentation.isTablet)
}
@@ -73,8 +73,7 @@ class EnterSplitScreenByDragFromAllApps(
taplInstrumentation.launchedAppState.taskbar
.openAllApps()
.getAppIcon(secondaryApp.appName)
- .dragToSplitscreen(secondaryApp.component.packageName,
- primaryApp.component.packageName)
+ .dragToSplitscreen(secondaryApp.`package`, primaryApp.`package`)
}
}
diff --git a/libs/input/SpriteController.cpp b/libs/input/SpriteController.cpp
index cab3f8414d7b..130b204954b4 100644
--- a/libs/input/SpriteController.cpp
+++ b/libs/input/SpriteController.cpp
@@ -131,8 +131,9 @@ void SpriteController::doUpdateSprites() {
update.state.surfaceHeight = update.state.icon.height();
update.state.surfaceDrawn = false;
update.state.surfaceVisible = false;
- update.state.surfaceControl = obtainSurface(
- update.state.surfaceWidth, update.state.surfaceHeight);
+ update.state.surfaceControl =
+ obtainSurface(update.state.surfaceWidth, update.state.surfaceHeight,
+ update.state.displayId);
if (update.state.surfaceControl != NULL) {
update.surfaceChanged = surfaceChanged = true;
}
@@ -168,8 +169,8 @@ void SpriteController::doUpdateSprites() {
}
}
- // If surface is a new one, we have to set right layer stack.
- if (update.surfaceChanged || update.state.dirty & DIRTY_DISPLAY_ID) {
+ // If surface has changed to a new display, we have to reparent it.
+ if (update.state.dirty & DIRTY_DISPLAY_ID) {
t.reparent(update.state.surfaceControl, mParentSurfaceProvider(update.state.displayId));
needApplyTransaction = true;
}
@@ -330,21 +331,28 @@ void SpriteController::ensureSurfaceComposerClient() {
}
}
-sp<SurfaceControl> SpriteController::obtainSurface(int32_t width, int32_t height) {
+sp<SurfaceControl> SpriteController::obtainSurface(int32_t width, int32_t height,
+ int32_t displayId) {
ensureSurfaceComposerClient();
- sp<SurfaceControl> surfaceControl = mSurfaceComposerClient->createSurface(
- String8("Sprite"), width, height, PIXEL_FORMAT_RGBA_8888,
- ISurfaceComposerClient::eHidden |
- ISurfaceComposerClient::eCursorWindow);
- if (surfaceControl == NULL || !surfaceControl->isValid()) {
+ const sp<SurfaceControl> parent = mParentSurfaceProvider(displayId);
+ if (parent == nullptr) {
+ ALOGE("Failed to get the parent surface for pointers on display %d", displayId);
+ }
+
+ const sp<SurfaceControl> surfaceControl =
+ mSurfaceComposerClient->createSurface(String8("Sprite"), width, height,
+ PIXEL_FORMAT_RGBA_8888,
+ ISurfaceComposerClient::eHidden |
+ ISurfaceComposerClient::eCursorWindow,
+ parent ? parent->getHandle() : nullptr);
+ if (surfaceControl == nullptr || !surfaceControl->isValid()) {
ALOGE("Error creating sprite surface.");
- return NULL;
+ return nullptr;
}
return surfaceControl;
}
-
// --- SpriteController::SpriteImpl ---
SpriteController::SpriteImpl::SpriteImpl(const sp<SpriteController> controller) :
diff --git a/libs/input/SpriteController.h b/libs/input/SpriteController.h
index 2e9cb9685c46..1f113c045360 100644
--- a/libs/input/SpriteController.h
+++ b/libs/input/SpriteController.h
@@ -265,7 +265,7 @@ private:
void doDisposeSurfaces();
void ensureSurfaceComposerClient();
- sp<SurfaceControl> obtainSurface(int32_t width, int32_t height);
+ sp<SurfaceControl> obtainSurface(int32_t width, int32_t height, int32_t displayId);
};
} // namespace android
diff --git a/libs/protoutil/Android.bp b/libs/protoutil/Android.bp
index 132d71eb6db8..128be3c33ac5 100644
--- a/libs/protoutil/Android.bp
+++ b/libs/protoutil/Android.bp
@@ -55,6 +55,7 @@ cc_library {
export_include_dirs: ["include"],
+ min_sdk_version: "30",
apex_available: [
"//apex_available:platform",
"com.android.os.statsd",
@@ -81,5 +82,5 @@ cc_test {
proto: {
type: "full",
- }
+ },
}