diff options
Diffstat (limited to 'libs')
163 files changed, 2055 insertions, 1662 deletions
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/util/AcceptOnceConsumer.java b/libs/WindowManager/Jetpack/src/androidx/window/common/AcceptOnceConsumer.java index 63828ab2e62b..c2f827a22fc2 100644 --- a/libs/WindowManager/Jetpack/src/androidx/window/util/AcceptOnceConsumer.java +++ b/libs/WindowManager/Jetpack/src/androidx/window/common/AcceptOnceConsumer.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package androidx.window.util; +package androidx.window.common; import android.annotation.NonNull; diff --git a/libs/WindowManager/Jetpack/src/androidx/window/util/BaseDataProducer.java b/libs/WindowManager/Jetpack/src/androidx/window/common/BaseDataProducer.java index cd26efd4fdb6..e7099dc3a281 100644 --- a/libs/WindowManager/Jetpack/src/androidx/window/util/BaseDataProducer.java +++ b/libs/WindowManager/Jetpack/src/androidx/window/common/BaseDataProducer.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package androidx.window.util; +package androidx.window.common; import androidx.annotation.GuardedBy; import androidx.annotation.NonNull; @@ -125,4 +125,4 @@ public abstract class BaseDataProducer<T> implements mCallbacksToRemove.add(callback); } } -}
\ No newline at end of file +} diff --git a/libs/WindowManager/Jetpack/src/androidx/window/common/CommonFoldingFeature.java b/libs/WindowManager/Jetpack/src/androidx/window/common/CommonFoldingFeature.java index e37dea4dfd69..b95bca16ef5b 100644 --- a/libs/WindowManager/Jetpack/src/androidx/window/common/CommonFoldingFeature.java +++ b/libs/WindowManager/Jetpack/src/androidx/window/common/CommonFoldingFeature.java @@ -16,7 +16,7 @@ package androidx.window.common; -import static androidx.window.util.ExtensionHelper.isZero; +import static androidx.window.common.ExtensionHelper.isZero; import android.annotation.IntDef; import android.annotation.Nullable; diff --git a/libs/WindowManager/Jetpack/src/androidx/window/common/DeviceStateManagerFoldingFeatureProducer.java b/libs/WindowManager/Jetpack/src/androidx/window/common/DeviceStateManagerFoldingFeatureProducer.java index 98935e95deaf..b2bc3de1e7f5 100644 --- a/libs/WindowManager/Jetpack/src/androidx/window/common/DeviceStateManagerFoldingFeatureProducer.java +++ b/libs/WindowManager/Jetpack/src/androidx/window/common/DeviceStateManagerFoldingFeatureProducer.java @@ -31,9 +31,6 @@ import android.text.TextUtils; import android.util.Log; import android.util.SparseIntArray; -import androidx.window.util.AcceptOnceConsumer; -import androidx.window.util.BaseDataProducer; - import com.android.internal.R; import java.util.ArrayList; @@ -44,7 +41,7 @@ import java.util.Optional; import java.util.function.Consumer; /** - * An implementation of {@link androidx.window.util.BaseDataProducer} that returns + * An implementation of {@link BaseDataProducer} that returns * the device's posture by mapping the state returned from {@link DeviceStateManager} to * values provided in the resources' config at {@link R.array#config_device_state_postures}. */ diff --git a/libs/WindowManager/Jetpack/src/androidx/window/util/ExtensionHelper.java b/libs/WindowManager/Jetpack/src/androidx/window/common/ExtensionHelper.java index a08db7939eca..f466d603bda3 100644 --- a/libs/WindowManager/Jetpack/src/androidx/window/util/ExtensionHelper.java +++ b/libs/WindowManager/Jetpack/src/androidx/window/common/ExtensionHelper.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package androidx.window.util; +package androidx.window.common; import static android.view.Surface.ROTATION_270; import static android.view.Surface.ROTATION_90; diff --git a/libs/WindowManager/Jetpack/src/androidx/window/common/RawFoldingFeatureProducer.java b/libs/WindowManager/Jetpack/src/androidx/window/common/RawFoldingFeatureProducer.java index 88264f383153..6d758f1fb3c1 100644 --- a/libs/WindowManager/Jetpack/src/androidx/window/common/RawFoldingFeatureProducer.java +++ b/libs/WindowManager/Jetpack/src/androidx/window/common/RawFoldingFeatureProducer.java @@ -26,15 +26,13 @@ import android.os.Looper; import android.provider.Settings; import android.text.TextUtils; -import androidx.window.util.BaseDataProducer; - import com.android.internal.R; import java.util.Optional; import java.util.function.Consumer; /** - * Implementation of {@link androidx.window.util.BaseDataProducer} that produces a + * Implementation of {@link BaseDataProducer} that produces a * {@link String} that can be parsed to a {@link CommonFoldingFeature}. * {@link RawFoldingFeatureProducer} searches for the value in two places. The first check is in * settings where the {@link String} property is saved with the key 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 8e1fde066277..409cde30cf8c 100644 --- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java +++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java @@ -119,7 +119,8 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen // TODO(b/243518738): Move to WM Extensions if we have requirement of overlay without // association. It's not set in WM Extensions nor Wm Jetpack library currently. - private static final String KEY_OVERLAY_ASSOCIATE_WITH_LAUNCHING_ACTIVITY = + @VisibleForTesting + static final String KEY_OVERLAY_ASSOCIATE_WITH_LAUNCHING_ACTIVITY = "androidx.window.extensions.embedding.shouldAssociateWithLaunchingActivity"; @VisibleForTesting @@ -2742,89 +2743,70 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen } final int taskId = getTaskId(launchActivity); - if (!overlayContainers.isEmpty()) { - for (final TaskFragmentContainer overlayContainer : overlayContainers) { - final boolean isTopNonFinishingOverlay = overlayContainer.equals( - overlayContainer.getTaskContainer().getTopNonFinishingTaskFragmentContainer( - true /* includePin */, true /* includeOverlay */)); - if (taskId != overlayContainer.getTaskId()) { - // If there's an overlay container with same tag in a different task, - // dismiss the overlay container since the tag must be unique per process. - if (overlayTag.equals(overlayContainer.getOverlayTag())) { - Log.w(TAG, "The overlay container with tag:" - + overlayContainer.getOverlayTag() + " is dismissed because" - + " there's an existing overlay container with the same tag but" - + " different task ID:" + overlayContainer.getTaskId() + ". " - + "The new associated activity is " + launchActivity); - mPresenter.cleanupContainer(wct, overlayContainer, - false /* shouldFinishDependant */); - } - continue; - } - if (!overlayTag.equals(overlayContainer.getOverlayTag())) { - // If there's an overlay container with different tag on top in the same - // task, dismiss the existing overlay container. - if (isTopNonFinishingOverlay) { - mPresenter.cleanupContainer(wct, overlayContainer, - false /* shouldFinishDependant */); - } - continue; - } - // The overlay container has the same tag and task ID with the new launching - // overlay container. - if (!isTopNonFinishingOverlay) { - // Dismiss the invisible overlay container regardless of activity - // association if it collides the tag of new launched overlay container . - Log.w(TAG, "The invisible overlay container with tag:" - + overlayContainer.getOverlayTag() + " is dismissed because" - + " there's a launching overlay container with the same tag." - + " The new associated activity is " + launchActivity); - mPresenter.cleanupContainer(wct, overlayContainer, - false /* shouldFinishDependant */); - continue; - } - // Requesting an always-on-top overlay. - if (!associateLaunchingActivity) { - if (overlayContainer.isOverlayWithActivityAssociation()) { - // Dismiss the overlay container since it has associated with an activity. - Log.w(TAG, "The overlay container with tag:" - + overlayContainer.getOverlayTag() + " is dismissed because" - + " there's an existing overlay container with the same tag but" - + " different associated launching activity. The overlay container" - + " doesn't associate with any activity."); - mPresenter.cleanupContainer(wct, overlayContainer, - false /* shouldFinishDependant */); - continue; - } else { - // The existing overlay container doesn't associate an activity as well. - // Just update the overlay and return. - // Note that going to this condition means the tag, task ID matches a - // visible always-on-top overlay, and won't dismiss any overlay any more. - mPresenter.applyActivityStackAttributes(wct, overlayContainer, attrs, - getMinDimensions(intent)); - return overlayContainer; - } - } - if (launchActivity.getActivityToken() - != overlayContainer.getAssociatedActivityToken()) { - Log.w(TAG, "The overlay container with tag:" - + overlayContainer.getOverlayTag() + " is dismissed because" - + " there's an existing overlay container with the same tag but" - + " different associated launching activity. The new associated" - + " activity is " + launchActivity); - // The associated activity must be the same, or it will be dismissed. - mPresenter.cleanupContainer(wct, overlayContainer, - false /* shouldFinishDependant */); - continue; - } - // Reaching here means the launching activity launch an overlay container with the - // same task ID, tag, while there's a previously launching visible overlay - // container. We'll regard it as updating the existing overlay container. + // Overlay container policy: + // 1. Overlay tag must be unique per process. + // a. For associated overlay, if a new launched overlay container has the same tag as + // an existing one, the existing overlay will be dismissed regardless of its task + // and window hierarchy. + // b. For always-on-top overlay, if there's an overlay container has the same tag in the + // launched task, the overlay container will be re-used, which means the + // ActivityStackAttributes will be applied and the launched activity will be positioned + // on top of the overlay container. + // 2. There must be at most one overlay that partially occludes a visible activity per task. + // a. For associated overlay, only the top visible overlay container in the launched task + // will be dismissed. + // b. Always-on-top overlay is always visible. If there's an overlay with different tags + // in the same task, the overlay will be dismissed in case an activity above + // the overlay is dismissed and the overlay is shown unexpectedly. + for (final TaskFragmentContainer overlayContainer : overlayContainers) { + final boolean isTopNonFinishingOverlay = overlayContainer.isTopNonFinishingChild(); + final boolean areInSameTask = taskId == overlayContainer.getTaskId(); + final boolean haveSameTag = overlayTag.equals(overlayContainer.getOverlayTag()); + if (!associateLaunchingActivity && overlayContainer.isAlwaysOnTopOverlay() + && haveSameTag && areInSameTask) { + // Just launch the activity and update the existing always-on-top overlay + // if the requested overlay is an always-on-top overlay with the same tag + // as the existing one. mPresenter.applyActivityStackAttributes(wct, overlayContainer, attrs, getMinDimensions(intent)); return overlayContainer; - } + if (haveSameTag) { + // For other tag match, we should clean up the existing overlay since the overlay + // tag must be unique per process. + Log.w(TAG, "The overlay container with tag:" + + overlayContainer.getOverlayTag() + " is dismissed with " + + " the launching activity=" + launchActivity + + " because there's an existing overlay container with the same tag."); + mPresenter.cleanupContainer(wct, overlayContainer, + false /* shouldFinishDependant */); + } + if (!areInSameTask) { + // Early return here because we won't clean-up or update overlay from different + // tasks except tag collision. + continue; + } + if (associateLaunchingActivity) { + // For associated overlay, we only dismiss the overlay if it's the top non-finishing + // child of its parent container. + if (isTopNonFinishingOverlay) { + Log.w(TAG, "The on-top overlay container with tag:" + + overlayContainer.getOverlayTag() + " is dismissed with " + + " the launching activity=" + launchActivity + + "because we only allow one overlay on top."); + mPresenter.cleanupContainer(wct, overlayContainer, + false /* shouldFinishDependant */); + } + continue; + } + // Otherwise, we should clean up the overlay in the task because we only allow one + // overlay when an always-on-top overlay is launched. + Log.w(TAG, "The overlay container with tag:" + + overlayContainer.getOverlayTag() + " is dismissed with " + + " the launching activity=" + launchActivity + + "because an always-on-top overlay is launched."); + mPresenter.cleanupContainer(wct, overlayContainer, + false /* shouldFinishDependant */); } // Launch the overlay container to the task with taskId. return createEmptyContainer(wct, intent, taskId, attrs, launchActivity, overlayTag, 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 7173b0c95230..d0e2c998e961 100644 --- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java +++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java @@ -340,6 +340,13 @@ class TaskFragmentContainer { return mInfo != null && mInfo.isVisible(); } + /** + * See {@link TaskFragmentInfo#isTopNonFinishingChild()} + */ + boolean isTopNonFinishingChild() { + return mInfo != null && mInfo.isTopNonFinishingChild(); + } + /** Whether the TaskFragment is in an intermediate state waiting for the server update.*/ boolean isInIntermediateState() { if (mInfo == null) { diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/layout/WindowLayoutComponentImpl.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/layout/WindowLayoutComponentImpl.java index 84984a9f8c7b..a3ef68a15196 100644 --- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/layout/WindowLayoutComponentImpl.java +++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/layout/WindowLayoutComponentImpl.java @@ -21,9 +21,9 @@ import static android.view.Display.INVALID_DISPLAY; import static androidx.window.common.CommonFoldingFeature.COMMON_STATE_FLAT; import static androidx.window.common.CommonFoldingFeature.COMMON_STATE_HALF_OPENED; -import static androidx.window.util.ExtensionHelper.isZero; -import static androidx.window.util.ExtensionHelper.rotateRectToDisplayRotation; -import static androidx.window.util.ExtensionHelper.transformToWindowSpaceRect; +import static androidx.window.common.ExtensionHelper.isZero; +import static androidx.window.common.ExtensionHelper.rotateRectToDisplayRotation; +import static androidx.window.common.ExtensionHelper.transformToWindowSpaceRect; import android.app.Activity; import android.app.ActivityThread; diff --git a/libs/WindowManager/Jetpack/src/androidx/window/sidecar/SampleSidecarImpl.java b/libs/WindowManager/Jetpack/src/androidx/window/sidecar/SampleSidecarImpl.java index 339908a3a9a4..b63fd0802e5f 100644 --- a/libs/WindowManager/Jetpack/src/androidx/window/sidecar/SampleSidecarImpl.java +++ b/libs/WindowManager/Jetpack/src/androidx/window/sidecar/SampleSidecarImpl.java @@ -25,11 +25,11 @@ import android.os.Bundle; import android.os.IBinder; import androidx.annotation.NonNull; +import androidx.window.common.BaseDataProducer; import androidx.window.common.CommonFoldingFeature; import androidx.window.common.DeviceStateManagerFoldingFeatureProducer; import androidx.window.common.EmptyLifecycleCallbacksAdapter; import androidx.window.common.RawFoldingFeatureProducer; -import androidx.window.util.BaseDataProducer; import java.util.ArrayList; import java.util.List; diff --git a/libs/WindowManager/Jetpack/src/androidx/window/sidecar/SidecarHelper.java b/libs/WindowManager/Jetpack/src/androidx/window/sidecar/SidecarHelper.java index bb6ab47b144d..4fd03e4bdc0b 100644 --- a/libs/WindowManager/Jetpack/src/androidx/window/sidecar/SidecarHelper.java +++ b/libs/WindowManager/Jetpack/src/androidx/window/sidecar/SidecarHelper.java @@ -17,8 +17,8 @@ package androidx.window.sidecar; import static android.view.Display.DEFAULT_DISPLAY; -import static androidx.window.util.ExtensionHelper.rotateRectToDisplayRotation; -import static androidx.window.util.ExtensionHelper.transformToWindowSpaceRect; +import static androidx.window.common.ExtensionHelper.rotateRectToDisplayRotation; +import static androidx.window.common.ExtensionHelper.transformToWindowSpaceRect; import android.annotation.NonNull; import android.app.Activity; diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/util/ExtensionHelperTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/common/ExtensionHelperTest.java index 3278cdf1c337..b6e951961a69 100644 --- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/util/ExtensionHelperTest.java +++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/common/ExtensionHelperTest.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package androidx.window.util; +package androidx.window.common; import static org.junit.Assert.assertEquals; 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 d649c6d57137..7dc78fdd601f 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 @@ -163,12 +163,14 @@ public class EmbeddingTestUtils { } /** Creates a mock TaskFragmentInfo for the given TaskFragment. */ + @NonNull static TaskFragmentInfo createMockTaskFragmentInfo(@NonNull TaskFragmentContainer container, @NonNull Activity activity) { return createMockTaskFragmentInfo(container, activity, true /* isVisible */); } /** Creates a mock TaskFragmentInfo for the given TaskFragment. */ + @NonNull static TaskFragmentInfo createMockTaskFragmentInfo(@NonNull TaskFragmentContainer container, @NonNull Activity activity, boolean isVisible) { return new TaskFragmentInfo(container.getTaskFragmentToken(), @@ -182,7 +184,27 @@ public class EmbeddingTestUtils { false /* isTaskClearedForReuse */, false /* isTaskFragmentClearedForPip */, false /* isClearedForReorderActivityToFront */, - new Point()); + new Point(), + false /* isTopChild */); + } + + /** Creates a mock TaskFragmentInfo for the given TaskFragment. */ + @NonNull + static TaskFragmentInfo createMockTaskFragmentInfo(@NonNull TaskFragmentContainer container, + @NonNull Activity activity, boolean isVisible, boolean isOnTop) { + return new TaskFragmentInfo(container.getTaskFragmentToken(), + mock(WindowContainerToken.class), + new Configuration(), + 1, + isVisible, + Collections.singletonList(activity.getActivityToken()), + new ArrayList<>(), + new Point(), + false /* isTaskClearedForReuse */, + false /* isTaskFragmentClearedForPip */, + false /* isClearedForReorderActivityToFront */, + new Point(), + isOnTop); } static ActivityInfo createActivityInfoWithMinDimensions() { diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizerTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizerTest.java index ad41b18dcbc6..8911d18b9b97 100644 --- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizerTest.java +++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizerTest.java @@ -114,6 +114,7 @@ public class JetpackTaskFragmentOrganizerTest { mock(WindowContainerToken.class), new Configuration(), 0 /* runningActivityCount */, false /* isVisible */, new ArrayList<>(), new ArrayList<>(), new Point(), false /* isTaskClearedForReuse */, false /* isTaskFragmentClearedForPip */, - false /* isClearedForReorderActivityToFront */, new Point()); + false /* isClearedForReorderActivityToFront */, new Point(), + false /* isTopChild */); } } diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/OverlayPresentationTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/OverlayPresentationTest.java index 1c4c8870b26f..475475b05272 100644 --- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/OverlayPresentationTest.java +++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/OverlayPresentationTest.java @@ -30,6 +30,7 @@ import static androidx.window.extensions.embedding.EmbeddingTestUtils.createSpli import static androidx.window.extensions.embedding.EmbeddingTestUtils.createSplitPlaceholderRuleBuilder; import static androidx.window.extensions.embedding.EmbeddingTestUtils.createSplitRule; import static androidx.window.extensions.embedding.EmbeddingTestUtils.createTfContainer; +import static androidx.window.extensions.embedding.SplitController.KEY_OVERLAY_ASSOCIATE_WITH_LAUNCHING_ACTIVITY; import static androidx.window.extensions.embedding.SplitPresenter.CONTAINER_POSITION_BOTTOM; import static androidx.window.extensions.embedding.SplitPresenter.CONTAINER_POSITION_LEFT; import static androidx.window.extensions.embedding.SplitPresenter.CONTAINER_POSITION_RIGHT; @@ -94,6 +95,7 @@ import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; +import org.mockito.Mockito; import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoRule; @@ -267,7 +269,7 @@ public class OverlayPresentationTest { } @Test - public void testCreateOrUpdateOverlay_visibleOverlaySameTagInTask_dismissOverlay() { + public void testCreateOrUpdateOverlay_topOverlayInTask_dismissOverlay() { createExistingOverlayContainers(); final TaskFragmentContainer overlayContainer = @@ -295,26 +297,6 @@ public class OverlayPresentationTest { } @Test - public void testCreateOrUpdateOverlay_sameTagTaskAndActivity_updateOverlay() { - createExistingOverlayContainers(); - - final Rect bounds = new Rect(0, 0, 100, 100); - mSplitController.setActivityStackAttributesCalculator(params -> - new ActivityStackAttributes.Builder().setRelativeBounds(bounds).build()); - final TaskFragmentContainer overlayContainer = createOrUpdateOverlayTaskFragmentIfNeeded( - mOverlayContainer1.getOverlayTag()); - - assertWithMessage("overlayContainer1 must be updated since the new overlay container" - + " is launched with the same tag and task") - .that(mSplitController.getAllNonFinishingOverlayContainers()) - .containsExactly(mOverlayContainer1, mOverlayContainer2); - - assertThat(overlayContainer).isEqualTo(mOverlayContainer1); - verify(mSplitPresenter).resizeTaskFragment(eq(mTransaction), - eq(mOverlayContainer1.getTaskFragmentToken()), eq(bounds)); - } - - @Test public void testCreateOrUpdateOverlay_sameTagAndTaskButNotActivity_dismissOverlay() { createExistingOverlayContainers(); @@ -362,6 +344,43 @@ public class OverlayPresentationTest { } @Test + public void testCreateOrUpdateAlwaysOnTopOverlay_dismissMultipleOverlaysInTask() { + createExistingOverlayContainers(); + // Create another overlay in task. + final TaskFragmentContainer overlayContainer3 = + createTestOverlayContainer(TASK_ID, "test3"); + assertThat(mSplitController.getAllNonFinishingOverlayContainers()) + .containsExactly(mOverlayContainer1, mOverlayContainer2, overlayContainer3); + + final TaskFragmentContainer overlayContainer = + createOrUpdateAlwaysOnTopOverlay("test4"); + + assertWithMessage("overlayContainer1 and overlayContainer3 must be dismissed") + .that(mSplitController.getAllNonFinishingOverlayContainers()) + .containsExactly(mOverlayContainer2, overlayContainer); + } + + @Test + public void testCreateOrUpdateAlwaysOnTopOverlay_updateOverlay() { + createExistingOverlayContainers(); + // Create another overlay in task. + final TaskFragmentContainer alwaysOnTopOverlay = createTestOverlayContainer(TASK_ID, + "test3", true /* isVisible */, false /* associateLaunchingActivity */); + final ActivityStackAttributes attrs = new ActivityStackAttributes.Builder() + .setRelativeBounds(new Rect(0, 0, 100, 100)).build(); + mSplitController.setActivityStackAttributesCalculator(params -> attrs); + + Mockito.clearInvocations(mSplitPresenter); + final TaskFragmentContainer overlayContainer = + createOrUpdateAlwaysOnTopOverlay(alwaysOnTopOverlay.getOverlayTag()); + + assertWithMessage("overlayContainer1 and overlayContainer3 must be dismissed") + .that(mSplitController.getAllNonFinishingOverlayContainers()) + .containsExactly(mOverlayContainer2, alwaysOnTopOverlay); + assertThat(overlayContainer).isEqualTo(alwaysOnTopOverlay); + } + + @Test public void testCreateOrUpdateOverlay_launchFromSplit_returnNull() { final Activity primaryActivity = createMockActivity(); final Activity secondaryActivity = createMockActivity(); @@ -381,13 +400,13 @@ public class OverlayPresentationTest { } private void createExistingOverlayContainers() { - createExistingOverlayContainers(true /* visible */); + createExistingOverlayContainers(true /* isOnTop */); } - private void createExistingOverlayContainers(boolean visible) { - mOverlayContainer1 = createTestOverlayContainer(TASK_ID, "test1", visible, + private void createExistingOverlayContainers(boolean isOnTop) { + mOverlayContainer1 = createTestOverlayContainer(TASK_ID, "test1", isOnTop, true /* associatedLaunchingActivity */, mActivity); - mOverlayContainer2 = createTestOverlayContainer(TASK_ID + 1, "test2", visible); + mOverlayContainer2 = createTestOverlayContainer(TASK_ID + 1, "test2", isOnTop); List<TaskFragmentContainer> overlayContainers = mSplitController .getAllNonFinishingOverlayContainers(); assertThat(overlayContainers).containsExactly(mOverlayContainer1, mOverlayContainer2); @@ -966,6 +985,16 @@ public class OverlayPresentationTest { launchOptions, mIntent, activity); } + @Nullable + private TaskFragmentContainer createOrUpdateAlwaysOnTopOverlay( + @NonNull String tag) { + final Bundle launchOptions = new Bundle(); + launchOptions.putBoolean(KEY_OVERLAY_ASSOCIATE_WITH_LAUNCHING_ACTIVITY, false); + launchOptions.putString(KEY_OVERLAY_TAG, tag); + return mSplitController.createOrUpdateOverlayTaskFragmentIfNeeded(mTransaction, + launchOptions, mIntent, createMockActivity()); + } + /** Creates a mock TaskFragment that has been registered and appeared in the organizer. */ @NonNull private TaskFragmentContainer createMockTaskFragmentContainer(@NonNull Activity activity) { @@ -975,10 +1004,10 @@ public class OverlayPresentationTest { /** Creates a mock TaskFragment that has been registered and appeared in the organizer. */ @NonNull private TaskFragmentContainer createMockTaskFragmentContainer( - @NonNull Activity activity, boolean isVisible) { + @NonNull Activity activity, boolean isOnTop) { final TaskFragmentContainer container = createTfContainer(mSplitController, activity.getTaskId(), activity); - setupTaskFragmentInfo(container, activity, isVisible); + setupTaskFragmentInfo(container, activity, isOnTop); return container; } @@ -990,8 +1019,8 @@ public class OverlayPresentationTest { @NonNull private TaskFragmentContainer createTestOverlayContainer(int taskId, @NonNull String tag, - boolean isVisible) { - return createTestOverlayContainer(taskId, tag, isVisible, + boolean isOnTop) { + return createTestOverlayContainer(taskId, tag, isOnTop, true /* associateLaunchingActivity */); } @@ -1002,11 +1031,9 @@ public class OverlayPresentationTest { null /* launchingActivity */); } - // TODO(b/243518738): add more test coverage on overlay container without activity association - // once we have use cases. @NonNull private TaskFragmentContainer createTestOverlayContainer(int taskId, @NonNull String tag, - boolean isVisible, boolean associateLaunchingActivity, + boolean isOnTop, boolean associateLaunchingActivity, @Nullable Activity launchingActivity) { final Activity activity = launchingActivity != null ? launchingActivity : createMockActivity(); @@ -1017,14 +1044,15 @@ public class OverlayPresentationTest { .setLaunchOptions(Bundle.EMPTY) .setAssociatedActivity(associateLaunchingActivity ? activity : null) .build(); - setupTaskFragmentInfo(overlayContainer, createMockActivity(), isVisible); + setupTaskFragmentInfo(overlayContainer, createMockActivity(), isOnTop); return overlayContainer; } private void setupTaskFragmentInfo(@NonNull TaskFragmentContainer container, @NonNull Activity activity, - boolean isVisible) { - final TaskFragmentInfo info = createMockTaskFragmentInfo(container, activity, isVisible); + boolean isOnTop) { + final TaskFragmentInfo info = createMockTaskFragmentInfo(container, activity, isOnTop, + isOnTop); container.setInfo(mTransaction, info); mSplitPresenter.mFragmentInfos.put(container.getTaskFragmentToken(), info); } diff --git a/libs/WindowManager/Shell/res/layout/compat_ui_layout.xml b/libs/WindowManager/Shell/res/layout/compat_ui_layout.xml index 257fe1544bbb..62782a784db9 100644 --- a/libs/WindowManager/Shell/res/layout/compat_ui_layout.xml +++ b/libs/WindowManager/Shell/res/layout/compat_ui_layout.xml @@ -21,38 +21,6 @@ android:orientation="vertical" android:gravity="bottom|end"> - <include android:id="@+id/camera_compat_hint" - android:visibility="gone" - android:layout_width="@dimen/camera_compat_hint_width" - android:layout_height="wrap_content" - layout="@layout/compat_mode_hint"/> - - <LinearLayout - android:id="@+id/camera_compat_control" - android:visibility="gone" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:clipToPadding="false" - android:layout_marginEnd="@dimen/compat_button_margin" - android:layout_marginBottom="@dimen/compat_button_margin" - android:orientation="vertical"> - - <ImageButton - android:id="@+id/camera_compat_treatment_button" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:background="@android:color/transparent"/> - - <ImageButton - android:id="@+id/camera_compat_dismiss_button" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:src="@drawable/camera_compat_dismiss_ripple" - android:background="@android:color/transparent" - android:contentDescription="@string/camera_compat_dismiss_button_description"/> - - </LinearLayout> - <include android:id="@+id/size_compat_hint" android:visibility="gone" android:layout_width="@dimen/compat_hint_width" diff --git a/libs/WindowManager/Shell/res/values-af/strings.xml b/libs/WindowManager/Shell/res/values-af/strings.xml index e476db050f01..e58ff6aa331e 100644 --- a/libs/WindowManager/Shell/res/values-af/strings.xml +++ b/libs/WindowManager/Shell/res/values-af/strings.xml @@ -107,7 +107,7 @@ <string name="minimize_button_text" msgid="271592547935841753">"Maak klein"</string> <string name="close_button_text" msgid="2913281996024033299">"Maak toe"</string> <string name="back_button_text" msgid="1469718707134137085">"Terug"</string> - <string name="handle_text" msgid="1766582106752184456">"Handvatsel"</string> + <string name="handle_text" msgid="4419667835599523257">"Apphandvatsel"</string> <string name="app_icon_text" msgid="2823268023931811747">"Appikoon"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Volskerm"</string> <string name="desktop_text" msgid="1077633567027630454">"Rekenaarmodus"</string> diff --git a/libs/WindowManager/Shell/res/values-am/strings.xml b/libs/WindowManager/Shell/res/values-am/strings.xml index 33fea2bcdde5..3208ea9bea61 100644 --- a/libs/WindowManager/Shell/res/values-am/strings.xml +++ b/libs/WindowManager/Shell/res/values-am/strings.xml @@ -107,7 +107,7 @@ <string name="minimize_button_text" msgid="271592547935841753">"አሳንስ"</string> <string name="close_button_text" msgid="2913281996024033299">"ዝጋ"</string> <string name="back_button_text" msgid="1469718707134137085">"ተመለስ"</string> - <string name="handle_text" msgid="1766582106752184456">"መያዣ"</string> + <string name="handle_text" msgid="4419667835599523257">"የመተግበሪያ መያዣ"</string> <string name="app_icon_text" msgid="2823268023931811747">"የመተግበሪያ አዶ"</string> <string name="fullscreen_text" msgid="1162316685217676079">"ሙሉ ማያ"</string> <string name="desktop_text" msgid="1077633567027630454">"የዴስክቶፕ ሁነታ"</string> diff --git a/libs/WindowManager/Shell/res/values-ar/strings.xml b/libs/WindowManager/Shell/res/values-ar/strings.xml index b014c3ba7d77..18db50ecdadd 100644 --- a/libs/WindowManager/Shell/res/values-ar/strings.xml +++ b/libs/WindowManager/Shell/res/values-ar/strings.xml @@ -107,7 +107,7 @@ <string name="minimize_button_text" msgid="271592547935841753">"تصغير"</string> <string name="close_button_text" msgid="2913281996024033299">"إغلاق"</string> <string name="back_button_text" msgid="1469718707134137085">"رجوع"</string> - <string name="handle_text" msgid="1766582106752184456">"مقبض"</string> + <string name="handle_text" msgid="4419667835599523257">"مقبض التطبيق"</string> <string name="app_icon_text" msgid="2823268023931811747">"رمز التطبيق"</string> <string name="fullscreen_text" msgid="1162316685217676079">"ملء الشاشة"</string> <string name="desktop_text" msgid="1077633567027630454">"وضع سطح المكتب"</string> diff --git a/libs/WindowManager/Shell/res/values-as/strings.xml b/libs/WindowManager/Shell/res/values-as/strings.xml index b94ab2e73e9c..195177230419 100644 --- a/libs/WindowManager/Shell/res/values-as/strings.xml +++ b/libs/WindowManager/Shell/res/values-as/strings.xml @@ -107,7 +107,7 @@ <string name="minimize_button_text" msgid="271592547935841753">"মিনিমাইজ কৰক"</string> <string name="close_button_text" msgid="2913281996024033299">"বন্ধ কৰক"</string> <string name="back_button_text" msgid="1469718707134137085">"উভতি যাওক"</string> - <string name="handle_text" msgid="1766582106752184456">"হেণ্ডেল"</string> + <string name="handle_text" msgid="4419667835599523257">"এপৰ হেণ্ডেল"</string> <string name="app_icon_text" msgid="2823268023931811747">"এপৰ চিহ্ন"</string> <string name="fullscreen_text" msgid="1162316685217676079">"সম্পূৰ্ণ স্ক্ৰীন"</string> <string name="desktop_text" msgid="1077633567027630454">"ডেস্কটপ ম’ড"</string> diff --git a/libs/WindowManager/Shell/res/values-az/strings.xml b/libs/WindowManager/Shell/res/values-az/strings.xml index 9ec44a1e6325..32e0dd698571 100644 --- a/libs/WindowManager/Shell/res/values-az/strings.xml +++ b/libs/WindowManager/Shell/res/values-az/strings.xml @@ -107,7 +107,7 @@ <string name="minimize_button_text" msgid="271592547935841753">"Kiçildin"</string> <string name="close_button_text" msgid="2913281996024033299">"Bağlayın"</string> <string name="back_button_text" msgid="1469718707134137085">"Geriyə"</string> - <string name="handle_text" msgid="1766582106752184456">"Hər kəsə açıq istifadəçi adı"</string> + <string name="handle_text" msgid="4419667835599523257">"Tətbiq ləqəbi"</string> <string name="app_icon_text" msgid="2823268023931811747">"Tətbiq ikonası"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Tam Ekran"</string> <string name="desktop_text" msgid="1077633567027630454">"Masaüstü Rejimi"</string> diff --git a/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml b/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml index af695e73161d..1656e02b476a 100644 --- a/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml +++ b/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml @@ -107,7 +107,7 @@ <string name="minimize_button_text" msgid="271592547935841753">"Umanjite"</string> <string name="close_button_text" msgid="2913281996024033299">"Zatvorite"</string> <string name="back_button_text" msgid="1469718707134137085">"Nazad"</string> - <string name="handle_text" msgid="1766582106752184456">"Identifikator"</string> + <string name="handle_text" msgid="4419667835599523257">"Identifikator aplikacije"</string> <string name="app_icon_text" msgid="2823268023931811747">"Ikona aplikacije"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Preko celog ekrana"</string> <string name="desktop_text" msgid="1077633567027630454">"Režim za računare"</string> diff --git a/libs/WindowManager/Shell/res/values-be/strings.xml b/libs/WindowManager/Shell/res/values-be/strings.xml index dbbc07fe2407..26f3d3ce85e3 100644 --- a/libs/WindowManager/Shell/res/values-be/strings.xml +++ b/libs/WindowManager/Shell/res/values-be/strings.xml @@ -107,7 +107,7 @@ <string name="minimize_button_text" msgid="271592547935841753">"Згарнуць"</string> <string name="close_button_text" msgid="2913281996024033299">"Закрыць"</string> <string name="back_button_text" msgid="1469718707134137085">"Назад"</string> - <string name="handle_text" msgid="1766582106752184456">"Маркер"</string> + <string name="handle_text" msgid="4419667835599523257">"Маркер праграмы"</string> <string name="app_icon_text" msgid="2823268023931811747">"Значок праграмы"</string> <string name="fullscreen_text" msgid="1162316685217676079">"На ўвесь экран"</string> <string name="desktop_text" msgid="1077633567027630454">"Рэжым працоўнага стала"</string> diff --git a/libs/WindowManager/Shell/res/values-bg/strings.xml b/libs/WindowManager/Shell/res/values-bg/strings.xml index 8dc791501b1b..7c4f25efb7e3 100644 --- a/libs/WindowManager/Shell/res/values-bg/strings.xml +++ b/libs/WindowManager/Shell/res/values-bg/strings.xml @@ -107,7 +107,7 @@ <string name="minimize_button_text" msgid="271592547935841753">"Намаляване"</string> <string name="close_button_text" msgid="2913281996024033299">"Затваряне"</string> <string name="back_button_text" msgid="1469718707134137085">"Назад"</string> - <string name="handle_text" msgid="1766582106752184456">"Манипулатор"</string> + <string name="handle_text" msgid="4419667835599523257">"Манипулатор за приложението"</string> <string name="app_icon_text" msgid="2823268023931811747">"Икона на приложението"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Цял екран"</string> <string name="desktop_text" msgid="1077633567027630454">"Режим за настолни компютри"</string> diff --git a/libs/WindowManager/Shell/res/values-bn/strings.xml b/libs/WindowManager/Shell/res/values-bn/strings.xml index 61294ada298e..4286162c0c87 100644 --- a/libs/WindowManager/Shell/res/values-bn/strings.xml +++ b/libs/WindowManager/Shell/res/values-bn/strings.xml @@ -107,7 +107,7 @@ <string name="minimize_button_text" msgid="271592547935841753">"ছোট করুন"</string> <string name="close_button_text" msgid="2913281996024033299">"বন্ধ করুন"</string> <string name="back_button_text" msgid="1469718707134137085">"ফিরে যান"</string> - <string name="handle_text" msgid="1766582106752184456">"হাতল"</string> + <string name="handle_text" msgid="4419667835599523257">"অ্যাপের হ্যান্ডেল"</string> <string name="app_icon_text" msgid="2823268023931811747">"অ্যাপ আইকন"</string> <string name="fullscreen_text" msgid="1162316685217676079">"ফুলস্ক্রিন"</string> <string name="desktop_text" msgid="1077633567027630454">"ডেস্কটপ মোড"</string> diff --git a/libs/WindowManager/Shell/res/values-bs/strings.xml b/libs/WindowManager/Shell/res/values-bs/strings.xml index 676b226ec8c1..11f5e480f7db 100644 --- a/libs/WindowManager/Shell/res/values-bs/strings.xml +++ b/libs/WindowManager/Shell/res/values-bs/strings.xml @@ -107,7 +107,7 @@ <string name="minimize_button_text" msgid="271592547935841753">"Minimiziranje"</string> <string name="close_button_text" msgid="2913281996024033299">"Zatvaranje"</string> <string name="back_button_text" msgid="1469718707134137085">"Nazad"</string> - <string name="handle_text" msgid="1766582106752184456">"Identifikator"</string> + <string name="handle_text" msgid="4419667835599523257">"Ručica aplikacije"</string> <string name="app_icon_text" msgid="2823268023931811747">"Ikona aplikacije"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Cijeli ekran"</string> <string name="desktop_text" msgid="1077633567027630454">"Način rada radne površine"</string> diff --git a/libs/WindowManager/Shell/res/values-ca/strings.xml b/libs/WindowManager/Shell/res/values-ca/strings.xml index ce9f54798120..e1fc7d38a527 100644 --- a/libs/WindowManager/Shell/res/values-ca/strings.xml +++ b/libs/WindowManager/Shell/res/values-ca/strings.xml @@ -107,7 +107,7 @@ <string name="minimize_button_text" msgid="271592547935841753">"Minimitza"</string> <string name="close_button_text" msgid="2913281996024033299">"Tanca"</string> <string name="back_button_text" msgid="1469718707134137085">"Enrere"</string> - <string name="handle_text" msgid="1766582106752184456">"Ansa"</string> + <string name="handle_text" msgid="4419667835599523257">"Identificador de l\'aplicació"</string> <string name="app_icon_text" msgid="2823268023931811747">"Icona de l\'aplicació"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Pantalla completa"</string> <string name="desktop_text" msgid="1077633567027630454">"Mode d\'escriptori"</string> diff --git a/libs/WindowManager/Shell/res/values-cs/strings.xml b/libs/WindowManager/Shell/res/values-cs/strings.xml index 6b9d85f37f00..e4282105455e 100644 --- a/libs/WindowManager/Shell/res/values-cs/strings.xml +++ b/libs/WindowManager/Shell/res/values-cs/strings.xml @@ -107,7 +107,7 @@ <string name="minimize_button_text" msgid="271592547935841753">"Minimalizovat"</string> <string name="close_button_text" msgid="2913281996024033299">"Zavřít"</string> <string name="back_button_text" msgid="1469718707134137085">"Zpět"</string> - <string name="handle_text" msgid="1766582106752184456">"Úchyt"</string> + <string name="handle_text" msgid="4419667835599523257">"Popisovač aplikace"</string> <string name="app_icon_text" msgid="2823268023931811747">"Ikona aplikace"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Celá obrazovka"</string> <string name="desktop_text" msgid="1077633567027630454">"Režim počítače"</string> diff --git a/libs/WindowManager/Shell/res/values-da/strings.xml b/libs/WindowManager/Shell/res/values-da/strings.xml index de7d91943a4d..36c03304a670 100644 --- a/libs/WindowManager/Shell/res/values-da/strings.xml +++ b/libs/WindowManager/Shell/res/values-da/strings.xml @@ -107,7 +107,7 @@ <string name="minimize_button_text" msgid="271592547935841753">"Minimer"</string> <string name="close_button_text" msgid="2913281996024033299">"Luk"</string> <string name="back_button_text" msgid="1469718707134137085">"Tilbage"</string> - <string name="handle_text" msgid="1766582106752184456">"Håndtag"</string> + <string name="handle_text" msgid="4419667835599523257">"Apphåndtag"</string> <string name="app_icon_text" msgid="2823268023931811747">"Appikon"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Fuld skærm"</string> <string name="desktop_text" msgid="1077633567027630454">"Computertilstand"</string> diff --git a/libs/WindowManager/Shell/res/values-de/strings.xml b/libs/WindowManager/Shell/res/values-de/strings.xml index e4fd3118293f..0ad112cf87a7 100644 --- a/libs/WindowManager/Shell/res/values-de/strings.xml +++ b/libs/WindowManager/Shell/res/values-de/strings.xml @@ -107,7 +107,7 @@ <string name="minimize_button_text" msgid="271592547935841753">"Minimieren"</string> <string name="close_button_text" msgid="2913281996024033299">"Schließen"</string> <string name="back_button_text" msgid="1469718707134137085">"Zurück"</string> - <string name="handle_text" msgid="1766582106752184456">"Ziehpunkt"</string> + <string name="handle_text" msgid="4419667835599523257">"App-Ziehpunkt"</string> <string name="app_icon_text" msgid="2823268023931811747">"App-Symbol"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Vollbild"</string> <string name="desktop_text" msgid="1077633567027630454">"Desktopmodus"</string> diff --git a/libs/WindowManager/Shell/res/values-el/strings.xml b/libs/WindowManager/Shell/res/values-el/strings.xml index 964166e16034..1e2fec19c639 100644 --- a/libs/WindowManager/Shell/res/values-el/strings.xml +++ b/libs/WindowManager/Shell/res/values-el/strings.xml @@ -107,7 +107,7 @@ <string name="minimize_button_text" msgid="271592547935841753">"Ελαχιστοποίηση"</string> <string name="close_button_text" msgid="2913281996024033299">"Κλείσιμο"</string> <string name="back_button_text" msgid="1469718707134137085">"Πίσω"</string> - <string name="handle_text" msgid="1766582106752184456">"Λαβή"</string> + <string name="handle_text" msgid="4419667835599523257">"Λαβή εφαρμογής"</string> <string name="app_icon_text" msgid="2823268023931811747">"Εικονίδιο εφαρμογής"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Πλήρης οθόνη"</string> <string name="desktop_text" msgid="1077633567027630454">"Λειτουργία επιφάνειας εργασίας"</string> diff --git a/libs/WindowManager/Shell/res/values-en-rAU/strings.xml b/libs/WindowManager/Shell/res/values-en-rAU/strings.xml index c17b9f7ad8dc..71701c9a18a1 100644 --- a/libs/WindowManager/Shell/res/values-en-rAU/strings.xml +++ b/libs/WindowManager/Shell/res/values-en-rAU/strings.xml @@ -107,7 +107,7 @@ <string name="minimize_button_text" msgid="271592547935841753">"Minimise"</string> <string name="close_button_text" msgid="2913281996024033299">"Close"</string> <string name="back_button_text" msgid="1469718707134137085">"Back"</string> - <string name="handle_text" msgid="1766582106752184456">"Handle"</string> + <string name="handle_text" msgid="4419667835599523257">"App handle"</string> <string name="app_icon_text" msgid="2823268023931811747">"App icon"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Full screen"</string> <string name="desktop_text" msgid="1077633567027630454">"Desktop mode"</string> diff --git a/libs/WindowManager/Shell/res/values-en-rCA/strings.xml b/libs/WindowManager/Shell/res/values-en-rCA/strings.xml index bd8a63690ba3..5ab4af3d1557 100644 --- a/libs/WindowManager/Shell/res/values-en-rCA/strings.xml +++ b/libs/WindowManager/Shell/res/values-en-rCA/strings.xml @@ -107,7 +107,7 @@ <string name="minimize_button_text" msgid="271592547935841753">"Minimize"</string> <string name="close_button_text" msgid="2913281996024033299">"Close"</string> <string name="back_button_text" msgid="1469718707134137085">"Back"</string> - <string name="handle_text" msgid="1766582106752184456">"Handle"</string> + <string name="handle_text" msgid="4419667835599523257">"App handle"</string> <string name="app_icon_text" msgid="2823268023931811747">"App Icon"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Fullscreen"</string> <string name="desktop_text" msgid="1077633567027630454">"Desktop Mode"</string> diff --git a/libs/WindowManager/Shell/res/values-en-rGB/strings.xml b/libs/WindowManager/Shell/res/values-en-rGB/strings.xml index c17b9f7ad8dc..71701c9a18a1 100644 --- a/libs/WindowManager/Shell/res/values-en-rGB/strings.xml +++ b/libs/WindowManager/Shell/res/values-en-rGB/strings.xml @@ -107,7 +107,7 @@ <string name="minimize_button_text" msgid="271592547935841753">"Minimise"</string> <string name="close_button_text" msgid="2913281996024033299">"Close"</string> <string name="back_button_text" msgid="1469718707134137085">"Back"</string> - <string name="handle_text" msgid="1766582106752184456">"Handle"</string> + <string name="handle_text" msgid="4419667835599523257">"App handle"</string> <string name="app_icon_text" msgid="2823268023931811747">"App icon"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Full screen"</string> <string name="desktop_text" msgid="1077633567027630454">"Desktop mode"</string> diff --git a/libs/WindowManager/Shell/res/values-en-rIN/strings.xml b/libs/WindowManager/Shell/res/values-en-rIN/strings.xml index c17b9f7ad8dc..71701c9a18a1 100644 --- a/libs/WindowManager/Shell/res/values-en-rIN/strings.xml +++ b/libs/WindowManager/Shell/res/values-en-rIN/strings.xml @@ -107,7 +107,7 @@ <string name="minimize_button_text" msgid="271592547935841753">"Minimise"</string> <string name="close_button_text" msgid="2913281996024033299">"Close"</string> <string name="back_button_text" msgid="1469718707134137085">"Back"</string> - <string name="handle_text" msgid="1766582106752184456">"Handle"</string> + <string name="handle_text" msgid="4419667835599523257">"App handle"</string> <string name="app_icon_text" msgid="2823268023931811747">"App icon"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Full screen"</string> <string name="desktop_text" msgid="1077633567027630454">"Desktop mode"</string> diff --git a/libs/WindowManager/Shell/res/values-en-rXC/strings.xml b/libs/WindowManager/Shell/res/values-en-rXC/strings.xml index 35030808f4fd..42d5f068927b 100644 --- a/libs/WindowManager/Shell/res/values-en-rXC/strings.xml +++ b/libs/WindowManager/Shell/res/values-en-rXC/strings.xml @@ -107,7 +107,7 @@ <string name="minimize_button_text" msgid="271592547935841753">"Minimize"</string> <string name="close_button_text" msgid="2913281996024033299">"Close"</string> <string name="back_button_text" msgid="1469718707134137085">"Back"</string> - <string name="handle_text" msgid="1766582106752184456">"Handle"</string> + <string name="handle_text" msgid="4419667835599523257">"App handle"</string> <string name="app_icon_text" msgid="2823268023931811747">"App Icon"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Fullscreen"</string> <string name="desktop_text" msgid="1077633567027630454">"Desktop Mode"</string> diff --git a/libs/WindowManager/Shell/res/values-es-rUS/strings.xml b/libs/WindowManager/Shell/res/values-es-rUS/strings.xml index 049649f0c748..1e3091295460 100644 --- a/libs/WindowManager/Shell/res/values-es-rUS/strings.xml +++ b/libs/WindowManager/Shell/res/values-es-rUS/strings.xml @@ -107,7 +107,7 @@ <string name="minimize_button_text" msgid="271592547935841753">"Minimizar"</string> <string name="close_button_text" msgid="2913281996024033299">"Cerrar"</string> <string name="back_button_text" msgid="1469718707134137085">"Atrás"</string> - <string name="handle_text" msgid="1766582106752184456">"Controlador"</string> + <string name="handle_text" msgid="4419667835599523257">"Controlador de la app"</string> <string name="app_icon_text" msgid="2823268023931811747">"Ícono de la app"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Pantalla completa"</string> <string name="desktop_text" msgid="1077633567027630454">"Modo de escritorio"</string> diff --git a/libs/WindowManager/Shell/res/values-es/strings.xml b/libs/WindowManager/Shell/res/values-es/strings.xml index 77413186228d..312e2977b4c3 100644 --- a/libs/WindowManager/Shell/res/values-es/strings.xml +++ b/libs/WindowManager/Shell/res/values-es/strings.xml @@ -107,7 +107,7 @@ <string name="minimize_button_text" msgid="271592547935841753">"Minimizar"</string> <string name="close_button_text" msgid="2913281996024033299">"Cerrar"</string> <string name="back_button_text" msgid="1469718707134137085">"Atrás"</string> - <string name="handle_text" msgid="1766582106752184456">"Controlador"</string> + <string name="handle_text" msgid="4419667835599523257">"Controlador de la aplicación"</string> <string name="app_icon_text" msgid="2823268023931811747">"Icono de la aplicación"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Pantalla completa"</string> <string name="desktop_text" msgid="1077633567027630454">"Modo Escritorio"</string> diff --git a/libs/WindowManager/Shell/res/values-et/strings.xml b/libs/WindowManager/Shell/res/values-et/strings.xml index 29fc150fd229..5e4ef81c7795 100644 --- a/libs/WindowManager/Shell/res/values-et/strings.xml +++ b/libs/WindowManager/Shell/res/values-et/strings.xml @@ -107,7 +107,7 @@ <string name="minimize_button_text" msgid="271592547935841753">"Minimeeri"</string> <string name="close_button_text" msgid="2913281996024033299">"Sule"</string> <string name="back_button_text" msgid="1469718707134137085">"Tagasi"</string> - <string name="handle_text" msgid="1766582106752184456">"Käepide"</string> + <string name="handle_text" msgid="4419667835599523257">"Rakenduse element"</string> <string name="app_icon_text" msgid="2823268023931811747">"Rakenduse ikoon"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Täisekraan"</string> <string name="desktop_text" msgid="1077633567027630454">"Lauaarvuti režiim"</string> diff --git a/libs/WindowManager/Shell/res/values-eu/strings.xml b/libs/WindowManager/Shell/res/values-eu/strings.xml index 580f6e1cd875..40d67a2a9a9d 100644 --- a/libs/WindowManager/Shell/res/values-eu/strings.xml +++ b/libs/WindowManager/Shell/res/values-eu/strings.xml @@ -107,7 +107,7 @@ <string name="minimize_button_text" msgid="271592547935841753">"Minimizatu"</string> <string name="close_button_text" msgid="2913281996024033299">"Itxi"</string> <string name="back_button_text" msgid="1469718707134137085">"Atzera"</string> - <string name="handle_text" msgid="1766582106752184456">"Kontu-izena"</string> + <string name="handle_text" msgid="4419667835599523257">"Aplikazioaren kontrol-puntua"</string> <string name="app_icon_text" msgid="2823268023931811747">"Aplikazioaren ikonoa"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Pantaila osoa"</string> <string name="desktop_text" msgid="1077633567027630454">"Ordenagailuetarako modua"</string> diff --git a/libs/WindowManager/Shell/res/values-fa/strings.xml b/libs/WindowManager/Shell/res/values-fa/strings.xml index 766e78734fbc..55da319031e3 100644 --- a/libs/WindowManager/Shell/res/values-fa/strings.xml +++ b/libs/WindowManager/Shell/res/values-fa/strings.xml @@ -107,7 +107,7 @@ <string name="minimize_button_text" msgid="271592547935841753">"کوچک کردن"</string> <string name="close_button_text" msgid="2913281996024033299">"بستن"</string> <string name="back_button_text" msgid="1469718707134137085">"برگشتن"</string> - <string name="handle_text" msgid="1766582106752184456">"دستگیره"</string> + <string name="handle_text" msgid="4419667835599523257">"دستگیره برنامه"</string> <string name="app_icon_text" msgid="2823268023931811747">"نماد برنامه"</string> <string name="fullscreen_text" msgid="1162316685217676079">"تمامصفحه"</string> <string name="desktop_text" msgid="1077633567027630454">"حالت رایانه"</string> diff --git a/libs/WindowManager/Shell/res/values-fi/strings.xml b/libs/WindowManager/Shell/res/values-fi/strings.xml index 96c7b7504724..c2610ff182f2 100644 --- a/libs/WindowManager/Shell/res/values-fi/strings.xml +++ b/libs/WindowManager/Shell/res/values-fi/strings.xml @@ -107,7 +107,7 @@ <string name="minimize_button_text" msgid="271592547935841753">"Pienennä"</string> <string name="close_button_text" msgid="2913281996024033299">"Sulje"</string> <string name="back_button_text" msgid="1469718707134137085">"Takaisin"</string> - <string name="handle_text" msgid="1766582106752184456">"Kahva"</string> + <string name="handle_text" msgid="4419667835599523257">"Sovelluksen tunnus"</string> <string name="app_icon_text" msgid="2823268023931811747">"Sovelluskuvake"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Koko näyttö"</string> <string name="desktop_text" msgid="1077633567027630454">"Työpöytätila"</string> diff --git a/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml b/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml index e54e59d279fd..7a59b62812b9 100644 --- a/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml +++ b/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml @@ -107,7 +107,7 @@ <string name="minimize_button_text" msgid="271592547935841753">"Réduire"</string> <string name="close_button_text" msgid="2913281996024033299">"Fermer"</string> <string name="back_button_text" msgid="1469718707134137085">"Retour"</string> - <string name="handle_text" msgid="1766582106752184456">"Identifiant"</string> + <string name="handle_text" msgid="4419667835599523257">"Poignée de l\'appli"</string> <string name="app_icon_text" msgid="2823268023931811747">"Icône de l\'appli"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Plein écran"</string> <string name="desktop_text" msgid="1077633567027630454">"Mode Bureau"</string> diff --git a/libs/WindowManager/Shell/res/values-fr/strings.xml b/libs/WindowManager/Shell/res/values-fr/strings.xml index d150ad7e89f5..0cf944fca1e6 100644 --- a/libs/WindowManager/Shell/res/values-fr/strings.xml +++ b/libs/WindowManager/Shell/res/values-fr/strings.xml @@ -107,7 +107,7 @@ <string name="minimize_button_text" msgid="271592547935841753">"Réduire"</string> <string name="close_button_text" msgid="2913281996024033299">"Fermer"</string> <string name="back_button_text" msgid="1469718707134137085">"Retour"</string> - <string name="handle_text" msgid="1766582106752184456">"Poignée"</string> + <string name="handle_text" msgid="4419667835599523257">"Poignée de l\'appli"</string> <string name="app_icon_text" msgid="2823268023931811747">"Icône d\'application"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Plein écran"</string> <string name="desktop_text" msgid="1077633567027630454">"Mode ordinateur"</string> diff --git a/libs/WindowManager/Shell/res/values-gl/strings.xml b/libs/WindowManager/Shell/res/values-gl/strings.xml index 6429fb31acd7..0f2a6010c860 100644 --- a/libs/WindowManager/Shell/res/values-gl/strings.xml +++ b/libs/WindowManager/Shell/res/values-gl/strings.xml @@ -107,7 +107,7 @@ <string name="minimize_button_text" msgid="271592547935841753">"Minimizar"</string> <string name="close_button_text" msgid="2913281996024033299">"Pechar"</string> <string name="back_button_text" msgid="1469718707134137085">"Atrás"</string> - <string name="handle_text" msgid="1766582106752184456">"Controlador"</string> + <string name="handle_text" msgid="4419667835599523257">"Controlador da aplicación"</string> <string name="app_icon_text" msgid="2823268023931811747">"Icona de aplicación"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Pantalla completa"</string> <string name="desktop_text" msgid="1077633567027630454">"Modo de escritorio"</string> diff --git a/libs/WindowManager/Shell/res/values-gu/strings.xml b/libs/WindowManager/Shell/res/values-gu/strings.xml index f8bdfaeccc15..6151da03797c 100644 --- a/libs/WindowManager/Shell/res/values-gu/strings.xml +++ b/libs/WindowManager/Shell/res/values-gu/strings.xml @@ -107,7 +107,7 @@ <string name="minimize_button_text" msgid="271592547935841753">"નાનું કરો"</string> <string name="close_button_text" msgid="2913281996024033299">"બંધ કરો"</string> <string name="back_button_text" msgid="1469718707134137085">"પાછળ"</string> - <string name="handle_text" msgid="1766582106752184456">"હૅન્ડલ"</string> + <string name="handle_text" msgid="4419667835599523257">"ઍપનું હૅન્ડલ"</string> <string name="app_icon_text" msgid="2823268023931811747">"ઍપનું આઇકન"</string> <string name="fullscreen_text" msgid="1162316685217676079">"પૂર્ણસ્ક્રીન"</string> <string name="desktop_text" msgid="1077633567027630454">"ડેસ્કટૉપ મોડ"</string> diff --git a/libs/WindowManager/Shell/res/values-hi/strings.xml b/libs/WindowManager/Shell/res/values-hi/strings.xml index d7c380387509..04e76bc5bed3 100644 --- a/libs/WindowManager/Shell/res/values-hi/strings.xml +++ b/libs/WindowManager/Shell/res/values-hi/strings.xml @@ -107,7 +107,7 @@ <string name="minimize_button_text" msgid="271592547935841753">"विंडो छोटी करें"</string> <string name="close_button_text" msgid="2913281996024033299">"बंद करें"</string> <string name="back_button_text" msgid="1469718707134137085">"वापस जाएं"</string> - <string name="handle_text" msgid="1766582106752184456">"हैंडल"</string> + <string name="handle_text" msgid="4419667835599523257">"ऐप्लिकेशन का हैंडल"</string> <string name="app_icon_text" msgid="2823268023931811747">"ऐप्लिकेशन आइकॉन"</string> <string name="fullscreen_text" msgid="1162316685217676079">"फ़ुलस्क्रीन"</string> <string name="desktop_text" msgid="1077633567027630454">"डेस्कटॉप मोड"</string> diff --git a/libs/WindowManager/Shell/res/values-hr/strings.xml b/libs/WindowManager/Shell/res/values-hr/strings.xml index 000b0e63bf8e..aa2ee17a157f 100644 --- a/libs/WindowManager/Shell/res/values-hr/strings.xml +++ b/libs/WindowManager/Shell/res/values-hr/strings.xml @@ -107,7 +107,7 @@ <string name="minimize_button_text" msgid="271592547935841753">"Minimiziraj"</string> <string name="close_button_text" msgid="2913281996024033299">"Zatvori"</string> <string name="back_button_text" msgid="1469718707134137085">"Natrag"</string> - <string name="handle_text" msgid="1766582106752184456">"Pokazivač"</string> + <string name="handle_text" msgid="4419667835599523257">"Pokazivač aplikacije"</string> <string name="app_icon_text" msgid="2823268023931811747">"Ikona aplikacije"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Puni zaslon"</string> <string name="desktop_text" msgid="1077633567027630454">"Stolni način rada"</string> diff --git a/libs/WindowManager/Shell/res/values-hu/strings.xml b/libs/WindowManager/Shell/res/values-hu/strings.xml index b1268cc849ab..8ffeeed1b1f3 100644 --- a/libs/WindowManager/Shell/res/values-hu/strings.xml +++ b/libs/WindowManager/Shell/res/values-hu/strings.xml @@ -107,7 +107,7 @@ <string name="minimize_button_text" msgid="271592547935841753">"Kis méret"</string> <string name="close_button_text" msgid="2913281996024033299">"Bezárás"</string> <string name="back_button_text" msgid="1469718707134137085">"Vissza"</string> - <string name="handle_text" msgid="1766582106752184456">"Fogópont"</string> + <string name="handle_text" msgid="4419667835599523257">"App fogópontja"</string> <string name="app_icon_text" msgid="2823268023931811747">"Alkalmazásikon"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Teljes képernyő"</string> <string name="desktop_text" msgid="1077633567027630454">"Asztali üzemmód"</string> diff --git a/libs/WindowManager/Shell/res/values-hy/strings.xml b/libs/WindowManager/Shell/res/values-hy/strings.xml index 1d2d2ff76912..b3fccfaa93f1 100644 --- a/libs/WindowManager/Shell/res/values-hy/strings.xml +++ b/libs/WindowManager/Shell/res/values-hy/strings.xml @@ -107,7 +107,7 @@ <string name="minimize_button_text" msgid="271592547935841753">"Ծալել"</string> <string name="close_button_text" msgid="2913281996024033299">"Փակել"</string> <string name="back_button_text" msgid="1469718707134137085">"Հետ"</string> - <string name="handle_text" msgid="1766582106752184456">"Նշիչ"</string> + <string name="handle_text" msgid="4419667835599523257">"Հավելվածի կեղծանուն"</string> <string name="app_icon_text" msgid="2823268023931811747">"Հավելվածի պատկերակ"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Լիաէկրան"</string> <string name="desktop_text" msgid="1077633567027630454">"Համակարգչի ռեժիմ"</string> diff --git a/libs/WindowManager/Shell/res/values-in/strings.xml b/libs/WindowManager/Shell/res/values-in/strings.xml index 17e91050584d..38b24f92b76d 100644 --- a/libs/WindowManager/Shell/res/values-in/strings.xml +++ b/libs/WindowManager/Shell/res/values-in/strings.xml @@ -107,7 +107,7 @@ <string name="minimize_button_text" msgid="271592547935841753">"Minimalkan"</string> <string name="close_button_text" msgid="2913281996024033299">"Tutup"</string> <string name="back_button_text" msgid="1469718707134137085">"Kembali"</string> - <string name="handle_text" msgid="1766582106752184456">"Tuas"</string> + <string name="handle_text" msgid="4419667835599523257">"Penanganan aplikasi"</string> <string name="app_icon_text" msgid="2823268023931811747">"Ikon Aplikasi"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Layar Penuh"</string> <string name="desktop_text" msgid="1077633567027630454">"Mode Desktop"</string> diff --git a/libs/WindowManager/Shell/res/values-is/strings.xml b/libs/WindowManager/Shell/res/values-is/strings.xml index b955ef89759f..5b1f4d2205f7 100644 --- a/libs/WindowManager/Shell/res/values-is/strings.xml +++ b/libs/WindowManager/Shell/res/values-is/strings.xml @@ -107,7 +107,7 @@ <string name="minimize_button_text" msgid="271592547935841753">"Minnka"</string> <string name="close_button_text" msgid="2913281996024033299">"Loka"</string> <string name="back_button_text" msgid="1469718707134137085">"Til baka"</string> - <string name="handle_text" msgid="1766582106752184456">"Handfang"</string> + <string name="handle_text" msgid="4419667835599523257">"Handfang forrits"</string> <string name="app_icon_text" msgid="2823268023931811747">"Tákn forrits"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Allur skjárinn"</string> <string name="desktop_text" msgid="1077633567027630454">"Skjáborðsstilling"</string> diff --git a/libs/WindowManager/Shell/res/values-it/strings.xml b/libs/WindowManager/Shell/res/values-it/strings.xml index d33e770f8199..adc9569b0afe 100644 --- a/libs/WindowManager/Shell/res/values-it/strings.xml +++ b/libs/WindowManager/Shell/res/values-it/strings.xml @@ -107,7 +107,7 @@ <string name="minimize_button_text" msgid="271592547935841753">"Riduci a icona"</string> <string name="close_button_text" msgid="2913281996024033299">"Chiudi"</string> <string name="back_button_text" msgid="1469718707134137085">"Indietro"</string> - <string name="handle_text" msgid="1766582106752184456">"Handle"</string> + <string name="handle_text" msgid="4419667835599523257">"Punto di manipolazione app"</string> <string name="app_icon_text" msgid="2823268023931811747">"Icona dell\'app"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Schermo intero"</string> <string name="desktop_text" msgid="1077633567027630454">"Modalità desktop"</string> diff --git a/libs/WindowManager/Shell/res/values-iw/strings.xml b/libs/WindowManager/Shell/res/values-iw/strings.xml index 6ebbc81046bf..9bae1c970b97 100644 --- a/libs/WindowManager/Shell/res/values-iw/strings.xml +++ b/libs/WindowManager/Shell/res/values-iw/strings.xml @@ -107,7 +107,7 @@ <string name="minimize_button_text" msgid="271592547935841753">"מזעור"</string> <string name="close_button_text" msgid="2913281996024033299">"סגירה"</string> <string name="back_button_text" msgid="1469718707134137085">"חזרה"</string> - <string name="handle_text" msgid="1766582106752184456">"נקודת אחיזה"</string> + <string name="handle_text" msgid="4419667835599523257">"נקודת אחיזה לאפליקציה"</string> <string name="app_icon_text" msgid="2823268023931811747">"סמל האפליקציה"</string> <string name="fullscreen_text" msgid="1162316685217676079">"מסך מלא"</string> <string name="desktop_text" msgid="1077633567027630454">"ממשק המחשב"</string> diff --git a/libs/WindowManager/Shell/res/values-ja/strings.xml b/libs/WindowManager/Shell/res/values-ja/strings.xml index 55fd8b16f2a2..fff794eda59b 100644 --- a/libs/WindowManager/Shell/res/values-ja/strings.xml +++ b/libs/WindowManager/Shell/res/values-ja/strings.xml @@ -107,7 +107,7 @@ <string name="minimize_button_text" msgid="271592547935841753">"最小化"</string> <string name="close_button_text" msgid="2913281996024033299">"閉じる"</string> <string name="back_button_text" msgid="1469718707134137085">"戻る"</string> - <string name="handle_text" msgid="1766582106752184456">"ハンドル"</string> + <string name="handle_text" msgid="4419667835599523257">"アプリハンドル"</string> <string name="app_icon_text" msgid="2823268023931811747">"アプリのアイコン"</string> <string name="fullscreen_text" msgid="1162316685217676079">"全画面表示"</string> <string name="desktop_text" msgid="1077633567027630454">"デスクトップ モード"</string> diff --git a/libs/WindowManager/Shell/res/values-ka/strings.xml b/libs/WindowManager/Shell/res/values-ka/strings.xml index 235420812937..a73c4f0f9cff 100644 --- a/libs/WindowManager/Shell/res/values-ka/strings.xml +++ b/libs/WindowManager/Shell/res/values-ka/strings.xml @@ -107,7 +107,7 @@ <string name="minimize_button_text" msgid="271592547935841753">"ჩაკეცვა"</string> <string name="close_button_text" msgid="2913281996024033299">"დახურვა"</string> <string name="back_button_text" msgid="1469718707134137085">"უკან"</string> - <string name="handle_text" msgid="1766582106752184456">"იდენტიფიკატორი"</string> + <string name="handle_text" msgid="4419667835599523257">"აპის იდენტიფიკატორი"</string> <string name="app_icon_text" msgid="2823268023931811747">"აპის ხატულა"</string> <string name="fullscreen_text" msgid="1162316685217676079">"სრულ ეკრანზე"</string> <string name="desktop_text" msgid="1077633567027630454">"დესკტოპის რეჟიმი"</string> diff --git a/libs/WindowManager/Shell/res/values-kk/strings.xml b/libs/WindowManager/Shell/res/values-kk/strings.xml index 3e9b85ecd3a3..5a7197e08942 100644 --- a/libs/WindowManager/Shell/res/values-kk/strings.xml +++ b/libs/WindowManager/Shell/res/values-kk/strings.xml @@ -107,7 +107,7 @@ <string name="minimize_button_text" msgid="271592547935841753">"Кішірейту"</string> <string name="close_button_text" msgid="2913281996024033299">"Жабу"</string> <string name="back_button_text" msgid="1469718707134137085">"Артқа"</string> - <string name="handle_text" msgid="1766582106752184456">"Идентификатор"</string> + <string name="handle_text" msgid="4419667835599523257">"Қолданба идентификаторы"</string> <string name="app_icon_text" msgid="2823268023931811747">"Қолданба белгішесі"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Толық экран"</string> <string name="desktop_text" msgid="1077633567027630454">"Компьютер режимі"</string> diff --git a/libs/WindowManager/Shell/res/values-km/strings.xml b/libs/WindowManager/Shell/res/values-km/strings.xml index 69c0e1eabc05..4db7aeaae457 100644 --- a/libs/WindowManager/Shell/res/values-km/strings.xml +++ b/libs/WindowManager/Shell/res/values-km/strings.xml @@ -107,7 +107,7 @@ <string name="minimize_button_text" msgid="271592547935841753">"បង្រួម"</string> <string name="close_button_text" msgid="2913281996024033299">"បិទ"</string> <string name="back_button_text" msgid="1469718707134137085">"ថយក្រោយ"</string> - <string name="handle_text" msgid="1766582106752184456">"ឈ្មោះអ្នកប្រើប្រាស់"</string> + <string name="handle_text" msgid="4419667835599523257">"ឈ្មោះអ្នកប្រើប្រាស់កម្មវិធី"</string> <string name="app_icon_text" msgid="2823268023931811747">"រូបកម្មវិធី"</string> <string name="fullscreen_text" msgid="1162316685217676079">"អេក្រង់ពេញ"</string> <string name="desktop_text" msgid="1077633567027630454">"មុខងារកុំព្យូទ័រ"</string> diff --git a/libs/WindowManager/Shell/res/values-kn/strings.xml b/libs/WindowManager/Shell/res/values-kn/strings.xml index 88a29df525e9..5615afcf55f8 100644 --- a/libs/WindowManager/Shell/res/values-kn/strings.xml +++ b/libs/WindowManager/Shell/res/values-kn/strings.xml @@ -107,7 +107,7 @@ <string name="minimize_button_text" msgid="271592547935841753">"ಕುಗ್ಗಿಸಿ"</string> <string name="close_button_text" msgid="2913281996024033299">"ಮುಚ್ಚಿರಿ"</string> <string name="back_button_text" msgid="1469718707134137085">"ಹಿಂದಕ್ಕೆ"</string> - <string name="handle_text" msgid="1766582106752184456">"ಹ್ಯಾಂಡಲ್"</string> + <string name="handle_text" msgid="4419667835599523257">"ಆ್ಯಪ್ ಹ್ಯಾಂಡಲ್"</string> <string name="app_icon_text" msgid="2823268023931811747">"ಆ್ಯಪ್ ಐಕಾನ್"</string> <string name="fullscreen_text" msgid="1162316685217676079">"ಫುಲ್ಸ್ಕ್ರೀನ್"</string> <string name="desktop_text" msgid="1077633567027630454">"ಡೆಸ್ಕ್ಟಾಪ್ ಮೋಡ್"</string> diff --git a/libs/WindowManager/Shell/res/values-ko/strings.xml b/libs/WindowManager/Shell/res/values-ko/strings.xml index 0f27080d65cd..33b980d40a6c 100644 --- a/libs/WindowManager/Shell/res/values-ko/strings.xml +++ b/libs/WindowManager/Shell/res/values-ko/strings.xml @@ -107,7 +107,7 @@ <string name="minimize_button_text" msgid="271592547935841753">"최소화"</string> <string name="close_button_text" msgid="2913281996024033299">"닫기"</string> <string name="back_button_text" msgid="1469718707134137085">"뒤로"</string> - <string name="handle_text" msgid="1766582106752184456">"핸들"</string> + <string name="handle_text" msgid="4419667835599523257">"앱 핸들"</string> <string name="app_icon_text" msgid="2823268023931811747">"앱 아이콘"</string> <string name="fullscreen_text" msgid="1162316685217676079">"전체 화면"</string> <string name="desktop_text" msgid="1077633567027630454">"데스크톱 모드"</string> diff --git a/libs/WindowManager/Shell/res/values-ky/strings.xml b/libs/WindowManager/Shell/res/values-ky/strings.xml index 289d930ecedd..bf3ca5255a80 100644 --- a/libs/WindowManager/Shell/res/values-ky/strings.xml +++ b/libs/WindowManager/Shell/res/values-ky/strings.xml @@ -107,7 +107,7 @@ <string name="minimize_button_text" msgid="271592547935841753">"Кичирейтүү"</string> <string name="close_button_text" msgid="2913281996024033299">"Жабуу"</string> <string name="back_button_text" msgid="1469718707134137085">"Артка"</string> - <string name="handle_text" msgid="1766582106752184456">"Маркер"</string> + <string name="handle_text" msgid="4419667835599523257">"Колдонмонун маркери"</string> <string name="app_icon_text" msgid="2823268023931811747">"Колдонмонун сүрөтчөсү"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Толук экран"</string> <string name="desktop_text" msgid="1077633567027630454">"Компьютер режими"</string> diff --git a/libs/WindowManager/Shell/res/values-lo/strings.xml b/libs/WindowManager/Shell/res/values-lo/strings.xml index 0b84d2c45957..ac6fa0085785 100644 --- a/libs/WindowManager/Shell/res/values-lo/strings.xml +++ b/libs/WindowManager/Shell/res/values-lo/strings.xml @@ -107,7 +107,7 @@ <string name="minimize_button_text" msgid="271592547935841753">"ຫຍໍ້ລົງ"</string> <string name="close_button_text" msgid="2913281996024033299">"ປິດ"</string> <string name="back_button_text" msgid="1469718707134137085">"ກັບຄືນ"</string> - <string name="handle_text" msgid="1766582106752184456">"ມືບັງຄັບ"</string> + <string name="handle_text" msgid="4419667835599523257">"ຊື່ຜູ້ໃຊ້ແອັບ"</string> <string name="app_icon_text" msgid="2823268023931811747">"ໄອຄອນແອັບ"</string> <string name="fullscreen_text" msgid="1162316685217676079">"ເຕັມຈໍ"</string> <string name="desktop_text" msgid="1077633567027630454">"ໂໝດເດັສທັອບ"</string> diff --git a/libs/WindowManager/Shell/res/values-lt/strings.xml b/libs/WindowManager/Shell/res/values-lt/strings.xml index 21dbb68c8c04..97b53d343dd8 100644 --- a/libs/WindowManager/Shell/res/values-lt/strings.xml +++ b/libs/WindowManager/Shell/res/values-lt/strings.xml @@ -107,7 +107,7 @@ <string name="minimize_button_text" msgid="271592547935841753">"Sumažinti"</string> <string name="close_button_text" msgid="2913281996024033299">"Uždaryti"</string> <string name="back_button_text" msgid="1469718707134137085">"Atgal"</string> - <string name="handle_text" msgid="1766582106752184456">"Rankenėlė"</string> + <string name="handle_text" msgid="4419667835599523257">"Programos kreipinys"</string> <string name="app_icon_text" msgid="2823268023931811747">"Programos piktograma"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Visas ekranas"</string> <string name="desktop_text" msgid="1077633567027630454">"Stalinio kompiuterio režimas"</string> diff --git a/libs/WindowManager/Shell/res/values-lv/strings.xml b/libs/WindowManager/Shell/res/values-lv/strings.xml index f988c14605c4..3a7e90a9da21 100644 --- a/libs/WindowManager/Shell/res/values-lv/strings.xml +++ b/libs/WindowManager/Shell/res/values-lv/strings.xml @@ -107,7 +107,7 @@ <string name="minimize_button_text" msgid="271592547935841753">"Minimizēt"</string> <string name="close_button_text" msgid="2913281996024033299">"Aizvērt"</string> <string name="back_button_text" msgid="1469718707134137085">"Atpakaļ"</string> - <string name="handle_text" msgid="1766582106752184456">"Turis"</string> + <string name="handle_text" msgid="4419667835599523257">"Lietotnes turis"</string> <string name="app_icon_text" msgid="2823268023931811747">"Lietotnes ikona"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Pilnekrāna režīms"</string> <string name="desktop_text" msgid="1077633567027630454">"Darbvirsmas režīms"</string> diff --git a/libs/WindowManager/Shell/res/values-mk/strings.xml b/libs/WindowManager/Shell/res/values-mk/strings.xml index ce34b9749e80..f7867cecdfae 100644 --- a/libs/WindowManager/Shell/res/values-mk/strings.xml +++ b/libs/WindowManager/Shell/res/values-mk/strings.xml @@ -107,7 +107,7 @@ <string name="minimize_button_text" msgid="271592547935841753">"Минимизирај"</string> <string name="close_button_text" msgid="2913281996024033299">"Затвори"</string> <string name="back_button_text" msgid="1469718707134137085">"Назад"</string> - <string name="handle_text" msgid="1766582106752184456">"Прекар"</string> + <string name="handle_text" msgid="4419667835599523257">"Прекар на апликацијата"</string> <string name="app_icon_text" msgid="2823268023931811747">"Икона на апликацијата"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Цел екран"</string> <string name="desktop_text" msgid="1077633567027630454">"Режим за компјутер"</string> diff --git a/libs/WindowManager/Shell/res/values-ml/strings.xml b/libs/WindowManager/Shell/res/values-ml/strings.xml index 2efd983b3342..68ff07474778 100644 --- a/libs/WindowManager/Shell/res/values-ml/strings.xml +++ b/libs/WindowManager/Shell/res/values-ml/strings.xml @@ -107,7 +107,7 @@ <string name="minimize_button_text" msgid="271592547935841753">"ചെറുതാക്കുക"</string> <string name="close_button_text" msgid="2913281996024033299">"അടയ്ക്കുക"</string> <string name="back_button_text" msgid="1469718707134137085">"മടങ്ങുക"</string> - <string name="handle_text" msgid="1766582106752184456">"ഹാൻഡിൽ"</string> + <string name="handle_text" msgid="4419667835599523257">"ആപ്പ് ഹാൻഡിൽ"</string> <string name="app_icon_text" msgid="2823268023931811747">"ആപ്പ് ഐക്കൺ"</string> <string name="fullscreen_text" msgid="1162316685217676079">"പൂർണ്ണസ്ക്രീൻ"</string> <string name="desktop_text" msgid="1077633567027630454">"ഡെസ്ക്ടോപ്പ് മോഡ്"</string> diff --git a/libs/WindowManager/Shell/res/values-mn/strings.xml b/libs/WindowManager/Shell/res/values-mn/strings.xml index de58ed89864e..27b38bc283f9 100644 --- a/libs/WindowManager/Shell/res/values-mn/strings.xml +++ b/libs/WindowManager/Shell/res/values-mn/strings.xml @@ -107,7 +107,7 @@ <string name="minimize_button_text" msgid="271592547935841753">"Багасгах"</string> <string name="close_button_text" msgid="2913281996024033299">"Хаах"</string> <string name="back_button_text" msgid="1469718707134137085">"Буцах"</string> - <string name="handle_text" msgid="1766582106752184456">"Бариул"</string> + <string name="handle_text" msgid="4419667835599523257">"Аппын бариул"</string> <string name="app_icon_text" msgid="2823268023931811747">"Aппын дүрс тэмдэг"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Бүтэн дэлгэц"</string> <string name="desktop_text" msgid="1077633567027630454">"Дэлгэцийн горим"</string> diff --git a/libs/WindowManager/Shell/res/values-mr/strings.xml b/libs/WindowManager/Shell/res/values-mr/strings.xml index ef71e864a809..f57f06375be9 100644 --- a/libs/WindowManager/Shell/res/values-mr/strings.xml +++ b/libs/WindowManager/Shell/res/values-mr/strings.xml @@ -107,7 +107,7 @@ <string name="minimize_button_text" msgid="271592547935841753">"लहान करा"</string> <string name="close_button_text" msgid="2913281996024033299">"बंद करा"</string> <string name="back_button_text" msgid="1469718707134137085">"मागे जा"</string> - <string name="handle_text" msgid="1766582106752184456">"हँडल"</string> + <string name="handle_text" msgid="4419667835599523257">"अॅपचे हँडल"</string> <string name="app_icon_text" msgid="2823268023931811747">"अॅप आयकन"</string> <string name="fullscreen_text" msgid="1162316685217676079">"फुलस्क्रीन"</string> <string name="desktop_text" msgid="1077633567027630454">"डेस्कटॉप मोड"</string> diff --git a/libs/WindowManager/Shell/res/values-ms/strings.xml b/libs/WindowManager/Shell/res/values-ms/strings.xml index a9a97d8112c6..9c3b8716c7e6 100644 --- a/libs/WindowManager/Shell/res/values-ms/strings.xml +++ b/libs/WindowManager/Shell/res/values-ms/strings.xml @@ -107,7 +107,7 @@ <string name="minimize_button_text" msgid="271592547935841753">"Minimumkan"</string> <string name="close_button_text" msgid="2913281996024033299">"Tutup"</string> <string name="back_button_text" msgid="1469718707134137085">"Kembali"</string> - <string name="handle_text" msgid="1766582106752184456">"Pemegang"</string> + <string name="handle_text" msgid="4419667835599523257">"Pengendalian apl"</string> <string name="app_icon_text" msgid="2823268023931811747">"Ikon Apl"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Skrin penuh"</string> <string name="desktop_text" msgid="1077633567027630454">"Mod Desktop"</string> diff --git a/libs/WindowManager/Shell/res/values-my/strings.xml b/libs/WindowManager/Shell/res/values-my/strings.xml index 2f313cfe7e26..2685c56a246c 100644 --- a/libs/WindowManager/Shell/res/values-my/strings.xml +++ b/libs/WindowManager/Shell/res/values-my/strings.xml @@ -107,7 +107,7 @@ <string name="minimize_button_text" msgid="271592547935841753">"ချုံ့ရန်"</string> <string name="close_button_text" msgid="2913281996024033299">"ပိတ်ရန်"</string> <string name="back_button_text" msgid="1469718707134137085">"နောက်သို့"</string> - <string name="handle_text" msgid="1766582106752184456">"သုံးသူအမည်"</string> + <string name="handle_text" msgid="4419667835599523257">"အက်ပ်သုံးသူအမည်"</string> <string name="app_icon_text" msgid="2823268023931811747">"အက်ပ်သင်္ကေတ"</string> <string name="fullscreen_text" msgid="1162316685217676079">"ဖန်သားပြင်အပြည့်"</string> <string name="desktop_text" msgid="1077633567027630454">"ဒက်စ်တော့မုဒ်"</string> diff --git a/libs/WindowManager/Shell/res/values-nb/strings.xml b/libs/WindowManager/Shell/res/values-nb/strings.xml index 11a807b73054..36c0b8b9febd 100644 --- a/libs/WindowManager/Shell/res/values-nb/strings.xml +++ b/libs/WindowManager/Shell/res/values-nb/strings.xml @@ -107,7 +107,7 @@ <string name="minimize_button_text" msgid="271592547935841753">"Minimer"</string> <string name="close_button_text" msgid="2913281996024033299">"Lukk"</string> <string name="back_button_text" msgid="1469718707134137085">"Tilbake"</string> - <string name="handle_text" msgid="1766582106752184456">"Håndtak"</string> + <string name="handle_text" msgid="4419667835599523257">"Apphåndtak"</string> <string name="app_icon_text" msgid="2823268023931811747">"Appikon"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Fullskjerm"</string> <string name="desktop_text" msgid="1077633567027630454">"Skrivebordmodus"</string> diff --git a/libs/WindowManager/Shell/res/values-ne/strings.xml b/libs/WindowManager/Shell/res/values-ne/strings.xml index 7cc4a437905b..4e96f5f5a0fb 100644 --- a/libs/WindowManager/Shell/res/values-ne/strings.xml +++ b/libs/WindowManager/Shell/res/values-ne/strings.xml @@ -107,7 +107,7 @@ <string name="minimize_button_text" msgid="271592547935841753">"मिनिमाइज गर्नुहोस्"</string> <string name="close_button_text" msgid="2913281996024033299">"बन्द गर्नुहोस्"</string> <string name="back_button_text" msgid="1469718707134137085">"पछाडि"</string> - <string name="handle_text" msgid="1766582106752184456">"ह्यान्डल"</string> + <string name="handle_text" msgid="4419667835599523257">"एपको ह्यान्डल"</string> <string name="app_icon_text" msgid="2823268023931811747">"एपको आइकन"</string> <string name="fullscreen_text" msgid="1162316685217676079">"फुल स्क्रिन"</string> <string name="desktop_text" msgid="1077633567027630454">"डेस्कटप मोड"</string> diff --git a/libs/WindowManager/Shell/res/values-nl/strings.xml b/libs/WindowManager/Shell/res/values-nl/strings.xml index 7480add2ab0a..5ae084a7021a 100644 --- a/libs/WindowManager/Shell/res/values-nl/strings.xml +++ b/libs/WindowManager/Shell/res/values-nl/strings.xml @@ -107,7 +107,7 @@ <string name="minimize_button_text" msgid="271592547935841753">"Minimaliseren"</string> <string name="close_button_text" msgid="2913281996024033299">"Sluiten"</string> <string name="back_button_text" msgid="1469718707134137085">"Terug"</string> - <string name="handle_text" msgid="1766582106752184456">"Gebruikersnaam"</string> + <string name="handle_text" msgid="4419667835599523257">"App-handgreep"</string> <string name="app_icon_text" msgid="2823268023931811747">"App-icoon"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Volledig scherm"</string> <string name="desktop_text" msgid="1077633567027630454">"Desktopmodus"</string> diff --git a/libs/WindowManager/Shell/res/values-or/strings.xml b/libs/WindowManager/Shell/res/values-or/strings.xml index b3b5e7cd6955..536c6fe18f94 100644 --- a/libs/WindowManager/Shell/res/values-or/strings.xml +++ b/libs/WindowManager/Shell/res/values-or/strings.xml @@ -107,7 +107,7 @@ <string name="minimize_button_text" msgid="271592547935841753">"ଛୋଟ କରନ୍ତୁ"</string> <string name="close_button_text" msgid="2913281996024033299">"ବନ୍ଦ କରନ୍ତୁ"</string> <string name="back_button_text" msgid="1469718707134137085">"ପଛକୁ ଫେରନ୍ତୁ"</string> - <string name="handle_text" msgid="1766582106752184456">"ହେଣ୍ଡେଲ"</string> + <string name="handle_text" msgid="4419667835599523257">"ଆପର ହେଣ୍ଡେଲ"</string> <string name="app_icon_text" msgid="2823268023931811747">"ଆପ ଆଇକନ"</string> <string name="fullscreen_text" msgid="1162316685217676079">"ପୂର୍ଣ୍ଣସ୍କ୍ରିନ"</string> <string name="desktop_text" msgid="1077633567027630454">"ଡେସ୍କଟପ ମୋଡ"</string> diff --git a/libs/WindowManager/Shell/res/values-pa/strings.xml b/libs/WindowManager/Shell/res/values-pa/strings.xml index 4a08f6762673..bdef224e99b4 100644 --- a/libs/WindowManager/Shell/res/values-pa/strings.xml +++ b/libs/WindowManager/Shell/res/values-pa/strings.xml @@ -107,7 +107,7 @@ <string name="minimize_button_text" msgid="271592547935841753">"ਛੋਟਾ ਕਰੋ"</string> <string name="close_button_text" msgid="2913281996024033299">"ਬੰਦ ਕਰੋ"</string> <string name="back_button_text" msgid="1469718707134137085">"ਪਿੱਛੇ"</string> - <string name="handle_text" msgid="1766582106752184456">"ਹੈਂਡਲ"</string> + <string name="handle_text" msgid="4419667835599523257">"ਐਪ ਹੈਂਡਲ"</string> <string name="app_icon_text" msgid="2823268023931811747">"ਐਪ ਪ੍ਰਤੀਕ"</string> <string name="fullscreen_text" msgid="1162316685217676079">"ਪੂਰੀ-ਸਕ੍ਰੀਨ"</string> <string name="desktop_text" msgid="1077633567027630454">"ਡੈਸਕਟਾਪ ਮੋਡ"</string> diff --git a/libs/WindowManager/Shell/res/values-pl/strings.xml b/libs/WindowManager/Shell/res/values-pl/strings.xml index 1c268bd34d55..41c4bb08a29a 100644 --- a/libs/WindowManager/Shell/res/values-pl/strings.xml +++ b/libs/WindowManager/Shell/res/values-pl/strings.xml @@ -107,7 +107,7 @@ <string name="minimize_button_text" msgid="271592547935841753">"Minimalizuj"</string> <string name="close_button_text" msgid="2913281996024033299">"Zamknij"</string> <string name="back_button_text" msgid="1469718707134137085">"Wstecz"</string> - <string name="handle_text" msgid="1766582106752184456">"Uchwyt"</string> + <string name="handle_text" msgid="4419667835599523257">"Uchwyt aplikacji"</string> <string name="app_icon_text" msgid="2823268023931811747">"Ikona aplikacji"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Pełny ekran"</string> <string name="desktop_text" msgid="1077633567027630454">"Tryb pulpitu"</string> diff --git a/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml b/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml index 82566fedf890..83d34c04cbfd 100644 --- a/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml +++ b/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml @@ -107,7 +107,7 @@ <string name="minimize_button_text" msgid="271592547935841753">"Minimizar"</string> <string name="close_button_text" msgid="2913281996024033299">"Fechar"</string> <string name="back_button_text" msgid="1469718707134137085">"Voltar"</string> - <string name="handle_text" msgid="1766582106752184456">"Alça"</string> + <string name="handle_text" msgid="4419667835599523257">"Identificador do app"</string> <string name="app_icon_text" msgid="2823268023931811747">"Ícone do app"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Tela cheia"</string> <string name="desktop_text" msgid="1077633567027630454">"Modo área de trabalho"</string> diff --git a/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml b/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml index b2e89182ace4..425ad052aeca 100644 --- a/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml +++ b/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml @@ -107,7 +107,7 @@ <string name="minimize_button_text" msgid="271592547935841753">"Minimizar"</string> <string name="close_button_text" msgid="2913281996024033299">"Fechar"</string> <string name="back_button_text" msgid="1469718707134137085">"Anterior"</string> - <string name="handle_text" msgid="1766582106752184456">"Indicador"</string> + <string name="handle_text" msgid="4419667835599523257">"Indicador da app"</string> <string name="app_icon_text" msgid="2823268023931811747">"Ícone da app"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Ecrã inteiro"</string> <string name="desktop_text" msgid="1077633567027630454">"Modo de ambiente de trabalho"</string> diff --git a/libs/WindowManager/Shell/res/values-pt/strings.xml b/libs/WindowManager/Shell/res/values-pt/strings.xml index 82566fedf890..83d34c04cbfd 100644 --- a/libs/WindowManager/Shell/res/values-pt/strings.xml +++ b/libs/WindowManager/Shell/res/values-pt/strings.xml @@ -107,7 +107,7 @@ <string name="minimize_button_text" msgid="271592547935841753">"Minimizar"</string> <string name="close_button_text" msgid="2913281996024033299">"Fechar"</string> <string name="back_button_text" msgid="1469718707134137085">"Voltar"</string> - <string name="handle_text" msgid="1766582106752184456">"Alça"</string> + <string name="handle_text" msgid="4419667835599523257">"Identificador do app"</string> <string name="app_icon_text" msgid="2823268023931811747">"Ícone do app"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Tela cheia"</string> <string name="desktop_text" msgid="1077633567027630454">"Modo área de trabalho"</string> diff --git a/libs/WindowManager/Shell/res/values-ro/strings.xml b/libs/WindowManager/Shell/res/values-ro/strings.xml index 503f68c99c38..ea1a6b7f1422 100644 --- a/libs/WindowManager/Shell/res/values-ro/strings.xml +++ b/libs/WindowManager/Shell/res/values-ro/strings.xml @@ -107,7 +107,7 @@ <string name="minimize_button_text" msgid="271592547935841753">"Minimizează"</string> <string name="close_button_text" msgid="2913281996024033299">"Închide"</string> <string name="back_button_text" msgid="1469718707134137085">"Înapoi"</string> - <string name="handle_text" msgid="1766582106752184456">"Ghidaj"</string> + <string name="handle_text" msgid="4419667835599523257">"Handle de aplicație"</string> <string name="app_icon_text" msgid="2823268023931811747">"Pictograma aplicației"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Ecran complet"</string> <string name="desktop_text" msgid="1077633567027630454">"Modul desktop"</string> diff --git a/libs/WindowManager/Shell/res/values-ru/strings.xml b/libs/WindowManager/Shell/res/values-ru/strings.xml index b2a60302bd1a..d0292beb27bf 100644 --- a/libs/WindowManager/Shell/res/values-ru/strings.xml +++ b/libs/WindowManager/Shell/res/values-ru/strings.xml @@ -107,7 +107,7 @@ <string name="minimize_button_text" msgid="271592547935841753">"Свернуть"</string> <string name="close_button_text" msgid="2913281996024033299">"Закрыть"</string> <string name="back_button_text" msgid="1469718707134137085">"Назад"</string> - <string name="handle_text" msgid="1766582106752184456">"Маркер"</string> + <string name="handle_text" msgid="4419667835599523257">"Обозначение приложения"</string> <string name="app_icon_text" msgid="2823268023931811747">"Значок приложения"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Полноэкранный режим"</string> <string name="desktop_text" msgid="1077633567027630454">"Режим компьютера"</string> diff --git a/libs/WindowManager/Shell/res/values-si/strings.xml b/libs/WindowManager/Shell/res/values-si/strings.xml index 8589f42dd125..7994222d4913 100644 --- a/libs/WindowManager/Shell/res/values-si/strings.xml +++ b/libs/WindowManager/Shell/res/values-si/strings.xml @@ -107,7 +107,7 @@ <string name="minimize_button_text" msgid="271592547935841753">"කුඩා කරන්න"</string> <string name="close_button_text" msgid="2913281996024033299">"වසන්න"</string> <string name="back_button_text" msgid="1469718707134137085">"ආපසු"</string> - <string name="handle_text" msgid="1766582106752184456">"හැඬලය"</string> + <string name="handle_text" msgid="4419667835599523257">"යෙදුම් හසුරුව"</string> <string name="app_icon_text" msgid="2823268023931811747">"යෙදුම් නිරූපකය"</string> <string name="fullscreen_text" msgid="1162316685217676079">"පූර්ණ තිරය"</string> <string name="desktop_text" msgid="1077633567027630454">"ඩෙස්ක්ටොප් ප්රකාරය"</string> diff --git a/libs/WindowManager/Shell/res/values-sk/strings.xml b/libs/WindowManager/Shell/res/values-sk/strings.xml index 895974462576..896a85b477da 100644 --- a/libs/WindowManager/Shell/res/values-sk/strings.xml +++ b/libs/WindowManager/Shell/res/values-sk/strings.xml @@ -107,7 +107,7 @@ <string name="minimize_button_text" msgid="271592547935841753">"Minimalizovať"</string> <string name="close_button_text" msgid="2913281996024033299">"Zavrieť"</string> <string name="back_button_text" msgid="1469718707134137085">"Späť"</string> - <string name="handle_text" msgid="1766582106752184456">"Rukoväť"</string> + <string name="handle_text" msgid="4419667835599523257">"Rukoväť aplikácie"</string> <string name="app_icon_text" msgid="2823268023931811747">"Ikona aplikácie"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Celá obrazovka"</string> <string name="desktop_text" msgid="1077633567027630454">"Režim počítača"</string> diff --git a/libs/WindowManager/Shell/res/values-sl/strings.xml b/libs/WindowManager/Shell/res/values-sl/strings.xml index 5848f9261d9b..3418c483508d 100644 --- a/libs/WindowManager/Shell/res/values-sl/strings.xml +++ b/libs/WindowManager/Shell/res/values-sl/strings.xml @@ -107,7 +107,7 @@ <string name="minimize_button_text" msgid="271592547935841753">"Minimiraj"</string> <string name="close_button_text" msgid="2913281996024033299">"Zapri"</string> <string name="back_button_text" msgid="1469718707134137085">"Nazaj"</string> - <string name="handle_text" msgid="1766582106752184456">"Ročica"</string> + <string name="handle_text" msgid="4419667835599523257">"Identifikator aplikacije"</string> <string name="app_icon_text" msgid="2823268023931811747">"Ikona aplikacije"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Celozaslonsko"</string> <string name="desktop_text" msgid="1077633567027630454">"Namizni način"</string> diff --git a/libs/WindowManager/Shell/res/values-sq/strings.xml b/libs/WindowManager/Shell/res/values-sq/strings.xml index 406389465aa0..306fcaa5191c 100644 --- a/libs/WindowManager/Shell/res/values-sq/strings.xml +++ b/libs/WindowManager/Shell/res/values-sq/strings.xml @@ -107,7 +107,7 @@ <string name="minimize_button_text" msgid="271592547935841753">"Minimizo"</string> <string name="close_button_text" msgid="2913281996024033299">"Mbyll"</string> <string name="back_button_text" msgid="1469718707134137085">"Pas"</string> - <string name="handle_text" msgid="1766582106752184456">"Emërtimi"</string> + <string name="handle_text" msgid="4419667835599523257">"Emërtimi i aplikacionit"</string> <string name="app_icon_text" msgid="2823268023931811747">"Ikona e aplikacionit"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Ekrani i plotë"</string> <string name="desktop_text" msgid="1077633567027630454">"Modaliteti i desktopit"</string> diff --git a/libs/WindowManager/Shell/res/values-sr/strings.xml b/libs/WindowManager/Shell/res/values-sr/strings.xml index 8402eef99c38..8fd824ec0d1c 100644 --- a/libs/WindowManager/Shell/res/values-sr/strings.xml +++ b/libs/WindowManager/Shell/res/values-sr/strings.xml @@ -107,7 +107,7 @@ <string name="minimize_button_text" msgid="271592547935841753">"Умањите"</string> <string name="close_button_text" msgid="2913281996024033299">"Затворите"</string> <string name="back_button_text" msgid="1469718707134137085">"Назад"</string> - <string name="handle_text" msgid="1766582106752184456">"Идентификатор"</string> + <string name="handle_text" msgid="4419667835599523257">"Идентификатор апликације"</string> <string name="app_icon_text" msgid="2823268023931811747">"Икона апликације"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Преко целог екрана"</string> <string name="desktop_text" msgid="1077633567027630454">"Режим за рачунаре"</string> diff --git a/libs/WindowManager/Shell/res/values-sv/strings.xml b/libs/WindowManager/Shell/res/values-sv/strings.xml index 77c7d09fdb24..b6375c69f0dc 100644 --- a/libs/WindowManager/Shell/res/values-sv/strings.xml +++ b/libs/WindowManager/Shell/res/values-sv/strings.xml @@ -107,7 +107,7 @@ <string name="minimize_button_text" msgid="271592547935841753">"Minimera"</string> <string name="close_button_text" msgid="2913281996024033299">"Stäng"</string> <string name="back_button_text" msgid="1469718707134137085">"Tillbaka"</string> - <string name="handle_text" msgid="1766582106752184456">"Handtag"</string> + <string name="handle_text" msgid="4419667835599523257">"Apphandtag"</string> <string name="app_icon_text" msgid="2823268023931811747">"Appikon"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Helskärm"</string> <string name="desktop_text" msgid="1077633567027630454">"Datorläge"</string> diff --git a/libs/WindowManager/Shell/res/values-sw/strings.xml b/libs/WindowManager/Shell/res/values-sw/strings.xml index d367c80c7197..2eadf34f5197 100644 --- a/libs/WindowManager/Shell/res/values-sw/strings.xml +++ b/libs/WindowManager/Shell/res/values-sw/strings.xml @@ -107,7 +107,7 @@ <string name="minimize_button_text" msgid="271592547935841753">"Punguza"</string> <string name="close_button_text" msgid="2913281996024033299">"Funga"</string> <string name="back_button_text" msgid="1469718707134137085">"Rudi nyuma"</string> - <string name="handle_text" msgid="1766582106752184456">"Ncha"</string> + <string name="handle_text" msgid="4419667835599523257">"Utambulisho wa programu"</string> <string name="app_icon_text" msgid="2823268023931811747">"Aikoni ya Programu"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Skrini nzima"</string> <string name="desktop_text" msgid="1077633567027630454">"Hali ya Kompyuta ya mezani"</string> diff --git a/libs/WindowManager/Shell/res/values-ta/strings.xml b/libs/WindowManager/Shell/res/values-ta/strings.xml index 697f9519688f..36f69ce02515 100644 --- a/libs/WindowManager/Shell/res/values-ta/strings.xml +++ b/libs/WindowManager/Shell/res/values-ta/strings.xml @@ -107,7 +107,7 @@ <string name="minimize_button_text" msgid="271592547935841753">"சிறிதாக்கும்"</string> <string name="close_button_text" msgid="2913281996024033299">"மூடும்"</string> <string name="back_button_text" msgid="1469718707134137085">"பின்செல்லும்"</string> - <string name="handle_text" msgid="1766582106752184456">"ஹேண்டில்"</string> + <string name="handle_text" msgid="4419667835599523257">"ஆப்ஸ் ஹேண்டில்"</string> <string name="app_icon_text" msgid="2823268023931811747">"ஆப்ஸ் ஐகான்"</string> <string name="fullscreen_text" msgid="1162316685217676079">"முழுத்திரை"</string> <string name="desktop_text" msgid="1077633567027630454">"டெஸ்க்டாப் பயன்முறை"</string> diff --git a/libs/WindowManager/Shell/res/values-te/strings.xml b/libs/WindowManager/Shell/res/values-te/strings.xml index ef094fcc8e64..2446ae8f58e6 100644 --- a/libs/WindowManager/Shell/res/values-te/strings.xml +++ b/libs/WindowManager/Shell/res/values-te/strings.xml @@ -107,7 +107,7 @@ <string name="minimize_button_text" msgid="271592547935841753">"కుదించండి"</string> <string name="close_button_text" msgid="2913281996024033299">"మూసివేయండి"</string> <string name="back_button_text" msgid="1469718707134137085">"వెనుకకు"</string> - <string name="handle_text" msgid="1766582106752184456">"హ్యాండిల్"</string> + <string name="handle_text" msgid="4419667835599523257">"యాప్ హ్యాండిల్"</string> <string name="app_icon_text" msgid="2823268023931811747">"యాప్ చిహ్నం"</string> <string name="fullscreen_text" msgid="1162316685217676079">"ఫుల్-స్క్రీన్"</string> <string name="desktop_text" msgid="1077633567027630454">"డెస్క్టాప్ మోడ్"</string> diff --git a/libs/WindowManager/Shell/res/values-th/strings.xml b/libs/WindowManager/Shell/res/values-th/strings.xml index 762a81a0305a..10cf216064a2 100644 --- a/libs/WindowManager/Shell/res/values-th/strings.xml +++ b/libs/WindowManager/Shell/res/values-th/strings.xml @@ -107,7 +107,7 @@ <string name="minimize_button_text" msgid="271592547935841753">"ย่อ"</string> <string name="close_button_text" msgid="2913281996024033299">"ปิด"</string> <string name="back_button_text" msgid="1469718707134137085">"กลับ"</string> - <string name="handle_text" msgid="1766582106752184456">"แฮนเดิล"</string> + <string name="handle_text" msgid="4419667835599523257">"แฮนเดิลแอป"</string> <string name="app_icon_text" msgid="2823268023931811747">"ไอคอนแอป"</string> <string name="fullscreen_text" msgid="1162316685217676079">"เต็มหน้าจอ"</string> <string name="desktop_text" msgid="1077633567027630454">"โหมดเดสก์ท็อป"</string> diff --git a/libs/WindowManager/Shell/res/values-tl/strings.xml b/libs/WindowManager/Shell/res/values-tl/strings.xml index 418f500aac80..497ac56b408d 100644 --- a/libs/WindowManager/Shell/res/values-tl/strings.xml +++ b/libs/WindowManager/Shell/res/values-tl/strings.xml @@ -107,7 +107,7 @@ <string name="minimize_button_text" msgid="271592547935841753">"I-minimize"</string> <string name="close_button_text" msgid="2913281996024033299">"Isara"</string> <string name="back_button_text" msgid="1469718707134137085">"Bumalik"</string> - <string name="handle_text" msgid="1766582106752184456">"Handle"</string> + <string name="handle_text" msgid="4419667835599523257">"Handle ng app"</string> <string name="app_icon_text" msgid="2823268023931811747">"Icon ng App"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Fullscreen"</string> <string name="desktop_text" msgid="1077633567027630454">"Desktop Mode"</string> diff --git a/libs/WindowManager/Shell/res/values-tr/strings.xml b/libs/WindowManager/Shell/res/values-tr/strings.xml index 1a9724079e65..05eb1ba79f2a 100644 --- a/libs/WindowManager/Shell/res/values-tr/strings.xml +++ b/libs/WindowManager/Shell/res/values-tr/strings.xml @@ -107,7 +107,7 @@ <string name="minimize_button_text" msgid="271592547935841753">"Küçült"</string> <string name="close_button_text" msgid="2913281996024033299">"Kapat"</string> <string name="back_button_text" msgid="1469718707134137085">"Geri"</string> - <string name="handle_text" msgid="1766582106752184456">"Herkese açık kullanıcı adı"</string> + <string name="handle_text" msgid="4419667835599523257">"Uygulama tanıtıcısı"</string> <string name="app_icon_text" msgid="2823268023931811747">"Uygulama Simgesi"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Tam Ekran"</string> <string name="desktop_text" msgid="1077633567027630454">"Masaüstü Modu"</string> diff --git a/libs/WindowManager/Shell/res/values-uk/strings.xml b/libs/WindowManager/Shell/res/values-uk/strings.xml index a5fcae5775a0..5c3cfaad4b28 100644 --- a/libs/WindowManager/Shell/res/values-uk/strings.xml +++ b/libs/WindowManager/Shell/res/values-uk/strings.xml @@ -107,7 +107,7 @@ <string name="minimize_button_text" msgid="271592547935841753">"Згорнути"</string> <string name="close_button_text" msgid="2913281996024033299">"Закрити"</string> <string name="back_button_text" msgid="1469718707134137085">"Назад"</string> - <string name="handle_text" msgid="1766582106752184456">"Маркер"</string> + <string name="handle_text" msgid="4419667835599523257">"Дескриптор додатка"</string> <string name="app_icon_text" msgid="2823268023931811747">"Значок додатка"</string> <string name="fullscreen_text" msgid="1162316685217676079">"На весь екран"</string> <string name="desktop_text" msgid="1077633567027630454">"Режим комп’ютера"</string> diff --git a/libs/WindowManager/Shell/res/values-ur/strings.xml b/libs/WindowManager/Shell/res/values-ur/strings.xml index 2cf9f325892d..98c433b1159f 100644 --- a/libs/WindowManager/Shell/res/values-ur/strings.xml +++ b/libs/WindowManager/Shell/res/values-ur/strings.xml @@ -107,7 +107,7 @@ <string name="minimize_button_text" msgid="271592547935841753">"چھوٹا کریں"</string> <string name="close_button_text" msgid="2913281996024033299">"بند کریں"</string> <string name="back_button_text" msgid="1469718707134137085">"پیچھے"</string> - <string name="handle_text" msgid="1766582106752184456">"ہینڈل"</string> + <string name="handle_text" msgid="4419667835599523257">"ایپ ہینڈل"</string> <string name="app_icon_text" msgid="2823268023931811747">"ایپ کا آئیکن"</string> <string name="fullscreen_text" msgid="1162316685217676079">"مکمل اسکرین"</string> <string name="desktop_text" msgid="1077633567027630454">"ڈیسک ٹاپ موڈ"</string> diff --git a/libs/WindowManager/Shell/res/values-uz/strings.xml b/libs/WindowManager/Shell/res/values-uz/strings.xml index f8cd43f9d6fa..3ec676d2942d 100644 --- a/libs/WindowManager/Shell/res/values-uz/strings.xml +++ b/libs/WindowManager/Shell/res/values-uz/strings.xml @@ -107,7 +107,7 @@ <string name="minimize_button_text" msgid="271592547935841753">"Kichraytirish"</string> <string name="close_button_text" msgid="2913281996024033299">"Yopish"</string> <string name="back_button_text" msgid="1469718707134137085">"Orqaga"</string> - <string name="handle_text" msgid="1766582106752184456">"Identifikator"</string> + <string name="handle_text" msgid="4419667835599523257">"Ilova identifikatori"</string> <string name="app_icon_text" msgid="2823268023931811747">"Ilova belgisi"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Butun ekran"</string> <string name="desktop_text" msgid="1077633567027630454">"Desktop rejimi"</string> diff --git a/libs/WindowManager/Shell/res/values-vi/strings.xml b/libs/WindowManager/Shell/res/values-vi/strings.xml index 86e2b3349716..125d703a464e 100644 --- a/libs/WindowManager/Shell/res/values-vi/strings.xml +++ b/libs/WindowManager/Shell/res/values-vi/strings.xml @@ -107,7 +107,7 @@ <string name="minimize_button_text" msgid="271592547935841753">"Thu nhỏ"</string> <string name="close_button_text" msgid="2913281996024033299">"Đóng"</string> <string name="back_button_text" msgid="1469718707134137085">"Quay lại"</string> - <string name="handle_text" msgid="1766582106752184456">"Xử lý"</string> + <string name="handle_text" msgid="4419667835599523257">"Ô điều khiển ứng dụng"</string> <string name="app_icon_text" msgid="2823268023931811747">"Biểu tượng ứng dụng"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Toàn màn hình"</string> <string name="desktop_text" msgid="1077633567027630454">"Chế độ máy tính"</string> diff --git a/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml b/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml index a56553b786c3..6ccc38b624e9 100644 --- a/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml +++ b/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml @@ -107,7 +107,7 @@ <string name="minimize_button_text" msgid="271592547935841753">"最小化"</string> <string name="close_button_text" msgid="2913281996024033299">"关闭"</string> <string name="back_button_text" msgid="1469718707134137085">"返回"</string> - <string name="handle_text" msgid="1766582106752184456">"处理"</string> + <string name="handle_text" msgid="4419667835599523257">"应用手柄"</string> <string name="app_icon_text" msgid="2823268023931811747">"应用图标"</string> <string name="fullscreen_text" msgid="1162316685217676079">"全屏"</string> <string name="desktop_text" msgid="1077633567027630454">"桌面模式"</string> diff --git a/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml b/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml index 78c97e4944c9..2787c1e86b0c 100644 --- a/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml +++ b/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml @@ -107,7 +107,7 @@ <string name="minimize_button_text" msgid="271592547935841753">"最小化"</string> <string name="close_button_text" msgid="2913281996024033299">"關閉"</string> <string name="back_button_text" msgid="1469718707134137085">"返去"</string> - <string name="handle_text" msgid="1766582106752184456">"控點"</string> + <string name="handle_text" msgid="4419667835599523257">"應用程式控點"</string> <string name="app_icon_text" msgid="2823268023931811747">"應用程式圖示"</string> <string name="fullscreen_text" msgid="1162316685217676079">"全螢幕"</string> <string name="desktop_text" msgid="1077633567027630454">"桌面模式"</string> diff --git a/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml b/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml index 307dc9db9381..72050fb3edc6 100644 --- a/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml +++ b/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml @@ -107,7 +107,7 @@ <string name="minimize_button_text" msgid="271592547935841753">"最小化"</string> <string name="close_button_text" msgid="2913281996024033299">"關閉"</string> <string name="back_button_text" msgid="1469718707134137085">"返回"</string> - <string name="handle_text" msgid="1766582106752184456">"控點"</string> + <string name="handle_text" msgid="4419667835599523257">"應用程式控制代碼"</string> <string name="app_icon_text" msgid="2823268023931811747">"應用程式圖示"</string> <string name="fullscreen_text" msgid="1162316685217676079">"全螢幕"</string> <string name="desktop_text" msgid="1077633567027630454">"電腦模式"</string> diff --git a/libs/WindowManager/Shell/res/values-zu/strings.xml b/libs/WindowManager/Shell/res/values-zu/strings.xml index ba3df301df54..ac62a7bd67b2 100644 --- a/libs/WindowManager/Shell/res/values-zu/strings.xml +++ b/libs/WindowManager/Shell/res/values-zu/strings.xml @@ -107,7 +107,7 @@ <string name="minimize_button_text" msgid="271592547935841753">"Nciphisa"</string> <string name="close_button_text" msgid="2913281996024033299">"Vala"</string> <string name="back_button_text" msgid="1469718707134137085">"Emuva"</string> - <string name="handle_text" msgid="1766582106752184456">"Isibambo"</string> + <string name="handle_text" msgid="4419667835599523257">"Inkomba ye-App"</string> <string name="app_icon_text" msgid="2823268023931811747">"Isithonjana Se-app"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Isikrini esigcwele"</string> <string name="desktop_text" msgid="1077633567027630454">"Imodi Yedeskithophu"</string> diff --git a/libs/WindowManager/Shell/res/values/dimen.xml b/libs/WindowManager/Shell/res/values/dimen.xml index 269a58693a24..1eb24580a582 100644 --- a/libs/WindowManager/Shell/res/values/dimen.xml +++ b/libs/WindowManager/Shell/res/values/dimen.xml @@ -296,9 +296,6 @@ <!-- The width of the compat hint. --> <dimen name="compat_hint_width">188dp</dimen> - <!-- The width of the camera compat hint. --> - <dimen name="camera_compat_hint_width">143dp</dimen> - <!-- The corner radius of the letterbox education dialog. --> <dimen name="letterbox_education_dialog_corner_radius">28dp</dimen> @@ -554,15 +551,10 @@ enable_windowing_edge_drag_resize is disabled. --> <dimen name="freeform_resize_corner">44dp</dimen> - <!-- The width of the area at the sides of the screen where a freeform task will transition to - split select if dragged until the touch input is within the range. --> - <dimen name="desktop_mode_transition_area_width">32dp</dimen> - - <!-- The width of the area where a desktop task will transition to fullscreen. --> - <dimen name="desktop_mode_fullscreen_from_desktop_width">80dp</dimen> + <!-- The thickness in dp for all desktop drag transition regions. --> + <dimen name="desktop_mode_transition_region_thickness">44dp</dimen> - <!-- The height of the area where a desktop task will transition to fullscreen. --> - <dimen name="desktop_mode_fullscreen_from_desktop_height">40dp</dimen> + <item type="dimen" format="float" name="desktop_mode_fullscreen_region_scale">0.4</item> <!-- The height on the screen where drag to the left or right edge will result in a desktop task snapping to split size. The empty space between this and the top is to allow diff --git a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopModeFlags.kt b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopModeFlags.kt index b1c9a775913a..13049694d3fb 100644 --- a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopModeFlags.kt +++ b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopModeFlags.kt @@ -35,6 +35,7 @@ enum class DesktopModeFlags( ) { // All desktop mode related flags will be added here DESKTOP_WINDOWING_MODE(Flags::enableDesktopWindowingMode, true), + CASCADING_WINDOWS(Flags::enableCascadingWindows, true), WALLPAPER_ACTIVITY(Flags::enableDesktopWindowingWallpaperActivity, true), MODALS_POLICY(Flags::enableDesktopWindowingModalsPolicy, true), THEMED_APP_HEADERS(Flags::enableThemedAppHeaders, true), @@ -42,7 +43,8 @@ enum class DesktopModeFlags( APP_HEADER_WITH_TASK_DENSITY(Flags::enableAppHeaderWithTaskDensity, true), TASK_STACK_OBSERVER_IN_SHELL(Flags::enableTaskStackObserverInShell, true), SIZE_CONSTRAINTS(Flags::enableDesktopWindowingSizeConstraints, true), - DYNAMIC_INITIAL_BOUNDS(Flags::enableWindowingDynamicInitialBounds, true); + DYNAMIC_INITIAL_BOUNDS(Flags::enableWindowingDynamicInitialBounds, true), + ENABLE_DESKTOP_WINDOWING_TASK_LIMIT(Flags::enableDesktopWindowingTaskLimit, true); /** * Determines state of flag based on the actual flag and desktop mode developer option overrides. diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java index f014e559d4b4..452d12a242c0 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java @@ -24,7 +24,6 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; -import static com.android.wm.shell.compatui.impl.CompatUIEventsKt.CAMERA_CONTROL_STATE_UPDATE; import static com.android.wm.shell.compatui.impl.CompatUIEventsKt.SIZE_COMPAT_RESTART_BUTTON_APPEARED; import static com.android.wm.shell.compatui.impl.CompatUIEventsKt.SIZE_COMPAT_RESTART_BUTTON_CLICKED; import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_TASK_ORG; @@ -61,7 +60,6 @@ import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.compatui.CompatUIController; import com.android.wm.shell.compatui.api.CompatUIHandler; import com.android.wm.shell.compatui.api.CompatUIInfo; -import com.android.wm.shell.compatui.impl.CompatUIEvents.CameraControlStateUpdated; import com.android.wm.shell.compatui.impl.CompatUIEvents.SizeCompatRestartButtonAppeared; import com.android.wm.shell.compatui.impl.CompatUIEvents.SizeCompatRestartButtonClicked; import com.android.wm.shell.recents.RecentTasksController; @@ -265,9 +263,6 @@ public class ShellTaskOrganizer extends TaskOrganizer { case SIZE_COMPAT_RESTART_BUTTON_CLICKED: onSizeCompatRestartButtonClicked(compatUIEvent.asType()); break; - case CAMERA_CONTROL_STATE_UPDATE: - onCameraControlStateUpdated(compatUIEvent.asType()); - break; default: } @@ -690,6 +685,15 @@ public class ShellTaskOrganizer extends TaskOrganizer { return result; } + /** Return list of {@link RunningTaskInfo}s on all the displays. */ + public ArrayList<RunningTaskInfo> getRunningTasks() { + ArrayList<RunningTaskInfo> result = new ArrayList<>(); + for (int i = 0; i < mTasks.size(); i++) { + result.add(mTasks.valueAt(i).getTaskInfo()); + } + return result; + } + /** Gets running task by taskId. Returns {@code null} if no such task observed. */ @Nullable public RunningTaskInfo getRunningTaskInfo(int taskId) { @@ -808,21 +812,6 @@ public class ShellTaskOrganizer extends TaskOrganizer { restartTaskTopActivityProcessIfVisible(info.getTaskInfo().token); } - @VisibleForTesting - void onCameraControlStateUpdated(@NonNull CameraControlStateUpdated compatUIEvent) { - final int taskId = compatUIEvent.getTaskId(); - final int state = compatUIEvent.getState(); - final TaskAppearedInfo info; - synchronized (mLock) { - info = mTasks.get(taskId); - } - if (info == null) { - return; - } - updateCameraCompatControlState(info.getTaskInfo().token, state); - } - - private void logSizeCompatRestartButtonEventReported(@NonNull TaskAppearedInfo info, int event) { ActivityInfo topActivityInfo = info.getTaskInfo().topActivityInfo; diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedView.java index 972dce51e02b..24c568c23bf2 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedView.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedView.java @@ -169,6 +169,8 @@ public class BubbleBarExpandedView extends FrameLayout implements BubbleTaskView R.layout.bubble_overflow_container, null /* root */); mOverflowView.initialize(expandedViewManager, positioner); addView(mOverflowView); + // Don't show handle for overflow + mHandleView.setVisibility(View.GONE); } else { mTaskView = bubbleTaskView.getTaskView(); mBubbleTaskViewHelper = new BubbleTaskViewHelper(mContext, expandedViewManager, diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java index 4fbb5744b64b..d7d19f7b8bbd 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java @@ -315,7 +315,7 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged } } if (!mImeShowing) { - removeImeSurface(); + removeImeSurface(mDisplayId); } } } else if (!android.view.inputmethod.Flags.refactorInsetsController() @@ -617,7 +617,7 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged || hasLeash) { t.hide(mImeSourceControl.getLeash()); } - removeImeSurface(); + removeImeSurface(mDisplayId); ImeTracker.forLogging().onHidden(mStatsToken); } else if (mAnimationDirection == DIRECTION_SHOW && !mCancelled) { ImeTracker.forLogging().onShown(mStatsToken); @@ -671,10 +671,10 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged } } - void removeImeSurface() { + void removeImeSurface(int displayId) { // Remove the IME surface to make the insets invisible for // non-client controlled insets. - InputMethodManagerGlobal.removeImeSurface( + InputMethodManagerGlobal.removeImeSurface(displayId, e -> Slog.e(TAG, "Failed to remove IME surface.", e)); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/ImeListener.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/common/ImeListener.kt new file mode 100644 index 000000000000..a34d7bed497b --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/ImeListener.kt @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.wm.shell.common + +import android.graphics.Rect +import android.view.InsetsSource +import android.view.InsetsState +import com.android.wm.shell.common.DisplayInsetsController.OnInsetsChangedListener + +abstract class ImeListener( + private val mDisplayController: DisplayController, + private val mDisplayId: Int +) : OnInsetsChangedListener { + // The last insets state + private val mInsetsState = InsetsState() + private val mTmpBounds = Rect() + + override fun insetsChanged(insetsState: InsetsState) { + if (mInsetsState == insetsState) { + return + } + + // Get the stable bounds that account for display cutout and system bars to calculate the + // relative IME height + val layout = mDisplayController.getDisplayLayout(mDisplayId) + if (layout == null) { + return + } + layout.getStableBounds(mTmpBounds) + + val wasVisible = getImeVisibilityAndHeight(mInsetsState).first + val oldHeight = getImeVisibilityAndHeight(mInsetsState).second + + val isVisible = getImeVisibilityAndHeight(insetsState).first + val newHeight = getImeVisibilityAndHeight(insetsState).second + + mInsetsState.set(insetsState, true) + if (wasVisible != isVisible || oldHeight != newHeight) { + onImeVisibilityChanged(isVisible, newHeight) + } + } + + private fun getImeVisibilityAndHeight( + insetsState: InsetsState): Pair<Boolean, Int> { + val source = insetsState.peekSource(InsetsSource.ID_IME) + val frame = if (source != null && source.isVisible) source.frame else null + val height = if (frame != null) mTmpBounds.bottom - frame.top else 0 + val visible = source?.isVisible ?: false + return Pair(visible, height) + } + + /** + * To be overridden by implementations to handle IME changes. + */ + protected abstract fun onImeVisibilityChanged(imeVisible: Boolean, imeHeight: Int) +}
\ No newline at end of file diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitDecorManager.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitDecorManager.java index 5097ed8866c9..19a109e9a28c 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitDecorManager.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitDecorManager.java @@ -31,6 +31,7 @@ import android.animation.ValueAnimator; import android.app.ActivityManager; import android.content.Context; import android.content.res.Configuration; +import android.graphics.Color; import android.graphics.PixelFormat; import android.graphics.Rect; import android.graphics.drawable.Drawable; @@ -201,7 +202,7 @@ public class SplitDecorManager extends WindowlessWindowManager { /** Showing resizing hint. */ public void onResizing(ActivityManager.RunningTaskInfo resizingTask, Rect newBounds, Rect sideBounds, SurfaceControl.Transaction t, int offsetX, int offsetY, - boolean immediately, float[] veilColor) { + boolean immediately) { if (mResizingIconView == null) { return; } @@ -234,7 +235,7 @@ public class SplitDecorManager extends WindowlessWindowManager { if (mBackgroundLeash == null) { mBackgroundLeash = SurfaceUtils.makeColorLayer(mHostLeash, RESIZING_BACKGROUND_SURFACE_NAME, mSurfaceSession); - t.setColor(mBackgroundLeash, veilColor) + t.setColor(mBackgroundLeash, getResizingBackgroundColor(resizingTask)) .setLayer(mBackgroundLeash, Integer.MAX_VALUE - 1); } @@ -245,7 +246,7 @@ public class SplitDecorManager extends WindowlessWindowManager { mGapBackgroundLeash = SurfaceUtils.makeColorLayer(mHostLeash, GAP_BACKGROUND_SURFACE_NAME, mSurfaceSession); // Fill up another side bounds area. - t.setColor(mGapBackgroundLeash, veilColor) + t.setColor(mGapBackgroundLeash, getResizingBackgroundColor(resizingTask)) .setLayer(mGapBackgroundLeash, Integer.MAX_VALUE - 2) .setPosition(mGapBackgroundLeash, left, top) .setWindowCrop(mGapBackgroundLeash, sideBounds.width(), sideBounds.height()); @@ -486,4 +487,9 @@ public class SplitDecorManager extends WindowlessWindowManager { mIcon = null; } } + + private static float[] getResizingBackgroundColor(ActivityManager.RunningTaskInfo taskInfo) { + final int taskBgColor = taskInfo.taskDescription.getBackgroundColor(); + return Color.valueOf(taskBgColor == -1 ? Color.WHITE : taskBgColor).getComponents(); + } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitScreenUtils.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitScreenUtils.java index e8226051b672..f9259e79472e 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitScreenUtils.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitScreenUtils.java @@ -16,6 +16,8 @@ package com.android.wm.shell.common.split; +import static android.content.pm.LauncherApps.ShortcutQuery.FLAG_MATCH_ALL_KINDS_WITH_ALL_PINNED; + import static com.android.wm.shell.common.split.SplitScreenConstants.CONTROLLED_ACTIVITY_TYPES; import static com.android.wm.shell.common.split.SplitScreenConstants.CONTROLLED_WINDOWING_MODES; import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT; @@ -24,18 +26,25 @@ import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSIT import android.app.ActivityManager; import android.app.PendingIntent; +import android.content.ComponentName; import android.content.Intent; +import android.content.pm.LauncherApps; +import android.content.pm.ShortcutInfo; import android.content.res.Configuration; import android.content.res.Resources; -import android.graphics.Color; import android.graphics.Rect; +import android.os.UserHandle; +import androidx.annotation.NonNull; import androidx.annotation.Nullable; import com.android.internal.util.ArrayUtils; import com.android.wm.shell.Flags; import com.android.wm.shell.ShellTaskOrganizer; +import java.util.Arrays; +import java.util.List; + /** Helper utility class for split screen components to use. */ public class SplitScreenUtils { /** Reverse the split position. */ @@ -128,10 +137,4 @@ public class SplitScreenUtils { return isLandscape; } } - - /** Returns the specified background color that matches a RunningTaskInfo. */ - public static Color getResizingBackgroundColor(ActivityManager.RunningTaskInfo taskInfo) { - final int taskBgColor = taskInfo.taskDescription.getBackgroundColor(); - return Color.valueOf(taskBgColor == -1 ? Color.WHITE : taskBgColor); - } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUILayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUILayout.java index 2b0bd3272ed2..688f8ca2dc75 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUILayout.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUILayout.java @@ -16,10 +16,7 @@ package com.android.wm.shell.compatui; -import static android.app.CameraCompatTaskInfo.CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED; - import android.annotation.IdRes; -import android.app.CameraCompatTaskInfo.CameraCompatControlState; import android.content.Context; import android.util.AttributeSet; import android.view.View; @@ -57,28 +54,10 @@ class CompatUILayout extends LinearLayout { mWindowManager = windowManager; } - void updateCameraTreatmentButton(@CameraCompatControlState int newState) { - int buttonBkgId = newState == CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED - ? R.drawable.camera_compat_treatment_suggested_ripple - : R.drawable.camera_compat_treatment_applied_ripple; - int hintStringId = newState == CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED - ? R.string.camera_compat_treatment_suggested_button_description - : R.string.camera_compat_treatment_applied_button_description; - final ImageButton button = findViewById(R.id.camera_compat_treatment_button); - button.setImageResource(buttonBkgId); - button.setContentDescription(getResources().getString(hintStringId)); - final LinearLayout hint = findViewById(R.id.camera_compat_hint); - ((TextView) hint.findViewById(R.id.compat_mode_hint_text)).setText(hintStringId); - } - void setSizeCompatHintVisibility(boolean show) { setViewVisibility(R.id.size_compat_hint, show); } - void setCameraCompatHintVisibility(boolean show) { - setViewVisibility(R.id.camera_compat_hint, show); - } - void setRestartButtonVisibility(boolean show) { setViewVisibility(R.id.size_compat_restart_button, show); // Hint should never be visible without button. @@ -87,14 +66,6 @@ class CompatUILayout extends LinearLayout { } } - void setCameraControlVisibility(boolean show) { - setViewVisibility(R.id.camera_compat_control, show); - // Hint should never be visible without button. - if (!show) { - setCameraCompatHintVisibility(/* show= */ false); - } - } - private void setViewVisibility(@IdRes int resId, boolean show) { final View view = findViewById(resId); int visibility = show ? View.VISIBLE : View.GONE; @@ -127,26 +98,5 @@ class CompatUILayout extends LinearLayout { ((TextView) sizeCompatHint.findViewById(R.id.compat_mode_hint_text)) .setText(R.string.restart_button_description); sizeCompatHint.setOnClickListener(view -> setSizeCompatHintVisibility(/* show= */ false)); - - final ImageButton cameraTreatmentButton = - findViewById(R.id.camera_compat_treatment_button); - cameraTreatmentButton.setOnClickListener( - view -> mWindowManager.onCameraTreatmentButtonClicked()); - cameraTreatmentButton.setOnLongClickListener(view -> { - mWindowManager.onCameraButtonLongClicked(); - return true; - }); - - final ImageButton cameraDismissButton = findViewById(R.id.camera_compat_dismiss_button); - cameraDismissButton.setOnClickListener( - view -> mWindowManager.onCameraDismissButtonClicked()); - cameraDismissButton.setOnLongClickListener(view -> { - mWindowManager.onCameraButtonLongClicked(); - return true; - }); - - final LinearLayout cameraCompatHint = findViewById(R.id.camera_compat_hint); - cameraCompatHint.setOnClickListener( - view -> setCameraCompatHintVisibility(/* show= */ false)); } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManager.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManager.java index f32683db533a..271c07d4011d 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManager.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManager.java @@ -16,10 +16,6 @@ package com.android.wm.shell.compatui; -import static android.app.CameraCompatTaskInfo.CAMERA_COMPAT_CONTROL_DISMISSED; -import static android.app.CameraCompatTaskInfo.CAMERA_COMPAT_CONTROL_HIDDEN; -import static android.app.CameraCompatTaskInfo.CAMERA_COMPAT_CONTROL_TREATMENT_APPLIED; -import static android.app.CameraCompatTaskInfo.CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED; import static android.view.WindowManager.LARGE_SCREEN_SMALLEST_SCREEN_WIDTH_DP; import static android.window.TaskConstants.TASK_CHILD_LAYER_COMPAT_UI; @@ -27,11 +23,9 @@ import static com.android.wm.shell.shared.desktopmode.DesktopModeFlags.DESKTOP_W import android.annotation.NonNull; import android.annotation.Nullable; -import android.app.CameraCompatTaskInfo.CameraCompatControlState; import android.app.TaskInfo; import android.content.Context; import android.graphics.Rect; -import android.util.Log; import android.util.Pair; import android.view.LayoutInflater; import android.view.View; @@ -44,7 +38,6 @@ import com.android.wm.shell.common.DisplayLayout; import com.android.wm.shell.common.SyncTransactionQueue; import com.android.wm.shell.compatui.CompatUIController.CompatUIHintsState; import com.android.wm.shell.compatui.api.CompatUIEvent; -import com.android.wm.shell.compatui.impl.CompatUIEvents.CameraControlStateUpdated; import com.android.wm.shell.compatui.impl.CompatUIEvents.SizeCompatRestartButtonAppeared; import com.android.wm.shell.shared.desktopmode.DesktopModeFlags; @@ -69,10 +62,6 @@ class CompatUIWindowManager extends CompatUIWindowManagerAbstract { boolean mHasSizeCompat; @VisibleForTesting - @CameraCompatControlState - int mCameraCompatControlState = CAMERA_COMPAT_CONTROL_HIDDEN; - - @VisibleForTesting @NonNull CompatUIHintsState mCompatUIHintsState; @@ -95,12 +84,10 @@ class CompatUIWindowManager extends CompatUIWindowManagerAbstract { mCallback = callback; mHasSizeCompat = taskInfo.appCompatTaskInfo.topActivityInSizeCompat; if (DESKTOP_WINDOWING_MODE.isEnabled(mContext) - && DesktopModeFlags.THEMED_APP_HEADERS.isEnabled(context)) { + && DesktopModeFlags.DYNAMIC_INITIAL_BOUNDS.isEnabled(context)) { // Don't show the SCM button for freeform tasks mHasSizeCompat &= !taskInfo.isFreeform(); } - mCameraCompatControlState = - taskInfo.appCompatTaskInfo.cameraCompatTaskInfo.cameraCompatControlState; mCompatUIHintsState = compatUIHintsState; mCompatUIConfiguration = compatUIConfiguration; mOnRestartButtonClicked = onRestartButtonClicked; @@ -124,8 +111,7 @@ class CompatUIWindowManager extends CompatUIWindowManagerAbstract { @Override protected boolean eligibleToShowLayout() { - return (mHasSizeCompat && shouldShowSizeCompatRestartButton(getLastTaskInfo())) - || shouldShowCameraControl(); + return mHasSizeCompat && shouldShowSizeCompatRestartButton(getLastTaskInfo()); } @Override @@ -152,22 +138,18 @@ class CompatUIWindowManager extends CompatUIWindowManagerAbstract { public boolean updateCompatInfo(TaskInfo taskInfo, ShellTaskOrganizer.TaskListener taskListener, boolean canShow) { final boolean prevHasSizeCompat = mHasSizeCompat; - final int prevCameraCompatControlState = mCameraCompatControlState; mHasSizeCompat = taskInfo.appCompatTaskInfo.topActivityInSizeCompat; if (DESKTOP_WINDOWING_MODE.isEnabled(mContext) && DesktopModeFlags.DYNAMIC_INITIAL_BOUNDS.isEnabled(mContext)) { // Don't show the SCM button for freeform tasks mHasSizeCompat &= !taskInfo.isFreeform(); } - mCameraCompatControlState = - taskInfo.appCompatTaskInfo.cameraCompatTaskInfo.cameraCompatControlState; if (!super.updateCompatInfo(taskInfo, taskListener, canShow)) { return false; } - if (prevHasSizeCompat != mHasSizeCompat - || prevCameraCompatControlState != mCameraCompatControlState) { + if (prevHasSizeCompat != mHasSizeCompat) { updateVisibilityOfViews(); } @@ -179,34 +161,6 @@ class CompatUIWindowManager extends CompatUIWindowManagerAbstract { mOnRestartButtonClicked.accept(Pair.create(getLastTaskInfo(), getTaskListener())); } - /** Called when the camera treatment button is clicked. */ - void onCameraTreatmentButtonClicked() { - if (!shouldShowCameraControl()) { - Log.w(getTag(), "Camera compat shouldn't receive clicks in the hidden state."); - return; - } - // When a camera control is shown, only two states are allowed: "treament applied" and - // "treatment suggested". Clicks on the conrol's treatment button toggle between these - // two states. - mCameraCompatControlState = - mCameraCompatControlState == CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED - ? CAMERA_COMPAT_CONTROL_TREATMENT_APPLIED - : CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED; - mCallback.accept(new CameraControlStateUpdated(mTaskId, mCameraCompatControlState)); - mLayout.updateCameraTreatmentButton(mCameraCompatControlState); - } - - /** Called when the camera dismiss button is clicked. */ - void onCameraDismissButtonClicked() { - if (!shouldShowCameraControl()) { - Log.w(getTag(), "Camera compat shouldn't receive clicks in the hidden state."); - return; - } - mCameraCompatControlState = CAMERA_COMPAT_CONTROL_DISMISSED; - mCallback.accept(new CameraControlStateUpdated(mTaskId, CAMERA_COMPAT_CONTROL_DISMISSED)); - mLayout.setCameraControlVisibility(/* show= */ false); - } - /** Called when the restart button is long clicked. */ void onRestartButtonLongClicked() { if (mLayout == null) { @@ -215,14 +169,6 @@ class CompatUIWindowManager extends CompatUIWindowManagerAbstract { mLayout.setSizeCompatHintVisibility(/* show= */ true); } - /** Called when either dismiss or treatment camera buttons is long clicked. */ - void onCameraButtonLongClicked() { - if (mLayout == null) { - return; - } - mLayout.setCameraCompatHintVisibility(/* show= */ true); - } - @Override @VisibleForTesting public void updateSurfacePosition() { @@ -270,6 +216,7 @@ class CompatUIWindowManager extends CompatUIWindowManagerAbstract { return false; } final float percentageAreaOfLetterboxInTask = (float) letterboxArea / taskArea * 100; + return percentageAreaOfLetterboxInTask < mHideScmTolerance; } @@ -284,21 +231,5 @@ class CompatUIWindowManager extends CompatUIWindowManagerAbstract { mLayout.setSizeCompatHintVisibility(/* show= */ true); mCompatUIHintsState.mHasShownSizeCompatHint = true; } - - // Camera control for stretched issues. - mLayout.setCameraControlVisibility(shouldShowCameraControl()); - // Only show by default for the first time. - if (shouldShowCameraControl() && !mCompatUIHintsState.mHasShownCameraCompatHint) { - mLayout.setCameraCompatHintVisibility(/* show= */ true); - mCompatUIHintsState.mHasShownCameraCompatHint = true; - } - if (shouldShowCameraControl()) { - mLayout.updateCameraTreatmentButton(mCameraCompatControlState); - } - } - - private boolean shouldShowCameraControl() { - return mCameraCompatControlState != CAMERA_COMPAT_CONTROL_HIDDEN - && mCameraCompatControlState != CAMERA_COMPAT_CONTROL_DISMISSED; } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/impl/CompatUIEvents.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/impl/CompatUIEvents.kt index 58ce8ed6c978..23205c3dca9e 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/impl/CompatUIEvents.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/impl/CompatUIEvents.kt @@ -16,13 +16,10 @@ package com.android.wm.shell.compatui.impl -import android.app.AppCompatTaskInfo -import android.app.CameraCompatTaskInfo import com.android.wm.shell.compatui.api.CompatUIEvent internal const val SIZE_COMPAT_RESTART_BUTTON_APPEARED = 0 internal const val SIZE_COMPAT_RESTART_BUTTON_CLICKED = 1 -internal const val CAMERA_CONTROL_STATE_UPDATE = 2 /** * All the {@link CompatUIEvent} the Compat UI Framework can handle @@ -35,10 +32,4 @@ sealed class CompatUIEvents(override val eventId: Int) : CompatUIEvent { /** Sent when the size compat restart button is clicked. */ data class SizeCompatRestartButtonClicked(val taskId: Int) : CompatUIEvents(SIZE_COMPAT_RESTART_BUTTON_CLICKED) - - /** Sent when the camera compat control state is updated. */ - data class CameraControlStateUpdated( - val taskId: Int, - @CameraCompatTaskInfo.CameraCompatControlState val state: Int - ) : CompatUIEvents(CAMERA_CONTROL_STATE_UPDATE) }
\ No newline at end of file diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java index afe46f500e51..da1af0d40a96 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java @@ -16,7 +16,7 @@ package com.android.wm.shell.dagger; -import static com.android.wm.shell.shared.desktopmode.DesktopModeFlags.DESKTOP_WINDOWING_MODE; +import static com.android.wm.shell.shared.desktopmode.DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_TASK_LIMIT; import android.annotation.Nullable; import android.app.KeyguardManager; @@ -566,16 +566,23 @@ public abstract class WMShellModule { Context context, Transitions transitions, @DynamicOverride DesktopModeTaskRepository desktopModeTaskRepository, - ShellTaskOrganizer shellTaskOrganizer) { + ShellTaskOrganizer shellTaskOrganizer, + InteractionJankMonitor interactionJankMonitor) { int maxTaskLimit = DesktopModeStatus.getMaxTaskLimit(context); if (!DesktopModeStatus.canEnterDesktopMode(context) - || DESKTOP_WINDOWING_MODE.isEnabled(context) + || !ENABLE_DESKTOP_WINDOWING_TASK_LIMIT.isEnabled(context) || maxTaskLimit <= 0) { return Optional.empty(); } return Optional.of( new DesktopTasksLimiter( - transitions, desktopModeTaskRepository, shellTaskOrganizer, maxTaskLimit)); + transitions, + desktopModeTaskRepository, + shellTaskOrganizer, + maxTaskLimit, + interactionJankMonitor, + context) + ); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip2Module.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip2Module.java index ea7e9685dd92..06c1e68753e1 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip2Module.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip2Module.java @@ -104,6 +104,7 @@ public abstract class Pip2Module { TaskStackListenerImpl taskStackListener, ShellTaskOrganizer shellTaskOrganizer, PipTransitionState pipTransitionState, + PipTouchHandler pipTouchHandler, @ShellMainThread ShellExecutor mainExecutor) { if (!PipUtils.isPip2ExperimentEnabled()) { return Optional.empty(); @@ -112,7 +113,7 @@ public abstract class Pip2Module { context, shellInit, shellCommandHandler, shellController, displayController, displayInsetsController, pipBoundsState, pipBoundsAlgorithm, pipDisplayLayoutState, pipScheduler, taskStackListener, shellTaskOrganizer, - pipTransitionState, mainExecutor)); + pipTransitionState, pipTouchHandler, mainExecutor)); } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepository.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepository.kt index 247cc42e51ed..83752945e9f9 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepository.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepository.kt @@ -32,77 +32,77 @@ import java.io.PrintWriter import java.util.concurrent.Executor import java.util.function.Consumer -/** Keeps track of task data related to desktop mode. */ +/** Tracks task data for Desktop Mode. */ class DesktopModeTaskRepository { - /** Task data that is tracked per display */ - private data class DisplayData( - /** - * Set of task ids that are marked as active in desktop mode. Active tasks in desktop mode - * are freeform tasks that are visible or have been visible after desktop mode was - * activated. Task gets removed from this list when it vanishes. Or when desktop mode is - * turned off. - */ + /** + * Task data tracked per desktop. + * + * @property activeTasks task ids of active tasks currently or previously visible in Desktop + * mode session. Tasks become inactive when task closes or when desktop mode session ends. + * @property visibleTasks task ids for active freeform tasks that are currently visible. There + * might be other active tasks in desktop mode that are not visible. + * @property minimizedTasks task ids for active freeform tasks that are currently minimized. + * @property closingTasks task ids for tasks that are going to close, but are currently visible. + * @property freeformTasksInZOrder list of current freeform task ids ordered from top to bottom + * (top is at index 0). + */ + private data class DesktopTaskData( val activeTasks: ArraySet<Int> = ArraySet(), val visibleTasks: ArraySet<Int> = ArraySet(), val minimizedTasks: ArraySet<Int> = ArraySet(), - // Tasks that are closing, but are still visible // TODO(b/332682201): Remove when the repository state is updated via TransitionObserver val closingTasks: ArraySet<Int> = ArraySet(), - // Tasks currently in freeform mode, ordered from top to bottom (top is at index 0). val freeformTasksInZOrder: ArrayList<Int> = ArrayList(), ) - // Token of the current wallpaper activity, used to remove it when the last task is removed + /* Current wallpaper activity token to remove wallpaper activity when last task is removed. */ var wallpaperActivityToken: WindowContainerToken? = null + private val activeTasksListeners = ArraySet<ActiveTasksListener>() - // Track visible tasks separately because a task may be part of the desktop but not visible. private val visibleTasksListeners = ArrayMap<VisibleTasksListener, Executor>() - // Track corner/caption regions of desktop tasks, used to determine gesture exclusion + + /* Tracks corner/caption regions of desktop tasks, used to determine gesture exclusion. */ private val desktopExclusionRegions = SparseArray<Region>() - // Track last bounds of task before toggled to stable bounds + + /* Tracks last bounds of task before toggled to stable bounds. */ private val boundsBeforeMaximizeByTaskId = SparseArray<Rect>() + private var desktopGestureExclusionListener: Consumer<Region>? = null private var desktopGestureExclusionExecutor: Executor? = null - private val displayData = - object : SparseArray<DisplayData>() { - /** - * Get the [DisplayData] associated with this [displayId] - * - * Creates a new instance if one does not exist - */ - fun getOrCreate(displayId: Int): DisplayData { - if (!contains(displayId)) { - put(displayId, DisplayData()) - } - return get(displayId) - } - } + private val desktopTaskDataByDisplayId = object : SparseArray<DesktopTaskData>() { + /** Gets [DesktopTaskData] for existing [displayId] or creates a new one. */ + fun getOrCreate(displayId: Int): DesktopTaskData = + this[displayId] ?: DesktopTaskData().also { this[displayId] = it } + } - /** Add a [ActiveTasksListener] to be notified of updates to active tasks in the repository. */ + /** Adds [activeTasksListener] to be notified of updates to active tasks. */ fun addActiveTaskListener(activeTasksListener: ActiveTasksListener) { activeTasksListeners.add(activeTasksListener) } - /** Add a [VisibleTasksListener] to be notified when freeform tasks are visible or not. */ + /** Adds [visibleTasksListener] to be notified of updates to visible tasks. */ fun addVisibleTasksListener(visibleTasksListener: VisibleTasksListener, executor: Executor) { visibleTasksListeners[visibleTasksListener] = executor - displayData.keyIterator().forEach { + desktopTaskDataByDisplayId.keyIterator().forEach { + val visibleTaskCount = getVisibleTaskCount(it) executor.execute { - visibleTasksListener.onTasksVisibilityChanged(it, visibleTaskCount(it)) + visibleTasksListener.onTasksVisibilityChanged(it, visibleTaskCount) } } } - /** Returns a list of all [DisplayData]. */ - private fun displayDataList(): Sequence<DisplayData> = - displayData.valueIterator().asSequence() + /** Updates tasks changes on all the active task listeners for given display id. */ + private fun updateActiveTasksListeners(displayId: Int) { + activeTasksListeners.onEach { it.onActiveTasksChanged(displayId) } + } - /** - * Add a Consumer which will inform other classes of changes to exclusion regions for all - * Desktop tasks. - */ + /** Returns a list of all [DesktopTaskData] in the repository. */ + private fun desktopTaskDataSequence(): Sequence<DesktopTaskData> = + desktopTaskDataByDisplayId.valueIterator().asSequence() + + /** Adds [regionListener] to inform about changes to exclusion regions for all Desktop tasks. */ fun setExclusionRegionListener(regionListener: Consumer<Region>, executor: Executor) { desktopGestureExclusionListener = regionListener desktopGestureExclusionExecutor = executor @@ -111,7 +111,7 @@ class DesktopModeTaskRepository { } } - /** Create a new merged region representative of all exclusion regions in all desktop tasks. */ + /** Creates a new merged region representative of all exclusion regions in all desktop tasks. */ private fun calculateDesktopExclusionRegion(): Region { val desktopExclusionRegion = Region() desktopExclusionRegions.valueIterator().forEach { taskExclusionRegion -> @@ -120,192 +120,120 @@ class DesktopModeTaskRepository { return desktopExclusionRegion } - /** Remove a previously registered [ActiveTasksListener] */ + /** Remove the previously registered [activeTasksListener] */ fun removeActiveTasksListener(activeTasksListener: ActiveTasksListener) { activeTasksListeners.remove(activeTasksListener) } - /** Remove a previously registered [VisibleTasksListener] */ + /** Removes the previously registered [visibleTasksListener]. */ fun removeVisibleTasksListener(visibleTasksListener: VisibleTasksListener) { visibleTasksListeners.remove(visibleTasksListener) } - /** - * Mark a task with given [taskId] as active on given [displayId] - * - * @return `true` if the task was not active on given [displayId] - */ - fun addActiveTask(displayId: Int, taskId: Int): Boolean { - // Check if task is active on another display, if so, remove it - displayData.forEach { id, data -> - if (id != displayId && data.activeTasks.remove(taskId)) { - activeTasksListeners.onEach { it.onActiveTasksChanged(id) } - } - } + /** Adds task with [taskId] to the list of active tasks on [displayId]. */ + fun addActiveTask(displayId: Int, taskId: Int) { + // Removes task if it is active on another display excluding [displayId]. + removeActiveTask(taskId, excludedDisplayId = displayId) - val added = displayData.getOrCreate(displayId).activeTasks.add(taskId) - if (added) { - ProtoLog.d( - WM_SHELL_DESKTOP_MODE, - "DesktopTaskRepo: add active task=%d displayId=%d", - taskId, - displayId - ) - activeTasksListeners.onEach { it.onActiveTasksChanged(displayId) } + if (desktopTaskDataByDisplayId.getOrCreate(displayId).activeTasks.add(taskId)) { + logD("Adds active task=%d displayId=%d", taskId, displayId) + updateActiveTasksListeners(displayId) } - return added } - /** - * Remove task with given [taskId] from active tasks. - * - * @return `true` if the task was active - */ - fun removeActiveTask(taskId: Int): Boolean { - var result = false - displayData.forEach { displayId, data -> - if (data.activeTasks.remove(taskId)) { - activeTasksListeners.onEach { it.onActiveTasksChanged(displayId) } - result = true + /** Removes task from active task list of displays excluding the [excludedDisplayId]. */ + fun removeActiveTask(taskId: Int, excludedDisplayId: Int? = null) { + desktopTaskDataByDisplayId.forEach { displayId, desktopTaskData -> + if ((displayId != excludedDisplayId) + && desktopTaskData.activeTasks.remove(taskId)) { + logD("Removed active task=%d displayId=%d", taskId, displayId) + updateActiveTasksListeners(displayId) } } - if (result) { - ProtoLog.d(WM_SHELL_DESKTOP_MODE, "DesktopTaskRepo: remove active task=%d", taskId) - } - return result } - /** - * Mark a task with given [taskId] as closing on given [displayId] - * - * @return `true` if the task was not closing on given [displayId] - */ - fun addClosingTask(displayId: Int, taskId: Int): Boolean { - val added = displayData.getOrCreate(displayId).closingTasks.add(taskId) - if (added) { - ProtoLog.d( - WM_SHELL_DESKTOP_MODE, - "DesktopTaskRepo: added closing task=%d displayId=%d", - taskId, - displayId - ) + /** Adds given task to the closing task list for [displayId]. */ + fun addClosingTask(displayId: Int, taskId: Int) { + if (desktopTaskDataByDisplayId.getOrCreate(displayId).closingTasks.add(taskId)) { + logD("Added closing task=%d displayId=%d", taskId, displayId) + } else { + // If the task hasn't been removed from closing list after it disappeared. + logW("Task with taskId=%d displayId=%d is already closing", taskId, displayId) } - return added } - /** - * Remove task with given [taskId] from closing tasks. - * - * @return `true` if the task was closing - */ - fun removeClosingTask(taskId: Int): Boolean { - var removed = false - displayData.forEach { _, data -> - if (data.closingTasks.remove(taskId)) { - removed = true + /** Removes task from the list of closing tasks for [displayId]. */ + fun removeClosingTask(taskId: Int) { + desktopTaskDataByDisplayId.forEach { displayId, taskInfo -> + if (taskInfo.closingTasks.remove(taskId)) { + logD("Removed closing task=%d displayId=%d", taskId, displayId) } } - if (removed) { - ProtoLog.d(WM_SHELL_DESKTOP_MODE, "DesktopTaskRepo: remove closing task=%d", taskId) - } - return removed } - fun isActiveTask(taskId: Int) = displayDataList().any { taskId in it.activeTasks } - fun isClosingTask(taskId: Int) = displayDataList().any { taskId in it.closingTasks } - fun isVisibleTask(taskId: Int) = displayDataList().any { taskId in it.visibleTasks } - fun isMinimizedTask(taskId: Int) = displayDataList().any { taskId in it.minimizedTasks } + fun isActiveTask(taskId: Int) = desktopTaskDataSequence().any { taskId in it.activeTasks } + fun isClosingTask(taskId: Int) = desktopTaskDataSequence().any { taskId in it.closingTasks } + fun isVisibleTask(taskId: Int) = desktopTaskDataSequence().any { taskId in it.visibleTasks } + fun isMinimizedTask(taskId: Int) = desktopTaskDataSequence().any { taskId in it.minimizedTasks } - /** - * Check if a task with the given [taskId] is the only visible, non-closing, not-minimized task - * on its display - */ + /** Checks if a task is the only visible, non-closing, non-minimized task on its display. */ fun isOnlyVisibleNonClosingTask(taskId: Int): Boolean = - displayDataList().any { data -> - data.visibleTasks - .subtract(data.closingTasks) - .subtract(data.minimizedTasks) - .singleOrNull() == taskId + desktopTaskDataSequence().any { it.visibleTasks + .subtract(it.closingTasks) + .subtract(it.minimizedTasks) + .singleOrNull() == taskId } - /** Get a set of the active tasks for given [displayId] */ - fun getActiveTasks(displayId: Int): ArraySet<Int> { - return ArraySet(displayData[displayId]?.activeTasks) - } + fun getActiveTasks(displayId: Int): ArraySet<Int> = + ArraySet(desktopTaskDataByDisplayId[displayId]?.activeTasks) - /** Returns the minimized tasks for the given [displayId]. */ fun getMinimizedTasks(displayId: Int): ArraySet<Int> = - ArraySet(displayData[displayId]?.minimizedTasks) + ArraySet(desktopTaskDataByDisplayId[displayId]?.minimizedTasks) - /** - * Returns a list of Tasks IDs representing all active non-minimized Tasks on the given display, - * ordered from front to back. - */ - fun getActiveNonMinimizedTasksOrderedFrontToBack(displayId: Int): List<Int> { - val activeTasks = getActiveTasks(displayId) - val allTasksInZOrder = getFreeformTasksInZOrder(displayId) - return activeTasks - // Don't show already minimized Tasks - .filter { taskId -> !isMinimizedTask(taskId) } - .sortedBy { taskId -> allTasksInZOrder.indexOf(taskId) } - } + /** Returns all active non-minimized tasks for [displayId] ordered from top to bottom. */ + fun getActiveNonMinimizedOrderedTasks(displayId: Int): List<Int> = + getFreeformTasksInZOrder(displayId).filter { !isMinimizedTask(it) } - /** Get a list of freeform tasks, ordered from top-bottom (top at index 0). */ + /** Returns a list of freeform tasks, ordered from top-bottom (top at index 0). */ fun getFreeformTasksInZOrder(displayId: Int): ArrayList<Int> = - ArrayList(displayData[displayId]?.freeformTasksInZOrder ?: emptyList()) + ArrayList(desktopTaskDataByDisplayId[displayId]?.freeformTasksInZOrder ?: emptyList()) + + /** Removes task from visible tasks of all displays except [excludedDisplayId]. */ + private fun removeVisibleTask(taskId: Int, excludedDisplayId: Int? = null) { + desktopTaskDataByDisplayId.forEach { displayId, data -> + if ((displayId != excludedDisplayId) && data.visibleTasks.remove(taskId)) { + notifyVisibleTaskListeners(displayId, data.visibleTasks.size) + } + } + } /** - * Updates whether a freeform task with this id is visible or not and notifies listeners. + * Updates visibility of a freeform task with [taskId] on [displayId] and notifies listeners. * - * If the task was visible on a different display with a different displayId, it is removed from - * the set of visible tasks on that display. Listeners will be notified. + * If task was visible on a different display with a different [displayId], removes from + * the set of visible tasks on that display and notifies listeners. */ - fun updateVisibleFreeformTasks(displayId: Int, taskId: Int, visible: Boolean) { + fun updateTaskVisibility(displayId: Int, taskId: Int, visible: Boolean) { if (visible) { - // Task is visible. Check if we need to remove it from any other display. - val otherDisplays = displayData.keyIterator().asSequence().filter { it != displayId } - for (otherDisplayId in otherDisplays) { - if (displayData[otherDisplayId].visibleTasks.remove(taskId)) { - notifyVisibleTaskListeners( - otherDisplayId, - displayData[otherDisplayId].visibleTasks.size - ) - } - } + // If task is visible, remove it from any other display besides [displayId]. + removeVisibleTask(taskId, excludedDisplayId = displayId) } else if (displayId == INVALID_DISPLAY) { // Task has vanished. Check which display to remove the task from. - displayData.forEach { displayId, data -> - if (data.visibleTasks.remove(taskId)) { - notifyVisibleTaskListeners(displayId, data.visibleTasks.size) - } - } + removeVisibleTask(taskId) return } - - val prevCount = visibleTaskCount(displayId) + val prevCount = getVisibleTaskCount(displayId) if (visible) { - displayData.getOrCreate(displayId).visibleTasks.add(taskId) + desktopTaskDataByDisplayId.getOrCreate(displayId).visibleTasks.add(taskId) unminimizeTask(displayId, taskId) } else { - displayData[displayId]?.visibleTasks?.remove(taskId) + desktopTaskDataByDisplayId[displayId]?.visibleTasks?.remove(taskId) } - val newCount = visibleTaskCount(displayId) - - // Check if count changed + val newCount = getVisibleTaskCount(displayId) if (prevCount != newCount) { - ProtoLog.d( - WM_SHELL_DESKTOP_MODE, - "DesktopTaskRepo: update task visibility taskId=%d visible=%b displayId=%d", - taskId, - visible, - displayId - ) - ProtoLog.d( - WM_SHELL_DESKTOP_MODE, - "DesktopTaskRepo: visibleTaskCount has changed from %d to %d", - prevCount, - newCount - ) + logD("Update task visibility taskId=%d visible=%b displayId=%d", + taskId, visible, displayId) + logD("VisibleTaskCount has changed from %d to %d", prevCount, newCount) notifyVisibleTaskListeners(displayId, newCount) } } @@ -316,72 +244,80 @@ class DesktopModeTaskRepository { } } - /** Get number of tasks that are marked as visible on given [displayId] */ - fun visibleTaskCount(displayId: Int): Int { - ProtoLog.d( - WM_SHELL_DESKTOP_MODE, - "DesktopTaskRepo: visibleTaskCount= %d", - displayData[displayId]?.visibleTasks?.size ?: 0 - ) - return displayData[displayId]?.visibleTasks?.size ?: 0 - } + /** Gets number of visible tasks on given [displayId] */ + fun getVisibleTaskCount(displayId: Int): Int = + desktopTaskDataByDisplayId[displayId]?.visibleTasks?.size ?: 0.also { + logD("getVisibleTaskCount=$it") + } - /** Add (or move if it already exists) the task to the top of the ordered list. */ - // TODO(b/342417921): Identify if there is additional checks needed to move tasks for - // multi-display scenarios. + /** + * Adds task (or moves if it already exists) to the top of the ordered list. + * + * Unminimizes the task if it is minimized. + */ fun addOrMoveFreeformTaskToTop(displayId: Int, taskId: Int) { - ProtoLog.d( - WM_SHELL_DESKTOP_MODE, - "DesktopTaskRepo: add or move task to top: display=%d, taskId=%d", - displayId, - taskId - ) - displayData[displayId]?.freeformTasksInZOrder?.remove(taskId) - displayData.getOrCreate(displayId).freeformTasksInZOrder.add(0, taskId) + logD("Add or move task to top: display=%d taskId=%d", taskId, displayId) + desktopTaskDataByDisplayId[displayId]?.freeformTasksInZOrder?.remove(taskId) + desktopTaskDataByDisplayId.getOrCreate(displayId).freeformTasksInZOrder.add(0, taskId) + // Unminimize the task if it is minimized. + unminimizeTask(displayId, taskId) } - /** Mark a Task as minimized. */ + /** Minimizes the task for [taskId] and [displayId] */ fun minimizeTask(displayId: Int, taskId: Int) { - ProtoLog.v( - WM_SHELL_DESKTOP_MODE, - "DesktopModeTaskRepository: minimize Task: display=%d, task=%d", - displayId, - taskId - ) - displayData.getOrCreate(displayId).minimizedTasks.add(taskId) + logD("Minimize Task: display=%d, task=%d", displayId, taskId) + desktopTaskDataByDisplayId.getOrCreate(displayId).minimizedTasks.add(taskId) } - /** Mark a Task as non-minimized. */ + /** Unminimizes the task for [taskId] and [displayId] */ fun unminimizeTask(displayId: Int, taskId: Int) { - ProtoLog.v( - WM_SHELL_DESKTOP_MODE, - "DesktopModeTaskRepository: unminimize Task: display=%d, task=%d", - displayId, - taskId - ) - displayData[displayId]?.minimizedTasks?.remove(taskId) + logD("Unminimize Task: display=%d, task=%d", displayId, taskId) + desktopTaskDataByDisplayId[displayId]?.minimizedTasks?.remove(taskId) ?: + logW("Unminimize Task: display=%d, task=%d, no task data", displayId, taskId) + } + + private fun getDisplayIdForTask(taskId: Int): Int? { + desktopTaskDataByDisplayId.forEach { displayId, data -> + if (taskId in data.freeformTasksInZOrder) { + return displayId + } + } + logW("No display id found for task: taskId=%d", taskId) + return null } - /** Remove the task from the ordered list. */ + /** + * Removes [taskId] from the respective display. If [INVALID_DISPLAY], the original display id + * will be looked up from the task id. + */ fun removeFreeformTask(displayId: Int, taskId: Int) { - ProtoLog.d( - WM_SHELL_DESKTOP_MODE, - "DesktopTaskRepo: remove freeform task from ordered list: display=%d, taskId=%d", - displayId, - taskId - ) - displayData[displayId]?.freeformTasksInZOrder?.remove(taskId) + logD("Removes freeform task: taskId=%d", taskId) + if (displayId == INVALID_DISPLAY) { + // Removes the original display id of the task. + getDisplayIdForTask(taskId)?.let { removeTaskFromDisplay(it, taskId) } + } else { + removeTaskFromDisplay(displayId, taskId) + } + } + + /** Removes given task from a valid [displayId] and updates the repository state. */ + private fun removeTaskFromDisplay(displayId: Int, taskId: Int) { + logD("Removes freeform task: taskId=%d, displayId=%d", taskId, displayId) + desktopTaskDataByDisplayId[displayId]?.freeformTasksInZOrder?.remove(taskId) boundsBeforeMaximizeByTaskId.remove(taskId) - ProtoLog.d( - WM_SHELL_DESKTOP_MODE, - "DesktopTaskRepo: remaining freeform tasks: %s", - displayData[displayId]?.freeformTasksInZOrder?.toDumpString() ?: "" - ) + logD("Remaining freeform tasks: %s", + desktopTaskDataByDisplayId[displayId]?.freeformTasksInZOrder?.toDumpString()) + // Remove task from unminimized task if it is minimized. + unminimizeTask(displayId, taskId) + removeActiveTask(taskId) + updateTaskVisibility(displayId, taskId, visible = false); } /** - * Updates the active desktop gesture exclusion regions; if desktopExclusionRegions has been - * accepted by desktopGestureExclusionListener, it will be updated in the appropriate classes. + * Updates active desktop gesture exclusion regions. + * + * If [desktopExclusionRegions] is accepted by [desktopGestureExclusionListener], updates it in + * appropriate classes. */ fun updateTaskExclusionRegions(taskId: Int, taskExclusionRegions: Region) { desktopExclusionRegions.put(taskId, taskExclusionRegions) @@ -391,9 +327,10 @@ class DesktopModeTaskRepository { } /** - * Removes the desktop gesture exclusion region for the specified task; if exclusionRegion has - * been accepted by desktopGestureExclusionListener, it will be updated in the appropriate - * classes. + * Removes desktop gesture exclusion region for the specified task. + * + * If [desktopExclusionRegions] is accepted by [desktopGestureExclusionListener], updates it in + * appropriate classes. */ fun removeExclusionRegion(taskId: Int) { desktopExclusionRegions.delete(taskId) @@ -403,26 +340,24 @@ class DesktopModeTaskRepository { } /** Removes and returns the bounds saved before maximizing the given task. */ - fun removeBoundsBeforeMaximize(taskId: Int): Rect? { - return boundsBeforeMaximizeByTaskId.removeReturnOld(taskId) - } + fun removeBoundsBeforeMaximize(taskId: Int): Rect? = + boundsBeforeMaximizeByTaskId.removeReturnOld(taskId) /** Saves the bounds of the given task before maximizing. */ - fun saveBoundsBeforeMaximize(taskId: Int, bounds: Rect) { + fun saveBoundsBeforeMaximize(taskId: Int, bounds: Rect) = boundsBeforeMaximizeByTaskId.set(taskId, Rect(bounds)) - } internal fun dump(pw: PrintWriter, prefix: String) { val innerPrefix = "$prefix " pw.println("${prefix}DesktopModeTaskRepository") - dumpDisplayData(pw, innerPrefix) + dumpDesktopTaskData(pw, innerPrefix) pw.println("${innerPrefix}activeTasksListeners=${activeTasksListeners.size}") pw.println("${innerPrefix}visibleTasksListeners=${visibleTasksListeners.size}") } - private fun dumpDisplayData(pw: PrintWriter, prefix: String) { + private fun dumpDesktopTaskData(pw: PrintWriter, prefix: String) { val innerPrefix = "$prefix " - displayData.forEach { displayId, data -> + desktopTaskDataByDisplayId.forEach { displayId, data -> pw.println("${prefix}Display $displayId:") pw.println("${innerPrefix}activeTasks=${data.activeTasks.toDumpString()}") pw.println("${innerPrefix}visibleTasks=${data.visibleTasks.toDumpString()}") @@ -432,23 +367,29 @@ class DesktopModeTaskRepository { } } - /** - * Defines interface for classes that can listen to changes for active tasks in desktop mode. - */ + /** Listens to changes for active tasks in desktop mode. */ interface ActiveTasksListener { - /** Called when the active tasks change in desktop mode. */ fun onActiveTasksChanged(displayId: Int) {} } - /** - * Defines interface for classes that can listen to changes for visible tasks in desktop mode. - */ + /** Listens to changes for visible tasks in desktop mode. */ interface VisibleTasksListener { - /** Called when the desktop changes the number of visible freeform tasks. */ fun onTasksVisibilityChanged(displayId: Int, visibleTasksCount: Int) {} } -} -private fun <T> Iterable<T>.toDumpString(): String { - return joinToString(separator = ", ", prefix = "[", postfix = "]") + private fun logD(msg: String, vararg arguments: Any?) { + ProtoLog.d(WM_SHELL_DESKTOP_MODE, "%s: $msg", TAG, *arguments) + } + + private fun logW(msg: String, vararg arguments: Any?) { + ProtoLog.w(WM_SHELL_DESKTOP_MODE, "%s: $msg", TAG, *arguments) + } + + companion object { + private const val TAG = "DesktopModeTaskRepository" + } } + +private fun <T> Iterable<T>.toDumpString(): String = + joinToString(separator = ", ", prefix = "[", postfix = "]") + diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeUtils.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeUtils.kt index da212e704b24..9fcf73d2c375 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeUtils.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeUtils.kt @@ -52,8 +52,10 @@ fun calculateInitialBounds( val idealSize = calculateIdealSize(screenBounds, scale) // If no top activity exists, apps fullscreen bounds and aspect ratio cannot be calculated. // Instead default to the desired initial bounds. + val stableBounds = Rect() + displayLayout.getStableBoundsForDesktopMode(stableBounds) val topActivityInfo = - taskInfo.topActivityInfo ?: return positionInScreen(idealSize, screenBounds) + taskInfo.topActivityInfo ?: return positionInScreen(idealSize, stableBounds) val initialSize: Size = when (taskInfo.configuration.orientation) { @@ -100,7 +102,7 @@ fun calculateInitialBounds( } } - return positionInScreen(initialSize, screenBounds) + return positionInScreen(initialSize, stableBounds) } /** @@ -163,17 +165,11 @@ private fun calculateIdealSize(screenBounds: Rect, scale: Float): Size { } /** Adjusts bounds to be positioned in the middle of the screen. */ -private fun positionInScreen(desiredSize: Size, screenBounds: Rect): Rect { - // TODO(b/325240051): Position apps with bottom heavy offset - val heightOffset = (screenBounds.height() - desiredSize.height) / 2 - val widthOffset = (screenBounds.width() - desiredSize.width) / 2 - return Rect( - widthOffset, - heightOffset, - desiredSize.width + widthOffset, - desiredSize.height + heightOffset - ) -} +private fun positionInScreen(desiredSize: Size, stableBounds: Rect): Rect = + Rect(0, 0, desiredSize.width, desiredSize.height).apply { + val offset = DesktopTaskPosition.Center.getTopLeftCoordinates(stableBounds, this) + offsetTo(offset.x, offset.y) + } /** * Adjusts bounds to be positioned in the middle of the area provided, not necessarily the diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicator.java index ed0d2b87b03f..6011db7fc752 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicator.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicator.java @@ -105,7 +105,7 @@ public class DesktopModeVisualIndicator { // If we are in freeform, we don't want a visible indicator in the "freeform" drag zone. IndicatorType result = IndicatorType.NO_INDICATOR; final int transitionAreaWidth = mContext.getResources().getDimensionPixelSize( - com.android.wm.shell.R.dimen.desktop_mode_transition_area_width); + com.android.wm.shell.R.dimen.desktop_mode_transition_region_thickness); // Because drags in freeform use task position for indicator calculation, we need to // account for the possibility of the task going off the top of the screen by captionHeight final int captionHeight = mContext.getResources().getDimensionPixelSize( @@ -140,18 +140,19 @@ public class DesktopModeVisualIndicator { final Region region = new Region(); int transitionHeight = windowingMode == WINDOWING_MODE_FREEFORM ? mContext.getResources().getDimensionPixelSize( - com.android.wm.shell.R.dimen.desktop_mode_fullscreen_from_desktop_height) + com.android.wm.shell.R.dimen.desktop_mode_transition_region_thickness) : 2 * layout.stableInsets().top; - // A thin, short Rect at the top of the screen. + // A Rect at the top of the screen that takes up the center 40%. if (windowingMode == WINDOWING_MODE_FREEFORM) { - int fromFreeformWidth = mContext.getResources().getDimensionPixelSize( - com.android.wm.shell.R.dimen.desktop_mode_fullscreen_from_desktop_width); - region.union(new Rect((layout.width() / 2) - (fromFreeformWidth / 2), + final float toFullscreenScale = mContext.getResources().getFloat( + R.dimen.desktop_mode_fullscreen_region_scale); + final float toFullscreenWidth = (layout.width() * toFullscreenScale); + region.union(new Rect((int) ((layout.width() / 2f) - (toFullscreenWidth / 2f)), -captionHeight, - (layout.width() / 2) + (fromFreeformWidth / 2), + (int) ((layout.width() / 2f) + (toFullscreenWidth / 2f)), transitionHeight)); } - // A screen-wide, shorter Rect if the task is in fullscreen or split. + // A screen-wide Rect if the task is in fullscreen or split. if (windowingMode == WINDOWING_MODE_FULLSCREEN || windowingMode == WINDOWING_MODE_MULTI_WINDOW) { region.union(new Rect(0, diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTaskPosition.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTaskPosition.kt new file mode 100644 index 000000000000..97abda81d12d --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTaskPosition.kt @@ -0,0 +1,151 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.wm.shell.desktopmode + +import android.app.TaskInfo +import android.content.res.Resources +import android.graphics.Point +import android.graphics.Rect +import android.view.Gravity +import com.android.internal.annotations.VisibleForTesting +import com.android.wm.shell.desktopmode.DesktopTaskPosition.BottomLeft +import com.android.wm.shell.desktopmode.DesktopTaskPosition.BottomRight +import com.android.wm.shell.desktopmode.DesktopTaskPosition.Center +import com.android.wm.shell.desktopmode.DesktopTaskPosition.TopLeft +import com.android.wm.shell.desktopmode.DesktopTaskPosition.TopRight +import com.android.wm.shell.R + +/** + * The position of a task window in desktop mode. + */ +sealed class DesktopTaskPosition { + data object Center : DesktopTaskPosition() { + private const val WINDOW_HEIGHT_PROPORTION = 0.375 + + override fun getTopLeftCoordinates(frame: Rect, window: Rect): Point { + val x = (frame.width() - window.width()) / 2 + // Position with more margin at the bottom. + val y = (frame.height() - window.height()) * WINDOW_HEIGHT_PROPORTION + frame.top + return Point(x, y.toInt()) + } + + override fun next(): DesktopTaskPosition { + return BottomRight + } + } + + data object BottomRight : DesktopTaskPosition() { + override fun getTopLeftCoordinates(frame: Rect, window: Rect): Point { + return Point(frame.right - window.width(), frame.bottom - window.height()) + } + + override fun next(): DesktopTaskPosition { + return TopLeft + } + } + + data object TopLeft : DesktopTaskPosition() { + override fun getTopLeftCoordinates(frame: Rect, window: Rect): Point { + return Point(frame.left, frame.top) + } + + override fun next(): DesktopTaskPosition { + return BottomLeft + } + } + + data object BottomLeft : DesktopTaskPosition() { + override fun getTopLeftCoordinates(frame: Rect, window: Rect): Point { + return Point(frame.left, frame.bottom - window.height()) + } + + override fun next(): DesktopTaskPosition { + return TopRight + } + } + + data object TopRight : DesktopTaskPosition() { + override fun getTopLeftCoordinates(frame: Rect, window: Rect): Point { + return Point(frame.right - window.width(), frame.top) + } + + override fun next(): DesktopTaskPosition { + return Center + } + } + + /** + * Returns the top left coordinates for the window to be placed in the given + * DesktopTaskPosition in the frame. + */ + abstract fun getTopLeftCoordinates(frame: Rect, window: Rect): Point + + abstract fun next(): DesktopTaskPosition +} + +/** + * If the app has specified horizontal or vertical gravity layout, don't change the + * task position for cascading effect. + */ +fun canChangeTaskPosition(taskInfo: TaskInfo): Boolean { + taskInfo.topActivityInfo?.windowLayout?.let { + val horizontalGravityApplied = it.gravity.and(Gravity.HORIZONTAL_GRAVITY_MASK) + val verticalGravityApplied = it.gravity.and(Gravity.VERTICAL_GRAVITY_MASK) + return horizontalGravityApplied == 0 && verticalGravityApplied == 0 + } + return true +} + +/** + * Returns the current DesktopTaskPosition for a given window in the frame. + */ +@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) +fun Rect.getDesktopTaskPosition(bounds: Rect): DesktopTaskPosition { + return when { + top == bounds.top && left == bounds.left -> TopLeft + top == bounds.top && right == bounds.right -> TopRight + bottom == bounds.bottom && left == bounds.left -> BottomLeft + bottom == bounds.bottom && right == bounds.right -> BottomRight + else -> Center + } +} + +internal fun cascadeWindow(res: Resources, frame: Rect, prev: Rect, dest: Rect) { + val candidateBounds = Rect(dest) + val lastPos = frame.getDesktopTaskPosition(prev) + var destCoord = Center.getTopLeftCoordinates(frame, candidateBounds) + candidateBounds.offsetTo(destCoord.x, destCoord.y) + // If the default center position is not free or if last focused window is not at the + // center, get the next cascading window position. + if (!prevBoundsMovedAboveThreshold(res, prev, candidateBounds) || Center != lastPos) { + val nextCascadingPos = lastPos.next() + destCoord = nextCascadingPos.getTopLeftCoordinates(frame, dest) + } + dest.offsetTo(destCoord.x, destCoord.y) +} + +internal fun prevBoundsMovedAboveThreshold(res: Resources, prev: Rect, newBounds: Rect): Boolean { + // This is the required minimum dp for a task to be touchable. + val moveThresholdPx = res.getDimensionPixelSize( + R.dimen.freeform_required_visible_empty_space_in_header) + val leftFar = newBounds.left - prev.left > moveThresholdPx + val topFar = newBounds.top - prev.top > moveThresholdPx + val rightFar = prev.right - newBounds.right > moveThresholdPx + val bottomFar = prev.bottom - newBounds.bottom > moveThresholdPx + + return leftFar || topFar || rightFar || bottomFar +} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt index 2ef045d9fb89..5f838d3adb3c 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt @@ -121,7 +121,7 @@ class DesktopTasksController( private val exitDesktopTaskTransitionHandler: ExitDesktopTaskTransitionHandler, private val toggleResizeDesktopTaskTransitionHandler: ToggleResizeDesktopTaskTransitionHandler, private val dragToDesktopTransitionHandler: DragToDesktopTransitionHandler, - private val desktopModeTaskRepository: DesktopModeTaskRepository, + private val taskRepository: DesktopModeTaskRepository, private val desktopModeLoggerTransitionObserver: DesktopModeLoggerTransitionObserver, private val launchAdjacentController: LaunchAdjacentController, private val recentsTransitionHandler: RecentsTransitionHandler, @@ -181,7 +181,7 @@ class DesktopTasksController( } private fun onInit() { - ProtoLog.d(WM_SHELL_DESKTOP_MODE, "Initialize DesktopTasksController") + logD("onInit") shellCommandHandler.addDumpCallback(this::dump, this) shellCommandHandler.addCommandCallback("desktopmode", desktopModeShellCommandHandler, this) shellController.addExternalInterface( @@ -190,16 +190,12 @@ class DesktopTasksController( this ) transitions.addHandler(this) - desktopModeTaskRepository.addVisibleTasksListener(taskVisibilityListener, mainExecutor) + taskRepository.addVisibleTasksListener(taskVisibilityListener, mainExecutor) dragToDesktopTransitionHandler.setDragToDesktopStateListener(dragToDesktopStateListener) recentsTransitionHandler.addTransitionStateListener( object : RecentsTransitionStateListener { override fun onAnimationStateChanged(running: Boolean) { - ProtoLog.v( - WM_SHELL_DESKTOP_MODE, - "DesktopTasksController: recents animation state changed running=%b", - running - ) + logV("Recents animation state changed running=%b", running) recentsAnimationRunning = running } } @@ -227,7 +223,7 @@ class DesktopTasksController( /** Returns the transition type for the given remote transition. */ private fun transitionType(remoteTransition: RemoteTransition?): Int { if (remoteTransition == null) { - ProtoLog.v(WM_SHELL_DESKTOP_MODE, "DesktopTasksController: remoteTransition is null") + logV("RemoteTransition is null") return TRANSIT_NONE } return TRANSIT_TO_FRONT @@ -235,7 +231,7 @@ class DesktopTasksController( /** Show all tasks, that are part of the desktop, on top of launcher */ fun showDesktopApps(displayId: Int, remoteTransition: RemoteTransition? = null) { - ProtoLog.v(WM_SHELL_DESKTOP_MODE, "DesktopTasksController: showDesktopApps") + logV("showDesktopApps") val wct = WindowContainerTransaction() bringDesktopAppsToFront(displayId, wct) @@ -255,7 +251,7 @@ class DesktopTasksController( /** Gets number of visible tasks in [displayId]. */ fun visibleTaskCount(displayId: Int): Int = - desktopModeTaskRepository.visibleTaskCount(displayId) + taskRepository.getVisibleTaskCount(displayId) /** Returns true if any tasks are visible in Desktop Mode. */ fun isDesktopModeShowing(displayId: Int): Boolean = visibleTaskCount(displayId) > 0 @@ -286,14 +282,8 @@ class DesktopTasksController( // Fullscreen case where we move the current focused task. moveToDesktop(allFocusedTasks[0].taskId, transitionSource = transitionSource) } - else -> { - ProtoLog.w( - WM_SHELL_DESKTOP_MODE, - "DesktopTasksController: Cannot enter desktop, expected less " + - "than 3 focused tasks but found %d", - allFocusedTasks.size - ) - } + else -> logW("Cannot enter desktop, expected < 3 focused tasks, found %d", + allFocusedTasks.size) } } } @@ -317,11 +307,7 @@ class DesktopTasksController( transitionSource: DesktopModeTransitionSource, ): Boolean { recentTasksController?.findTaskInBackground(taskId)?.let { - ProtoLog.v( - WM_SHELL_DESKTOP_MODE, - "DesktopTasksController: moveToDesktopFromNonRunningTask taskId=%d", - taskId - ) + logV("moveToDesktopFromNonRunningTask with taskId=%d, displayId=%d", taskId) // TODO(342378842): Instead of using default display, support multiple displays val taskToMinimize = bringDesktopAppsToFrontBeforeShowingNewTask(DEFAULT_DISPLAY, wct, taskId) @@ -351,18 +337,10 @@ class DesktopTasksController( ) { if (DesktopModeFlags.MODALS_POLICY.isEnabled(context) && isTopActivityExemptFromDesktopWindowing(context, task)) { - ProtoLog.w( - WM_SHELL_DESKTOP_MODE, - "DesktopTasksController: Cannot enter desktop, " + - "ineligible top activity found." - ) + logW("Cannot enter desktop for taskId %d, ineligible top activity found", task.taskId) return } - ProtoLog.v( - WM_SHELL_DESKTOP_MODE, - "DesktopTasksController: moveToDesktop taskId=%d", - task.taskId - ) + logV("moveToDesktop taskId=%d", task.taskId) exitSplitIfApplicable(wct, task) // Bring other apps to front first val taskToMinimize = @@ -386,11 +364,7 @@ class DesktopTasksController( dragToDesktopValueAnimator: MoveToDesktopAnimator, taskSurface: SurfaceControl, ) { - ProtoLog.v( - WM_SHELL_DESKTOP_MODE, - "DesktopTasksController: startDragToDesktop taskId=%d", - taskInfo.taskId - ) + logV("startDragToDesktop taskId=%d", taskInfo.taskId) interactionJankMonitor.begin(taskSurface, context, CUJ_DESKTOP_MODE_ENTER_APP_HANDLE_DRAG_HOLD) dragToDesktopTransitionHandler.startDragToDesktopTransition( @@ -403,7 +377,7 @@ class DesktopTasksController( * The second part of the animated drag to desktop transition, called after * [startDragToDesktop]. */ - private fun finalizeDragToDesktop(taskInfo: RunningTaskInfo, freeformBounds: Rect) { + private fun finalizeDragToDesktop(taskInfo: RunningTaskInfo) { ProtoLog.v( WM_SHELL_DESKTOP_MODE, "DesktopTasksController: finalizeDragToDesktop taskId=%d", @@ -415,7 +389,6 @@ class DesktopTasksController( val taskToMinimize = bringDesktopAppsToFrontBeforeShowingNewTask(taskInfo.displayId, wct, taskInfo.taskId) addMoveToDesktopChanges(wct, taskInfo) - wct.setBounds(taskInfo.token, freeformBounds) val transition = dragToDesktopTransitionHandler.finishDragToDesktopTransition(wct) transition?.let { addPendingMinimizeTransition(it, taskToMinimize) } } @@ -443,17 +416,10 @@ class DesktopTasksController( * @param taskId task id of the window that's being closed */ fun onDesktopWindowClose(wct: WindowContainerTransaction, displayId: Int, taskId: Int) { - if (desktopModeTaskRepository.isOnlyVisibleNonClosingTask(taskId)) { + if (taskRepository.isOnlyVisibleNonClosingTask(taskId)) { removeWallpaperActivity(wct) } - if (!desktopModeTaskRepository.addClosingTask(displayId, taskId)) { - // Could happen if the task hasn't been removed from closing list after it disappeared - ProtoLog.w( - WM_SHELL_DESKTOP_MODE, - "DesktopTasksController: the task with taskId=%d is already closing!", - taskId - ) - } + taskRepository.addClosingTask(displayId, taskId) } /** Move a task with given `taskId` to fullscreen */ @@ -472,11 +438,7 @@ class DesktopTasksController( /** Move a desktop app to split screen. */ fun moveToSplit(task: RunningTaskInfo) { - ProtoLog.v( - WM_SHELL_DESKTOP_MODE, - "DesktopTasksController: moveToSplit taskId=%d", - task.taskId - ) + logV( "moveToSplit taskId=%s", task.taskId) val wct = WindowContainerTransaction() wct.setBounds(task.token, Rect()) // Rather than set windowing mode to multi-window at task level, set it to @@ -505,11 +467,7 @@ class DesktopTasksController( * [startDragToDesktop]. */ fun cancelDragToDesktop(task: RunningTaskInfo) { - ProtoLog.v( - WM_SHELL_DESKTOP_MODE, - "DesktopTasksController: cancelDragToDesktop taskId=%d", - task.taskId - ) + logV("cancelDragToDesktop taskId=%d", task.taskId) dragToDesktopTransitionHandler.cancelDragToDesktopTransition( DragToDesktopTransitionHandler.CancelState.STANDARD_CANCEL ) @@ -520,11 +478,7 @@ class DesktopTasksController( position: Point, transitionSource: DesktopModeTransitionSource ) { - ProtoLog.v( - WM_SHELL_DESKTOP_MODE, - "DesktopTasksController: moveToFullscreen with animation taskId=%d", - task.taskId - ) + logV("moveToFullscreenWithAnimation taskId=%d", task.taskId) val wct = WindowContainerTransaction() addMoveToFullscreenChanges(wct, task) @@ -548,12 +502,7 @@ class DesktopTasksController( /** Move a task to the front */ fun moveTaskToFront(taskInfo: RunningTaskInfo) { - ProtoLog.v( - WM_SHELL_DESKTOP_MODE, - "DesktopTasksController: moveTaskToFront taskId=%d", - taskInfo.taskId - ) - + logV("moveTaskToFront taskId=%s", taskInfo.taskId) val wct = WindowContainerTransaction() wct.reorder(taskInfo.token, true) val taskToMinimize = addAndGetMinimizeChangesIfNeeded(taskInfo.displayId, wct, taskInfo) @@ -579,15 +528,10 @@ class DesktopTasksController( fun moveToNextDisplay(taskId: Int) { val task = shellTaskOrganizer.getRunningTaskInfo(taskId) if (task == null) { - ProtoLog.w(WM_SHELL_DESKTOP_MODE, "moveToNextDisplay: taskId=%d not found", taskId) + logW("moveToNextDisplay: taskId=%d not found", taskId) return } - ProtoLog.v( - WM_SHELL_DESKTOP_MODE, - "moveToNextDisplay: taskId=%d taskDisplayId=%d", - taskId, - task.displayId - ) + logV("moveToNextDisplay: taskId=%d displayId=%d", taskId, task.displayId) val displayIds = rootTaskDisplayAreaOrganizer.displayIds.sorted() // Get the first display id that is higher than current task display id @@ -597,7 +541,7 @@ class DesktopTasksController( newDisplayId = displayIds.firstOrNull { displayId -> displayId < task.displayId } } if (newDisplayId == null) { - ProtoLog.w(WM_SHELL_DESKTOP_MODE, "moveToNextDisplay: next display not found") + logW("moveToNextDisplay: next display not found") return } moveToDisplay(task, newDisplayId) @@ -609,21 +553,15 @@ class DesktopTasksController( * No-op if task is already on that display per [RunningTaskInfo.displayId]. */ private fun moveToDisplay(task: RunningTaskInfo, displayId: Int) { - ProtoLog.v( - WM_SHELL_DESKTOP_MODE, - "moveToDisplay: taskId=%d displayId=%d", - task.taskId, - displayId - ) - + logV("moveToDisplay: taskId=%d displayId=%d", task.taskId, displayId) if (task.displayId == displayId) { - ProtoLog.d(WM_SHELL_DESKTOP_MODE, "moveToDisplay: task already on display") + logD("moveToDisplay: task already on display %d", displayId) return } val displayAreaInfo = rootTaskDisplayAreaOrganizer.getDisplayAreaInfo(displayId) if (displayAreaInfo == null) { - ProtoLog.w(WM_SHELL_DESKTOP_MODE, "moveToDisplay: display not found") + logW("moveToDisplay: display not found") return } @@ -660,7 +598,7 @@ class DesktopTasksController( // If the task's pre-maximize stable bounds were saved, toggle the task to those bounds. // Otherwise, toggle to the default bounds. val taskBoundsBeforeMaximize = - desktopModeTaskRepository.removeBoundsBeforeMaximize(taskInfo.taskId) + taskRepository.removeBoundsBeforeMaximize(taskInfo.taskId) if (taskBoundsBeforeMaximize != null) { destinationBounds.set(taskBoundsBeforeMaximize) } else { @@ -673,7 +611,7 @@ class DesktopTasksController( } else { // Save current bounds so that task can be restored back to original bounds if necessary // and toggle to the stable bounds. - desktopModeTaskRepository.saveBoundsBeforeMaximize(taskInfo.taskId, currentTaskBounds) + taskRepository.saveBoundsBeforeMaximize(taskInfo.taskId, currentTaskBounds) if (taskInfo.isResizeable) { // if resizable then expand to entire stable bounds (full display minus insets) @@ -778,12 +716,7 @@ class DesktopTasksController( wct: WindowContainerTransaction, newTaskIdInFront: Int? = null ): RunningTaskInfo? { - ProtoLog.v( - WM_SHELL_DESKTOP_MODE, - "DesktopTasksController: bringDesktopAppsToFront, newTaskIdInFront=%s", - newTaskIdInFront ?: "null" - ) - + logV("bringDesktopAppsToFront, newTaskId=%d", newTaskIdInFront) // Move home to front, ensures that we go back home when all desktop windows are closed moveHomeTask(wct, toTop = true) @@ -794,7 +727,7 @@ class DesktopTasksController( } val nonMinimizedTasksOrderedFrontToBack = - desktopModeTaskRepository.getActiveNonMinimizedTasksOrderedFrontToBack(displayId) + taskRepository.getActiveNonMinimizedOrderedTasks(displayId) // If we're adding a new Task we might need to minimize an old one val taskToMinimize: RunningTaskInfo? = if (newTaskIdInFront != null && desktopTasksLimiter.isPresent) { @@ -812,7 +745,7 @@ class DesktopTasksController( .filter { taskId -> taskId != taskToMinimize?.taskId } .mapNotNull { taskId -> shellTaskOrganizer.getRunningTaskInfo(taskId) } .reversed() // Start from the back so the front task is brought forward last - .forEach { task -> wct.reorder(task.token, true /* onTop */) } + .forEach { task -> wct.reorder(task.token, /* onTop= */ true) } return taskToMinimize } @@ -820,11 +753,11 @@ class DesktopTasksController( shellTaskOrganizer .getRunningTasks(context.displayId) .firstOrNull { task -> task.activityType == ACTIVITY_TYPE_HOME } - ?.let { homeTask -> wct.reorder(homeTask.getToken(), toTop /* onTop */) } + ?.let { homeTask -> wct.reorder(homeTask.getToken(), /* onTop= */ toTop) } } private fun addWallpaperActivity(wct: WindowContainerTransaction) { - ProtoLog.v(WM_SHELL_DESKTOP_MODE, "DesktopTasksController: addWallpaper") + logV("addWallpaperActivity") val intent = Intent(context, DesktopWallpaperActivity::class.java) val options = ActivityOptions.makeBasic().apply { @@ -842,8 +775,8 @@ class DesktopTasksController( } private fun removeWallpaperActivity(wct: WindowContainerTransaction) { - desktopModeTaskRepository.wallpaperActivityToken?.let { token -> - ProtoLog.v(WM_SHELL_DESKTOP_MODE, "DesktopTasksController: removeWallpaper") + taskRepository.wallpaperActivityToken?.let { token -> + logV("removeWallpaperActivity") wct.removeTask(token) } } @@ -881,11 +814,7 @@ class DesktopTasksController( transition: IBinder, request: TransitionRequestInfo ): WindowContainerTransaction? { - ProtoLog.v( - WM_SHELL_DESKTOP_MODE, - "DesktopTasksController: handleRequest request=%s", - request - ) + logV("handleRequest request=%s", request) // Check if we should skip handling this transition var reason = "" val triggerTask = request.triggerTask @@ -923,11 +852,7 @@ class DesktopTasksController( } if (!shouldHandleRequest) { - ProtoLog.v( - WM_SHELL_DESKTOP_MODE, - "DesktopTasksController: skipping handleRequest reason=%s", - reason - ) + logV("skipping handleRequest reason=%s", reason) return null } @@ -947,11 +872,7 @@ class DesktopTasksController( } } } - ProtoLog.v( - WM_SHELL_DESKTOP_MODE, - "DesktopTasksController: handleRequest result=%s", - result ?: "null" - ) + logV("handleRequest result=%s", result) return result } @@ -985,25 +906,20 @@ class DesktopTasksController( task: RunningTaskInfo, transition: IBinder ): WindowContainerTransaction? { - ProtoLog.v(WM_SHELL_DESKTOP_MODE, "DesktopTasksController: handleFreeformTaskLaunch") + logV("handleFreeformTaskLaunch") if (keyguardManager.isKeyguardLocked) { // Do NOT handle freeform task launch when locked. // It will be launched in fullscreen windowing mode (Details: b/160925539) - ProtoLog.v(WM_SHELL_DESKTOP_MODE, "DesktopTasksController: skip keyguard is locked") + logV("skip keyguard is locked") return null } val wct = WindowContainerTransaction() if (!isDesktopModeShowing(task.displayId)) { - ProtoLog.d( - WM_SHELL_DESKTOP_MODE, - "DesktopTasksController: bring desktop tasks to front on transition" + - " taskId=%d", - task.taskId - ) + logD("Bring desktop tasks to front on transition=taskId=%d", task.taskId) // We are outside of desktop mode and already existing desktop task is being launched. // We should make this task go to fullscreen instead of freeform. Note that this means // any re-launch of a freeform window outside of desktop will be in fullscreen. - if (desktopModeTaskRepository.isActiveTask(task.taskId)) { + if (taskRepository.isActiveTask(task.taskId)) { addMoveToFullscreenChanges(wct, task) return wct } @@ -1028,14 +944,9 @@ class DesktopTasksController( task: RunningTaskInfo, transition: IBinder ): WindowContainerTransaction? { - ProtoLog.v(WM_SHELL_DESKTOP_MODE, "DesktopTasksController: handleFullscreenTaskLaunch") + logV("handleFullscreenTaskLaunch") if (isDesktopModeShowing(task.displayId)) { - ProtoLog.d( - WM_SHELL_DESKTOP_MODE, - "DesktopTasksController: switch fullscreen task to freeform on transition" + - " taskId=%d", - task.taskId - ) + logD("Switch fullscreen task to freeform on transition: taskId=%d", task.taskId) return WindowContainerTransaction().also { wct -> addMoveToDesktopChanges(wct, task) // In some launches home task is moved behind new task being launched. Make sure @@ -1062,33 +973,28 @@ class DesktopTasksController( /** Handle task closing by removing wallpaper activity if it's the last active task */ private fun handleTaskClosing(task: RunningTaskInfo): WindowContainerTransaction? { - ProtoLog.v(WM_SHELL_DESKTOP_MODE, "DesktopTasksController: handleTaskClosing") + logV("handleTaskClosing") val wct = WindowContainerTransaction() - if (desktopModeTaskRepository.isOnlyVisibleNonClosingTask(task.taskId) - && desktopModeTaskRepository.wallpaperActivityToken != null) { + if (taskRepository.isOnlyVisibleNonClosingTask(task.taskId) + && taskRepository.wallpaperActivityToken != null) { // Remove wallpaper activity when the last active task is removed removeWallpaperActivity(wct) } - if (!desktopModeTaskRepository.addClosingTask(task.displayId, task.taskId)) { - // Could happen if the task hasn't been removed from closing list after it disappeared - ProtoLog.w( - WM_SHELL_DESKTOP_MODE, - "DesktopTasksController: the task with taskId=%d is already closing!", - task.taskId - ) - } + taskRepository.addClosingTask(task.displayId, task.taskId) // If a CLOSE or TO_BACK is triggered on a desktop task, remove the task. if (Flags.enableDesktopWindowingBackNavigation() && - desktopModeTaskRepository.isVisibleTask(task.taskId)) { + taskRepository.isVisibleTask(task.taskId)) { wct.removeTask(task.token) } return if (wct.isEmpty) null else wct } - private fun addMoveToDesktopChanges( + @VisibleForTesting + fun addMoveToDesktopChanges( wct: WindowContainerTransaction, taskInfo: RunningTaskInfo ) { + val displayLayout = displayController.getDisplayLayout(taskInfo.displayId) ?: return val tdaInfo = rootTaskDisplayAreaOrganizer.getDisplayAreaInfo(taskInfo.displayId)!! val tdaWindowingMode = tdaInfo.configuration.windowConfiguration.windowingMode val targetWindowingMode = @@ -1098,6 +1004,28 @@ class DesktopTasksController( } else { WINDOWING_MODE_FREEFORM } + val initialBounds = if (DesktopModeFlags.DYNAMIC_INITIAL_BOUNDS.isEnabled(context)) { + calculateInitialBounds(displayLayout, taskInfo) + } else { + getDefaultDesktopTaskBounds(displayLayout) + } + + if (DesktopModeFlags.CASCADING_WINDOWS.isEnabled(context)) { + val stableBounds = Rect() + displayLayout.getStableBoundsForDesktopMode(stableBounds) + + val activeTasks = taskRepository + .getActiveNonMinimizedOrderedTasks(taskInfo.displayId) + activeTasks.firstOrNull()?.let { activeTask -> + shellTaskOrganizer.getRunningTaskInfo(activeTask)?.let { + cascadeWindow(context.resources, stableBounds, + it.configuration.windowConfiguration.bounds, initialBounds) + } + } + } + if (canChangeTaskPosition(taskInfo)) { + wct.setBounds(taskInfo.token, initialBounds) + } wct.setWindowingMode(taskInfo.token, targetWindowingMode) wct.reorder(taskInfo.token, true /* onTop */) if (useDesktopOverrideDensity()) { @@ -1123,7 +1051,7 @@ class DesktopTasksController( if (useDesktopOverrideDensity()) { wct.setDensityDpi(taskInfo.token, getDefaultDensityDpi()) } - if (desktopModeTaskRepository.isOnlyVisibleNonClosingTask(taskInfo.taskId)) { + if (taskRepository.isOnlyVisibleNonClosingTask(taskInfo.taskId)) { // Remove wallpaper activity when leaving desktop mode removeWallpaperActivity(wct) } @@ -1142,7 +1070,7 @@ class DesktopTasksController( // The task's density may have been overridden in freeform; revert it here as we don't // want it overridden in multi-window. wct.setDensityDpi(taskInfo.token, getDefaultDensityDpi()) - if (desktopModeTaskRepository.isOnlyVisibleNonClosingTask(taskInfo.taskId)) { + if (taskRepository.isOnlyVisibleNonClosingTask(taskInfo.taskId)) { // Remove wallpaper activity when leaving desktop mode removeWallpaperActivity(wct) } @@ -1357,16 +1285,10 @@ class DesktopTasksController( val indicatorType = indicator.updateIndicatorType(inputCoordinates, taskInfo.windowingMode) when (indicatorType) { IndicatorType.TO_DESKTOP_INDICATOR -> { - val displayLayout = displayController.getDisplayLayout(taskInfo.displayId) - ?: return IndicatorType.NO_INDICATOR // Start a new jank interaction for the drag release to desktop window animation. interactionJankMonitor.begin(taskSurface, context, CUJ_DESKTOP_MODE_ENTER_APP_HANDLE_DRAG_RELEASE, "to_desktop") - if (DesktopModeFlags.DYNAMIC_INITIAL_BOUNDS.isEnabled(context)) { - finalizeDragToDesktop(taskInfo, calculateInitialBounds(displayLayout, taskInfo)) - } else { - finalizeDragToDesktop(taskInfo, getDefaultDesktopTaskBounds(displayLayout)) - } + finalizeDragToDesktop(taskInfo) } IndicatorType.NO_INDICATOR, IndicatorType.TO_FULLSCREEN_INDICATOR -> { @@ -1384,12 +1306,12 @@ class DesktopTasksController( /** Update the exclusion region for a specified task */ fun onExclusionRegionChanged(taskId: Int, exclusionRegion: Region) { - desktopModeTaskRepository.updateTaskExclusionRegions(taskId, exclusionRegion) + taskRepository.updateTaskExclusionRegions(taskId, exclusionRegion) } /** Remove a previously tracked exclusion region for a specified task. */ fun removeExclusionRegionForTask(taskId: Int) { - desktopModeTaskRepository.removeExclusionRegion(taskId) + taskRepository.removeExclusionRegion(taskId) } /** @@ -1399,7 +1321,7 @@ class DesktopTasksController( * @param callbackExecutor the executor to call the listener on. */ fun addVisibleTasksListener(listener: VisibleTasksListener, callbackExecutor: Executor) { - desktopModeTaskRepository.addVisibleTasksListener(listener, callbackExecutor) + taskRepository.addVisibleTasksListener(listener, callbackExecutor) } /** @@ -1409,7 +1331,7 @@ class DesktopTasksController( * @param callbackExecutor the executor to call the listener on. */ fun setTaskRegionListener(listener: Consumer<Region>, callbackExecutor: Executor) { - desktopModeTaskRepository.setExclusionRegionListener(listener, callbackExecutor) + taskRepository.setExclusionRegionListener(listener, callbackExecutor) } override fun onUnhandledDrag( @@ -1427,7 +1349,7 @@ class DesktopTasksController( if (!multiInstanceHelper.supportsMultiInstanceSplit(launchComponent)) { // TODO(b/320797628): Should only return early if there is an existing running task, and // notify the user as well. But for now, just ignore the drop. - ProtoLog.v(WM_SHELL_DESKTOP_MODE, "Dropped intent does not support multi-instance") + logV("Dropped intent does not support multi-instance") return false } @@ -1459,7 +1381,7 @@ class DesktopTasksController( private fun dump(pw: PrintWriter, prefix: String) { val innerPrefix = "$prefix " pw.println("${prefix}DesktopTasksController") - desktopModeTaskRepository.dump(pw, innerPrefix) + taskRepository.dump(pw, innerPrefix) } /** The interface for calls from outside the shell, within the host process. */ @@ -1534,12 +1456,12 @@ class DesktopTasksController( SingleInstanceRemoteListener<DesktopTasksController, IDesktopTaskListener>( controller, { c -> - c.desktopModeTaskRepository.addVisibleTasksListener( + c.taskRepository.addVisibleTasksListener( listener, c.mainExecutor ) }, - { c -> c.desktopModeTaskRepository.removeVisibleTasksListener(listener) } + { c -> c.taskRepository.removeVisibleTasksListener(listener) } ) } @@ -1566,10 +1488,7 @@ class DesktopTasksController( } override fun hideStashedDesktopApps(displayId: Int) { - ProtoLog.w( - WM_SHELL_DESKTOP_MODE, - "IDesktopModeImpl: hideStashedDesktopApps is deprecated" - ) + ProtoLog.w(WM_SHELL_DESKTOP_MODE, "IDesktopModeImpl: hideStashedDesktopApps is deprecated") } override fun getVisibleTaskCount(displayId: Int): Int { @@ -1593,11 +1512,7 @@ class DesktopTasksController( } override fun setTaskListener(listener: IDesktopTaskListener?) { - ProtoLog.v( - WM_SHELL_DESKTOP_MODE, - "IDesktopModeImpl: set task listener=%s", - listener ?: "null" - ) + ProtoLog.v(WM_SHELL_DESKTOP_MODE, "IDesktopModeImpl: set task listener=%s", listener) executeRemoteCallWithTaskPermission(controller, "setTaskListener") { _ -> listener?.let { remoteListener.register(it) } ?: remoteListener.unregister() } @@ -1610,10 +1525,22 @@ class DesktopTasksController( } } + private fun logV(msg: String, vararg arguments: Any?) { + ProtoLog.v(WM_SHELL_DESKTOP_MODE, "%s: $msg", TAG, *arguments) + } + private fun logD(msg: String, vararg arguments: Any?) { + ProtoLog.d(WM_SHELL_DESKTOP_MODE, "%s: $msg", TAG, *arguments) + } + private fun logW(msg: String, vararg arguments: Any?) { + ProtoLog.w(WM_SHELL_DESKTOP_MODE, "%s: $msg", TAG, *arguments) + } + companion object { @JvmField val DESKTOP_MODE_INITIAL_BOUNDS_SCALE = SystemProperties.getInt("persist.wm.debug.desktop_mode_initial_bounds_scale", 75) / 100f + + private const val TAG = "DesktopTasksController" } /** The positions on a screen that a task can snap to. */ diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksLimiter.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksLimiter.kt index c5ed1be004e5..38675129ce57 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksLimiter.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksLimiter.kt @@ -17,12 +17,15 @@ package com.android.wm.shell.desktopmode import android.app.ActivityManager.RunningTaskInfo +import android.content.Context import android.os.IBinder import android.view.SurfaceControl import android.view.WindowManager.TRANSIT_TO_BACK import android.window.TransitionInfo import android.window.WindowContainerTransaction import androidx.annotation.VisibleForTesting +import com.android.internal.jank.Cuj.CUJ_DESKTOP_MODE_MINIMIZE_WINDOW +import com.android.internal.jank.InteractionJankMonitor import com.android.internal.protolog.ProtoLog import com.android.wm.shell.ShellTaskOrganizer import com.android.wm.shell.protolog.ShellProtoLogGroup @@ -33,13 +36,16 @@ import com.android.wm.shell.transition.Transitions.TransitionObserver * Limits the number of tasks shown in Desktop Mode. * * This class should only be used if - * [com.android.window.flags.Flags.enableDesktopWindowingTaskLimit()] is true. + * [com.android.wm.shell.shared.desktopmode.DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_TASK_LIMIT] + * is enabled and [maxTasksLimit] is strictly greater than 0. */ class DesktopTasksLimiter ( transitions: Transitions, private val taskRepository: DesktopModeTaskRepository, private val shellTaskOrganizer: ShellTaskOrganizer, private val maxTasksLimit: Int, + private val interactionJankMonitor: InteractionJankMonitor, + private val context: Context ) { private val minimizeTransitionObserver = MinimizeTransitionObserver() @VisibleForTesting @@ -52,25 +58,34 @@ class DesktopTasksLimiter ( } transitions.registerObserver(minimizeTransitionObserver) taskRepository.addActiveTaskListener(leftoverMinimizedTasksRemover) + ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE, + "DesktopTasksLimiter: starting limiter with a maximum of %d tasks", maxTasksLimit) } - private data class TaskDetails (val displayId: Int, val taskId: Int) + private data class TaskDetails( + val displayId: Int, + val taskId: Int, + var transitionInfo: TransitionInfo? + ) // TODO(b/333018485): replace this observer when implementing the minimize-animation private inner class MinimizeTransitionObserver : TransitionObserver { private val mPendingTransitionTokensAndTasks = mutableMapOf<IBinder, TaskDetails>() + private val mActiveTransitionTokensAndTasks = mutableMapOf<IBinder, TaskDetails>() fun addPendingTransitionToken(transition: IBinder, taskDetails: TaskDetails) { mPendingTransitionTokensAndTasks[transition] = taskDetails } override fun onTransitionReady( - transition: IBinder, - info: TransitionInfo, - startTransaction: SurfaceControl.Transaction, - finishTransaction: SurfaceControl.Transaction + transition: IBinder, + info: TransitionInfo, + startTransaction: SurfaceControl.Transaction, + finishTransaction: SurfaceControl.Transaction ) { val taskToMinimize = mPendingTransitionTokensAndTasks.remove(transition) ?: return + taskToMinimize.transitionInfo = info + mActiveTransitionTokensAndTasks[transition] = taskToMinimize if (!taskRepository.isActiveTask(taskToMinimize.taskId)) return @@ -81,15 +96,16 @@ class DesktopTasksLimiter ( taskToMinimize.taskId) return } + this@DesktopTasksLimiter.markTaskMinimized( taskToMinimize.displayId, taskToMinimize.taskId) } /** - * Returns whether the given Task is being reordered to the back in the given transition, or - * is already invisible. + * Returns whether the Task [taskDetails] is being reordered to the back in the transition + * [info], or is already invisible. * - * <p> This check can be used to double-check that a task was indeed minimized before + * This check can be used to double-check that a task was indeed minimized before * marking it as such. */ private fun isTaskReorderedToBackOrInvisible( @@ -104,9 +120,21 @@ class DesktopTasksLimiter ( return taskChange.mode == TRANSIT_TO_BACK } - override fun onTransitionStarting(transition: IBinder) {} + override fun onTransitionStarting(transition: IBinder) { + val mActiveTaskDetails = mActiveTransitionTokensAndTasks[transition] + if (mActiveTaskDetails != null && mActiveTaskDetails.transitionInfo != null) { + // Begin minimize window CUJ instrumentation. + interactionJankMonitor.begin( + mActiveTaskDetails.transitionInfo?.rootLeash, context, + CUJ_DESKTOP_MODE_MINIMIZE_WINDOW + ) + } + } override fun onTransitionMerged(merged: IBinder, playing: IBinder) { + if (mActiveTransitionTokensAndTasks.remove(merged) != null) { + interactionJankMonitor.end(CUJ_DESKTOP_MODE_MINIMIZE_WINDOW) + } mPendingTransitionTokensAndTasks.remove(merged)?.let { taskToTransfer -> mPendingTransitionTokensAndTasks[playing] = taskToTransfer } @@ -116,6 +144,13 @@ class DesktopTasksLimiter ( ProtoLog.v( ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE, "DesktopTasksLimiter: transition %s finished", transition) + if (mActiveTransitionTokensAndTasks.remove(transition) != null) { + if (aborted) { + interactionJankMonitor.cancel(CUJ_DESKTOP_MODE_MINIMIZE_WINDOW) + } else { + interactionJankMonitor.end(CUJ_DESKTOP_MODE_MINIMIZE_WINDOW) + } + } mPendingTransitionTokensAndTasks.remove(transition) } } @@ -129,8 +164,7 @@ class DesktopTasksLimiter ( } fun removeLeftoverMinimizedTasks(displayId: Int, wct: WindowContainerTransaction) { - if (taskRepository - .getActiveNonMinimizedTasksOrderedFrontToBack(displayId).isNotEmpty()) { + if (taskRepository.getActiveNonMinimizedOrderedTasks(displayId).isNotEmpty()) { return } val remainingMinimizedTasks = taskRepository.getMinimizedTasks(displayId) @@ -139,7 +173,9 @@ class DesktopTasksLimiter ( } ProtoLog.v( ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE, - "DesktopTasksLimiter: removing leftover minimized tasks: $remainingMinimizedTasks") + "DesktopTasksLimiter: removing leftover minimized tasks: %s", + remainingMinimizedTasks, + ) remainingMinimizedTasks.forEach { taskIdToRemove -> val taskToRemove = shellTaskOrganizer.getRunningTaskInfo(taskIdToRemove) if (taskToRemove != null) { @@ -150,8 +186,8 @@ class DesktopTasksLimiter ( } /** - * Mark a task as minimized, this should only be done after the corresponding transition has - * finished so we don't minimize the task if the transition fails. + * Mark [taskId], which must be on [displayId], as minimized, this should only be done after the + * corresponding transition has finished so we don't minimize the task if the transition fails. */ private fun markTaskMinimized(displayId: Int, taskId: Int) { ProtoLog.v( @@ -162,11 +198,9 @@ class DesktopTasksLimiter ( /** * Add a minimize-transition to [wct] if adding [newFrontTaskInfo] brings us over the task - * limit. + * limit, returning the task to minimize. * - * @param transition the transition that the minimize-transition will be appended to, or null if - * the transition will be started later. - * @return the ID of the minimized task, or null if no task is being minimized. + * The task must be on [displayId]. */ fun addAndGetMinimizeTaskChangesIfNeeded( displayId: Int, @@ -178,7 +212,7 @@ class DesktopTasksLimiter ( "DesktopTasksLimiter: addMinimizeBackTaskChangesIfNeeded, newFrontTask=%d", newFrontTaskInfo.taskId) val newTaskListOrderedFrontToBack = createOrderedTaskListWithGivenTaskInFront( - taskRepository.getActiveNonMinimizedTasksOrderedFrontToBack(displayId), + taskRepository.getActiveNonMinimizedOrderedTasks(displayId), newFrontTaskInfo.taskId) val taskToMinimize = getTaskToMinimizeIfNeeded(newTaskListOrderedFrontToBack) if (taskToMinimize != null) { @@ -194,7 +228,7 @@ class DesktopTasksLimiter ( */ fun addPendingMinimizeChange(transition: IBinder, displayId: Int, taskId: Int) { minimizeTransitionObserver.addPendingTransitionToken( - transition, TaskDetails(displayId, taskId)) + transition, TaskDetails(displayId, taskId, transitionInfo = null)) } /** @@ -221,13 +255,15 @@ class DesktopTasksLimiter ( // No need to minimize anything return null } + val taskIdToMinimize = visibleFreeformTaskIdsOrderedFrontToBack.last() val taskToMinimize = - shellTaskOrganizer.getRunningTaskInfo( - visibleFreeformTaskIdsOrderedFrontToBack.last()) + shellTaskOrganizer.getRunningTaskInfo(taskIdToMinimize) if (taskToMinimize == null) { ProtoLog.e( ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE, - "DesktopTasksLimiter: taskToMinimize == null") + "DesktopTasksLimiter: taskToMinimize(taskId = %d) == null", + taskIdToMinimize, + ) return null } return taskToMinimize @@ -242,7 +278,5 @@ class DesktopTasksLimiter ( } @VisibleForTesting - fun getTransitionObserver(): TransitionObserver { - return minimizeTransitionObserver - } + fun getTransitionObserver(): TransitionObserver = minimizeTransitionObserver }
\ No newline at end of file diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java index e4aa115347eb..d03a561cd3ea 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java @@ -21,11 +21,11 @@ import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; import static android.content.pm.ActivityInfo.CONFIG_ASSETS_PATHS; import static android.content.pm.ActivityInfo.CONFIG_UI_MODE; import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; +import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME; import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION; import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT; import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT; -import static com.android.wm.shell.common.split.SplitScreenUtils.getResizingBackgroundColor; import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_BOTTOM; import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_LEFT; import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_RIGHT; @@ -40,6 +40,7 @@ import android.app.StatusBarManager; import android.content.Context; import android.content.res.Configuration; import android.content.res.Resources; +import android.graphics.Color; import android.graphics.Insets; import android.graphics.Point; import android.graphics.Rect; @@ -290,7 +291,7 @@ public class DragLayout extends LinearLayout final int activityType = taskInfo1.getActivityType(); if (activityType == ACTIVITY_TYPE_STANDARD) { Drawable icon1 = mIconProvider.getIcon(taskInfo1.topActivityInfo); - int bgColor1 = getResizingBackgroundColor(taskInfo1).toArgb(); + int bgColor1 = getResizingBackgroundColor(taskInfo1); mDropZoneView1.setAppInfo(bgColor1, icon1); mDropZoneView2.setAppInfo(bgColor1, icon1); mDropZoneView1.setForceIgnoreBottomMargin(false); @@ -312,10 +313,10 @@ public class DragLayout extends LinearLayout mSplitScreenController.getTaskInfo(SPLIT_POSITION_BOTTOM_OR_RIGHT); if (topOrLeftTask != null && bottomOrRightTask != null) { Drawable topOrLeftIcon = mIconProvider.getIcon(topOrLeftTask.topActivityInfo); - int topOrLeftColor = getResizingBackgroundColor(topOrLeftTask).toArgb(); + int topOrLeftColor = getResizingBackgroundColor(topOrLeftTask); Drawable bottomOrRightIcon = mIconProvider.getIcon( bottomOrRightTask.topActivityInfo); - int bottomOrRightColor = getResizingBackgroundColor(bottomOrRightTask).toArgb(); + int bottomOrRightColor = getResizingBackgroundColor(bottomOrRightTask); mDropZoneView1.setAppInfo(topOrLeftColor, topOrLeftIcon); mDropZoneView2.setAppInfo(bottomOrRightColor, bottomOrRightIcon); } @@ -586,6 +587,11 @@ public class DragLayout extends LinearLayout } } + private static int getResizingBackgroundColor(ActivityManager.RunningTaskInfo taskInfo) { + final int taskBgColor = taskInfo.taskDescription.getBackgroundColor(); + return Color.valueOf(taskBgColor == -1 ? Color.WHITE : taskBgColor).toArgb(); + } + /** * Dumps information about this drag layout. */ diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java index 4531967d6f93..456767a1c9af 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java @@ -99,14 +99,10 @@ public class FreeformTaskListener implements ShellTaskOrganizer.TaskListener, if (DesktopModeStatus.canEnterDesktopMode(mContext)) { mDesktopModeTaskRepository.ifPresent(repository -> { repository.addOrMoveFreeformTaskToTop(taskInfo.displayId, taskInfo.taskId); - repository.unminimizeTask(taskInfo.displayId, taskInfo.taskId); if (taskInfo.isVisible) { - if (repository.addActiveTask(taskInfo.displayId, taskInfo.taskId)) { - ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE, - "Adding active freeform task: #%d", taskInfo.taskId); - } - repository.updateVisibleFreeformTasks(taskInfo.displayId, taskInfo.taskId, - true); + repository.addActiveTask(taskInfo.displayId, taskInfo.taskId); + repository.updateTaskVisibility(taskInfo.displayId, taskInfo.taskId, + /* visible= */ true); } }); } @@ -121,12 +117,6 @@ public class FreeformTaskListener implements ShellTaskOrganizer.TaskListener, if (DesktopModeStatus.canEnterDesktopMode(mContext)) { mDesktopModeTaskRepository.ifPresent(repository -> { repository.removeFreeformTask(taskInfo.displayId, taskInfo.taskId); - repository.unminimizeTask(taskInfo.displayId, taskInfo.taskId); - if (repository.removeActiveTask(taskInfo.taskId)) { - ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE, - "Removing active freeform task: #%d", taskInfo.taskId); - } - repository.updateVisibleFreeformTasks(taskInfo.displayId, taskInfo.taskId, false); }); } mWindowDecorationViewModel.onTaskVanished(taskInfo); @@ -146,16 +136,11 @@ public class FreeformTaskListener implements ShellTaskOrganizer.TaskListener, if (DesktopModeStatus.canEnterDesktopMode(mContext)) { mDesktopModeTaskRepository.ifPresent(repository -> { if (taskInfo.isVisible) { - if (repository.addActiveTask(taskInfo.displayId, taskInfo.taskId)) { - ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE, - "Adding active freeform task: #%d", taskInfo.taskId); - } - } else if (repository.isClosingTask(taskInfo.taskId) - && repository.removeClosingTask(taskInfo.taskId)) { - ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE, - "Removing closing freeform task: #%d", taskInfo.taskId); + repository.addActiveTask(taskInfo.displayId, taskInfo.taskId); + } else if (repository.isClosingTask(taskInfo.taskId)) { + repository.removeClosingTask(taskInfo.taskId); } - repository.updateVisibleFreeformTasks(taskInfo.displayId, taskInfo.taskId, + repository.updateTaskVisibility(taskInfo.displayId, taskInfo.taskId, taskInfo.isVisible); }); } @@ -172,7 +157,6 @@ public class FreeformTaskListener implements ShellTaskOrganizer.TaskListener, if (DesktopModeStatus.canEnterDesktopMode(mContext) && taskInfo.isFocused) { mDesktopModeTaskRepository.ifPresent(repository -> { repository.addOrMoveFreeformTaskToTop(taskInfo.displayId, taskInfo.taskId); - repository.unminimizeTask(taskInfo.displayId, taskInfo.taskId); }); } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java index 7451d2251588..284620e7d0c4 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java @@ -272,6 +272,7 @@ public class PipController implements PipTransitionController.PipTransitionCallb final boolean changed = onDisplayRotationChanged(mContext, outBounds, currentBounds, mTmpInsetBounds, displayId, fromRotation, toRotation, t); if (changed) { + mMenuController.hideMenu(); // If the pip was in the offset zone earlier, adjust the new bounds to the bottom of the // movement bounds mTouchHandler.adjustBoundsForRotation(outBounds, mPipBoundsState.getBounds(), diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java index df3803d54d9d..999ab95ccb1e 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java @@ -416,6 +416,17 @@ public class PipMotionHelper implements PipAppOpsListener.Callback, // location now. mSpringingToTouch = false; + // Boost the velocityX if it's zero to forcefully push it towards the nearest edge. + // We don't simply change the xEndValue below since the PhysicsAnimator would rely on the + // same velocityX to find out which edge to snap to. + if (velocityX == 0) { + final int motionCenterX = mPipBoundsState + .getMotionBoundsState().getBoundsInMotion().centerX(); + final int displayCenterX = mPipBoundsState + .getDisplayBounds().centerX(); + velocityX = (motionCenterX < displayCenterX) ? -0.001f : 0.001f; + } + mTemporaryBoundsPhysicsAnimator .spring(FloatProperties.RECT_WIDTH, getBounds().width(), mSpringConfig) .spring(FloatProperties.RECT_HEIGHT, getBounds().height(), mSpringConfig) diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipController.java index b939b169d8bd..94fe286de869 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipController.java @@ -44,6 +44,7 @@ import com.android.wm.shell.common.DisplayController; import com.android.wm.shell.common.DisplayInsetsController; import com.android.wm.shell.common.DisplayLayout; import com.android.wm.shell.common.ExternalInterfaceBinder; +import com.android.wm.shell.common.ImeListener; import com.android.wm.shell.common.RemoteCallable; import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.common.SingleInstanceRemoteListener; @@ -56,7 +57,6 @@ import com.android.wm.shell.common.pip.PipBoundsState; import com.android.wm.shell.common.pip.PipDisplayLayoutState; import com.android.wm.shell.common.pip.PipUtils; import com.android.wm.shell.pip.Pip; -import com.android.wm.shell.pip.PipTransitionController; import com.android.wm.shell.protolog.ShellProtoLogGroup; import com.android.wm.shell.sysui.ConfigurationChangeListener; import com.android.wm.shell.sysui.ShellCommandHandler; @@ -88,6 +88,7 @@ public class PipController implements ConfigurationChangeListener, private final TaskStackListenerImpl mTaskStackListener; private final ShellTaskOrganizer mShellTaskOrganizer; private final PipTransitionState mPipTransitionState; + private final PipTouchHandler mPipTouchHandler; private final ShellExecutor mMainExecutor; private final PipImpl mImpl; private Consumer<Boolean> mOnIsInPipStateChangedListener; @@ -130,6 +131,7 @@ public class PipController implements ConfigurationChangeListener, TaskStackListenerImpl taskStackListener, ShellTaskOrganizer shellTaskOrganizer, PipTransitionState pipTransitionState, + PipTouchHandler pipTouchHandler, ShellExecutor mainExecutor) { mContext = context; mShellCommandHandler = shellCommandHandler; @@ -144,6 +146,7 @@ public class PipController implements ConfigurationChangeListener, mShellTaskOrganizer = shellTaskOrganizer; mPipTransitionState = pipTransitionState; mPipTransitionState.addPipTransitionStateChangedListener(this); + mPipTouchHandler = pipTouchHandler; mMainExecutor = mainExecutor; mImpl = new PipImpl(); @@ -168,6 +171,7 @@ public class PipController implements ConfigurationChangeListener, TaskStackListenerImpl taskStackListener, ShellTaskOrganizer shellTaskOrganizer, PipTransitionState pipTransitionState, + PipTouchHandler pipTouchHandler, ShellExecutor mainExecutor) { if (!context.getPackageManager().hasSystemFeature(FEATURE_PICTURE_IN_PICTURE)) { ProtoLog.w(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE, @@ -177,7 +181,7 @@ public class PipController implements ConfigurationChangeListener, return new PipController(context, shellInit, shellCommandHandler, shellController, displayController, displayInsetsController, pipBoundsState, pipBoundsAlgorithm, pipDisplayLayoutState, pipScheduler, taskStackListener, shellTaskOrganizer, - pipTransitionState, mainExecutor); + pipTransitionState, pipTouchHandler, mainExecutor); } public PipImpl getPipImpl() { @@ -201,6 +205,13 @@ public class PipController implements ConfigurationChangeListener, .getDisplayLayout(mPipDisplayLayoutState.getDisplayId())); } }); + mDisplayInsetsController.addInsetsChangedListener(mPipDisplayLayoutState.getDisplayId(), + new ImeListener(mDisplayController, mPipDisplayLayoutState.getDisplayId()) { + @Override + public void onImeVisibilityChanged(boolean imeVisible, int imeHeight) { + mPipTouchHandler.onImeVisibilityChanged(imeVisible, imeHeight); + } + }); // Allow other outside processes to bind to PiP controller using the key below. mShellController.addExternalInterface(KEY_EXTRA_SHELL_PIP, diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipMotionHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipMotionHelper.java index ea02de9d9704..83253c6006fb 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipMotionHelper.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipMotionHelper.java @@ -134,6 +134,8 @@ public class PipMotionHelper implements PipAppOpsListener.Callback, private final PhysicsAnimator.SpringConfig mConflictResolutionSpringConfig = new PhysicsAnimator.SpringConfig(STIFFNESS_LOW, DAMPING_RATIO_NO_BOUNCY); + @Nullable private Runnable mUpdateMovementBoundsRunnable; + private final Consumer<Rect> mUpdateBoundsCallback = (Rect newBounds) -> { if (mPipBoundsState.getBounds().equals(newBounds)) { return; @@ -141,6 +143,7 @@ public class PipMotionHelper implements PipAppOpsListener.Callback, mMenuController.updateMenuLayout(newBounds); mPipBoundsState.setBounds(newBounds); + maybeUpdateMovementBounds(); }; /** @@ -416,6 +419,17 @@ public class PipMotionHelper implements PipAppOpsListener.Callback, // location now. mSpringingToTouch = false; + // Boost the velocityX if it's zero to forcefully push it towards the nearest edge. + // We don't simply change the xEndValue below since the PhysicsAnimator would rely on the + // same velocityX to find out which edge to snap to. + if (velocityX == 0) { + final int motionCenterX = mPipBoundsState + .getMotionBoundsState().getBoundsInMotion().centerX(); + final int displayCenterX = mPipBoundsState + .getDisplayBounds().centerX(); + velocityX = (motionCenterX < displayCenterX) ? -0.001f : 0.001f; + } + mTemporaryBoundsPhysicsAnimator .spring(FloatProperties.RECT_WIDTH, getBounds().width(), mSpringConfig) .spring(FloatProperties.RECT_HEIGHT, getBounds().height(), mSpringConfig) @@ -555,11 +569,20 @@ public class PipMotionHelper implements PipAppOpsListener.Callback, + " callers=\n%s", TAG, originalBounds, offset, Debug.getCallers(5, " ")); } + if (offset == 0) { + return; + } + cancelPhysicsAnimation(); - /* - mPipTaskOrganizer.scheduleOffsetPip(originalBounds, offset, SHIFT_DURATION, - mUpdateBoundsCallback); - */ + + Rect adjustedBounds = new Rect(originalBounds); + adjustedBounds.offset(0, offset); + + setAnimatingToBounds(adjustedBounds); + Bundle extra = new Bundle(); + extra.putBoolean(ANIMATING_BOUNDS_CHANGE, true); + extra.putInt(ANIMATING_BOUNDS_CHANGE_DURATION, SHIFT_DURATION); + mPipTransitionState.setState(PipTransitionState.SCHEDULED_BOUNDS_CHANGE, extra); } /** @@ -574,11 +597,11 @@ public class PipMotionHelper implements PipAppOpsListener.Callback, /** Set new fling configs whose min/max values respect the given movement bounds. */ private void rebuildFlingConfigs() { mFlingConfigX = new PhysicsAnimator.FlingConfig(DEFAULT_FRICTION, - mPipBoundsAlgorithm.getMovementBounds(getBounds()).left, - mPipBoundsAlgorithm.getMovementBounds(getBounds()).right); + mPipBoundsState.getMovementBounds().left, + mPipBoundsState.getMovementBounds().right); mFlingConfigY = new PhysicsAnimator.FlingConfig(DEFAULT_FRICTION, - mPipBoundsAlgorithm.getMovementBounds(getBounds()).top, - mPipBoundsAlgorithm.getMovementBounds(getBounds()).bottom); + mPipBoundsState.getMovementBounds().top, + mPipBoundsState.getMovementBounds().bottom); final Rect insetBounds = mPipBoundsState.getDisplayLayout().stableInsets(); mStashConfigX = new PhysicsAnimator.FlingConfig( DEFAULT_FRICTION, @@ -660,6 +683,16 @@ public class PipMotionHelper implements PipAppOpsListener.Callback, cleanUpHighPerfSessionMaybe(); } + void setUpdateMovementBoundsRunnable(Runnable updateMovementBoundsRunnable) { + mUpdateMovementBoundsRunnable = updateMovementBoundsRunnable; + } + + private void maybeUpdateMovementBounds() { + if (mUpdateMovementBoundsRunnable != null) { + mUpdateMovementBoundsRunnable.run(); + } + } + /** * Notifies the floating coordinator that we're moving, and sets the animating to bounds so * we return these bounds from @@ -796,8 +829,14 @@ public class PipMotionHelper implements PipAppOpsListener.Callback, startTx, finishTx, mPipBoundsState.getBounds(), mPipBoundsState.getBounds(), destinationBounds, duration, 0f /* angle */); animator.setAnimationEndCallback(() -> { - mPipBoundsState.setBounds(destinationBounds); - // All motion operations have actually finished, so make bounds cache updates. + mUpdateBoundsCallback.accept(destinationBounds); + + // In case an ongoing drag/fling was present before a deterministic resize transition + // kicked in, we need to update the update bounds properly before cleaning in-motion + // state. + mPipBoundsState.getMotionBoundsState().setBoundsInMotion(destinationBounds); + settlePipBoundsAfterPhysicsAnimation(false /* animatingAfter */); + cleanUpHighPerfSessionMaybe(); // Signal that we are done with resize transition mPipScheduler.scheduleFinishResizePip(true /* configAtEnd */); @@ -806,7 +845,7 @@ public class PipMotionHelper implements PipAppOpsListener.Callback, } private void settlePipBoundsAfterPhysicsAnimation(boolean animatingAfter) { - if (!animatingAfter) { + if (!animatingAfter && mPipBoundsState.getMotionBoundsState().isInMotion()) { // The physics animation ended, though we may not necessarily be done animating, such as // when we're still dragging after moving out of the magnetic target. Only set the final // bounds state and clear motion bounds completely if the whole animation is over. diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipResizeGestureHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipResizeGestureHandler.java index 5b0ca1837a1c..d28204add0ac 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipResizeGestureHandler.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipResizeGestureHandler.java @@ -146,8 +146,8 @@ public class PipResizeGestureHandler implements mUpdateResizeBoundsCallback = (rect) -> { mUserResizeBounds.set(rect); // mMotionHelper.synchronizePinnedStackBounds(); - mUpdateMovementBoundsRunnable.run(); mPipBoundsState.setBounds(rect); + mUpdateMovementBoundsRunnable.run(); resetState(); }; } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTouchHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTouchHandler.java index 53b80e8b7542..f387e72b3da6 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTouchHandler.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTouchHandler.java @@ -199,6 +199,7 @@ public class PipTouchHandler implements PipTransitionState.PipTransitionStateCha mMenuController.addListener(new PipMenuListener()); mGesture = new DefaultPipTouchGesture(); mMotionHelper = pipMotionHelper; + mMotionHelper.setUpdateMovementBoundsRunnable(this::updateMovementBounds); mPipDismissTargetHandler = new PipDismissTargetHandler(context, pipUiEventLogger, mMotionHelper, mainExecutor); mTouchState = new PipTouchState(ViewConfiguration.get(context), @@ -317,6 +318,8 @@ public class PipTouchHandler implements PipTransitionState.PipTransitionStateCha mFloatingContentCoordinator.onContentRemoved(mMotionHelper); mPipResizeGestureHandler.onActivityUnpinned(); mPipInputConsumer.unregisterInputConsumer(); + mPipBoundsState.setHasUserMovedPip(false); + mPipBoundsState.setHasUserResizedPip(false); } void onPinnedStackAnimationEnded( @@ -346,6 +349,22 @@ public class PipTouchHandler implements PipTransitionState.PipTransitionStateCha void onImeVisibilityChanged(boolean imeVisible, int imeHeight) { mIsImeShowing = imeVisible; mImeHeight = imeHeight; + + // Cache new movement bounds using the new potential IME height. + updateMovementBounds(); + + mPipTransitionState.setOnIdlePipTransitionStateRunnable(() -> { + int delta = mPipBoundsState.getMovementBounds().bottom + - mPipBoundsState.getBounds().top; + + boolean hasUserInteracted = (mPipBoundsState.hasUserMovedPip() + || mPipBoundsState.hasUserResizedPip()); + if ((imeVisible && delta < 0) || (!imeVisible && !hasUserInteracted)) { + // The policy is to ignore an IME disappearing if user has interacted with PiP. + // Otherwise, only offset due to an appearing IME if PiP occludes it. + mMotionHelper.animateToOffset(mPipBoundsState.getBounds(), delta); + } + }); } void onShelfVisibilityChanged(boolean shelfVisible, int shelfHeight) { @@ -1077,6 +1096,7 @@ public class PipTouchHandler implements PipTransitionState.PipTransitionStateCha switch (newState) { case PipTransitionState.ENTERED_PIP: onActivityPinned(); + updateMovementBounds(); mTouchState.setAllowInputEvents(true); mTouchState.reset(); break; diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransitionState.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransitionState.java index 29272be6e9bd..a132796f4a84 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransitionState.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransitionState.java @@ -149,6 +149,12 @@ public class PipTransitionState { @Nullable private SurfaceControl mSwipePipToHomeOverlay; + // + // Scheduling-related state + // + @Nullable + private Runnable mOnIdlePipTransitionStateRunnable; + /** * An interface to track state updates as we progress through PiP transitions. */ @@ -197,6 +203,8 @@ public class PipTransitionState { mState = state; dispatchPipTransitionStateChanged(prevState, mState, extra); } + + maybeRunOnIdlePipTransitionStateCallback(); } /** @@ -231,6 +239,29 @@ public class PipTransitionState { } /** + * Schedule a callback to run when in a valid idle PiP state. + * + * <p>We only allow for one callback to be scheduled to avoid cases with multiple transitions + * being scheduled. For instance, if user double taps and IME shows, this would + * schedule a bounds change transition for IME appearing. But if some other transition would + * want to animate PiP before the scheduled callback executes, we would rather want to replace + * the existing callback with a new one, to avoid multiple animations + * as soon as we are idle.</p> + */ + public void setOnIdlePipTransitionStateRunnable( + @Nullable Runnable onIdlePipTransitionStateRunnable) { + mOnIdlePipTransitionStateRunnable = onIdlePipTransitionStateRunnable; + maybeRunOnIdlePipTransitionStateCallback(); + } + + private void maybeRunOnIdlePipTransitionStateCallback() { + if (mOnIdlePipTransitionStateRunnable != null && isPipStateIdle()) { + mOnIdlePipTransitionStateRunnable.run(); + mOnIdlePipTransitionStateRunnable = null; + } + } + + /** * Adds a {@link PipTransitionStateChangedListener} for future PiP transition state updates. */ public void addPipTransitionStateChangedListener(PipTransitionStateChangedListener listener) { @@ -318,6 +349,11 @@ public class PipTransitionState { throw new IllegalStateException("Unknown state: " + state); } + public boolean isPipStateIdle() { + // This needs to be a valid in-PiP state that isn't a transient state. + return mState == ENTERED_PIP || mState == CHANGED_PIP_BOUNDS; + } + @Override public String toString() { return String.format("PipTransitionState(mState=%s, mInSwipePipToHomeTransition=%b)", 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 d7ee563b562c..2531ff150f43 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 @@ -41,7 +41,6 @@ import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSIT import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT; import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_UNDEFINED; import static com.android.wm.shell.common.split.SplitScreenConstants.splitPositionToString; -import static com.android.wm.shell.common.split.SplitScreenUtils.getResizingBackgroundColor; import static com.android.wm.shell.common.split.SplitScreenUtils.reverseSplitPosition; import static com.android.wm.shell.common.split.SplitScreenUtils.splitFailureMessage; import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN; @@ -2458,13 +2457,8 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, updateSurfaceBounds(layout, t, shouldUseParallaxEffect); getMainStageBounds(mTempRect1); getSideStageBounds(mTempRect2); - // TODO (b/307490004): "commonColor" below is a temporary fix to ensure the colors on both - // sides match. When b/307490004 is fixed, this code can be reverted. - float[] commonColor = getResizingBackgroundColor(mSideStage.mRootTaskInfo).getComponents(); - mMainStage.onResizing( - mTempRect1, mTempRect2, t, offsetX, offsetY, mShowDecorImmediately, commonColor); - mSideStage.onResizing( - mTempRect2, mTempRect1, t, offsetX, offsetY, mShowDecorImmediately, commonColor); + mMainStage.onResizing(mTempRect1, mTempRect2, t, offsetX, offsetY, mShowDecorImmediately); + mSideStage.onResizing(mTempRect2, mTempRect1, t, offsetX, offsetY, mShowDecorImmediately); t.apply(); mTransactionPool.release(t); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java index 1076eca60369..d1ab3e96d4c2 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java @@ -314,10 +314,10 @@ class StageTaskListener implements ShellTaskOrganizer.TaskListener { } void onResizing(Rect newBounds, Rect sideBounds, SurfaceControl.Transaction t, int offsetX, - int offsetY, boolean immediately, float[] veilColor) { + int offsetY, boolean immediately) { if (mSplitDecorManager != null && mRootTaskInfo != null) { mSplitDecorManager.onResizing(mRootTaskInfo, newBounds, sideBounds, t, offsetX, - offsetY, immediately, veilColor); + offsetY, immediately); } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewTransitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewTransitions.java index e6d1b4593a46..15fe7abb96a5 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewTransitions.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewTransitions.java @@ -217,6 +217,11 @@ public class TaskViewTransitions implements Transitions.TransitionHandler { return null; } + /** Returns true if the given {@code taskInfo} belongs to a task view. */ + public boolean isTaskViewTask(ActivityManager.RunningTaskInfo taskInfo) { + return findTaskView(taskInfo) != null; + } + void startTaskView(@NonNull WindowContainerTransaction wct, @NonNull TaskViewTaskController taskView, @NonNull IBinder launchCookie) { updateVisibilityState(taskView, true /* visible */); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java index 5c230c0a505c..d8dba71c0a4f 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java @@ -33,6 +33,7 @@ import android.graphics.Region; import android.hardware.input.InputManager; import android.os.Handler; import android.os.RemoteException; +import android.os.UserHandle; import android.provider.Settings; import android.util.Log; import android.util.SparseArray; @@ -288,6 +289,7 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel { final CaptionWindowDecoration windowDecoration = new CaptionWindowDecoration( mContext, + mContext.createContextAsUser(UserHandle.of(taskInfo.userId), 0 /* flags */), mDisplayController, mTaskOrganizer, taskInfo, diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java index cf42a49f7103..de514f661d01 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java @@ -77,6 +77,7 @@ public class CaptionWindowDecoration extends WindowDecoration<WindowDecorLinearL CaptionWindowDecoration( Context context, + @NonNull Context userContext, DisplayController displayController, ShellTaskOrganizer taskOrganizer, RunningTaskInfo taskInfo, @@ -85,7 +86,7 @@ public class CaptionWindowDecoration extends WindowDecoration<WindowDecorLinearL @ShellBackgroundThread ShellExecutor bgExecutor, Choreographer choreographer, SyncTransactionQueue syncQueue) { - super(context, displayController, taskOrganizer, taskInfo, taskSurface); + super(context, userContext, displayController, taskOrganizer, taskInfo, taskSurface); mHandler = handler; mBgExecutor = bgExecutor; mChoreographer = choreographer; diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java index 0ff35226b77e..7c8f205ce78f 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java @@ -59,6 +59,7 @@ import android.net.Uri; import android.os.Handler; import android.os.Looper; import android.os.RemoteException; +import android.os.UserHandle; import android.util.Log; import android.util.SparseArray; import android.view.Choreographer; @@ -1149,6 +1150,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { final DesktopModeWindowDecoration windowDecoration = mDesktopModeWindowDecorFactory.create( mContext, + mContext.createContextAsUser(UserHandle.of(taskInfo.userId), 0 /* flags */), mDisplayController, mSplitScreenController, mTaskOrganizer, diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java index 41f428b6ca83..e82990f9fe1d 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java @@ -160,6 +160,7 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin DesktopModeWindowDecoration( Context context, + @NonNull Context userContext, DisplayController displayController, SplitScreenController splitScreenController, ShellTaskOrganizer taskOrganizer, @@ -171,8 +172,8 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin SyncTransactionQueue syncQueue, RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer, AppToWebGenericLinksParser genericLinksParser) { - this (context, displayController, splitScreenController, taskOrganizer, taskInfo, - taskSurface, handler, bgExecutor, choreographer, syncQueue, + this (context, userContext, displayController, splitScreenController, taskOrganizer, + taskInfo, taskSurface, handler, bgExecutor, choreographer, syncQueue, rootTaskDisplayAreaOrganizer, genericLinksParser, SurfaceControl.Builder::new, SurfaceControl.Transaction::new, WindowContainerTransaction::new, SurfaceControl::new, new SurfaceControlViewHostFactory() {}, @@ -181,6 +182,7 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin DesktopModeWindowDecoration( Context context, + @NonNull Context userContext, DisplayController displayController, SplitScreenController splitScreenController, ShellTaskOrganizer taskOrganizer, @@ -199,7 +201,7 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin SurfaceControlViewHostFactory surfaceControlViewHostFactory, MaximizeMenuFactory maximizeMenuFactory, HandleMenuFactory handleMenuFactory) { - super(context, displayController, taskOrganizer, taskInfo, taskSurface, + super(context, userContext, displayController, taskOrganizer, taskInfo, taskSurface, surfaceControlBuilderSupplier, surfaceControlTransactionSupplier, windowContainerTransactionSupplier, surfaceControlSupplier, surfaceControlViewHostFactory); @@ -737,12 +739,8 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin Slog.e(TAG, "Base activity component not found in task"); return; } - final PackageManager pm = mContext.getApplicationContext().getPackageManager(); - final ActivityInfo activityInfo = pm.getActivityInfo(baseActivity, - // Include uninstalled apps. Despite its name, adding this flag is a workaround - // to #getActivityInfo throwing a NameNotFoundException for installed packages - // when HSUM is enabled. See b/354884302. - PackageManager.MATCH_UNINSTALLED_PACKAGES); + final PackageManager pm = mUserContext.getPackageManager(); + final ActivityInfo activityInfo = pm.getActivityInfo(baseActivity, 0 /* flags */); final IconProvider provider = new IconProvider(mContext); final Drawable appIconDrawable = provider.getIcon(activityInfo); final BaseIconFactory headerIconFactory = createIconFactory(mContext, @@ -1264,6 +1262,7 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin DesktopModeWindowDecoration create( Context context, + @NonNull Context userContext, DisplayController displayController, SplitScreenController splitScreenController, ShellTaskOrganizer taskOrganizer, @@ -1277,6 +1276,7 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin AppToWebGenericLinksParser genericLinksParser) { return new DesktopModeWindowDecoration( context, + userContext, displayController, splitScreenController, taskOrganizer, diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java index 3b8657d4adf5..68285602a26e 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java @@ -106,6 +106,7 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> * System-wide context. Only used to create context with overridden configurations. */ final Context mContext; + final @NonNull Context mUserContext; final @NonNull DisplayController mDisplayController; final ShellTaskOrganizer mTaskOrganizer; final Supplier<SurfaceControl.Builder> mSurfaceControlBuilderSupplier; @@ -147,11 +148,12 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> WindowDecoration( Context context, + @NonNull Context userContext, DisplayController displayController, ShellTaskOrganizer taskOrganizer, RunningTaskInfo taskInfo, SurfaceControl taskSurface) { - this(context, displayController, taskOrganizer, taskInfo, taskSurface, + this(context, userContext, displayController, taskOrganizer, taskInfo, taskSurface, SurfaceControl.Builder::new, SurfaceControl.Transaction::new, WindowContainerTransaction::new, SurfaceControl::new, new SurfaceControlViewHostFactory() {}); @@ -159,6 +161,7 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> WindowDecoration( Context context, + @NonNull Context userContext, @NonNull DisplayController displayController, ShellTaskOrganizer taskOrganizer, RunningTaskInfo taskInfo, @@ -169,6 +172,7 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> Supplier<SurfaceControl> surfaceControlSupplier, SurfaceControlViewHostFactory surfaceControlViewHostFactory) { mContext = context; + mUserContext = userContext; mDisplayController = displayController; mTaskOrganizer = taskOrganizer; mTaskInfo = taskInfo; @@ -177,7 +181,6 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> mSurfaceControlTransactionSupplier = surfaceControlTransactionSupplier; mWindowContainerTransactionSupplier = windowContainerTransactionSupplier; mSurfaceControlViewHostFactory = surfaceControlViewHostFactory; - mDisplay = mDisplayController.getDisplay(mTaskInfo.displayId); } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java index e91828be4ebe..716a148175df 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java @@ -16,10 +16,6 @@ package com.android.wm.shell; -import static android.app.CameraCompatTaskInfo.CAMERA_COMPAT_CONTROL_DISMISSED; -import static android.app.CameraCompatTaskInfo.CAMERA_COMPAT_CONTROL_HIDDEN; -import static android.app.CameraCompatTaskInfo.CAMERA_COMPAT_CONTROL_TREATMENT_APPLIED; -import static android.app.CameraCompatTaskInfo.CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED; import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW; @@ -443,84 +439,6 @@ public class ShellTaskOrganizerTests extends ShellTestCase { } @Test - public void testOnCameraCompatActivityChanged() { - final RunningTaskInfo taskInfo1 = createTaskInfo(/* taskId= */ 1, - WINDOWING_MODE_FULLSCREEN); - taskInfo1.displayId = DEFAULT_DISPLAY; - taskInfo1.appCompatTaskInfo.cameraCompatTaskInfo.cameraCompatControlState = - CAMERA_COMPAT_CONTROL_HIDDEN; - final TrackingTaskListener taskListener = new TrackingTaskListener(); - mOrganizer.addListenerForType(taskListener, TASK_LISTENER_TYPE_FULLSCREEN); - mOrganizer.onTaskAppeared(taskInfo1, /* leash= */ null); - - // Task listener sent to compat UI is null if top activity doesn't request a camera - // compat control. - verifyOnCompatInfoChangedInvokedWith(taskInfo1, null /* taskListener */); - - // Task listener is non-null when request a camera compat control for a visible task. - clearInvocations(mCompatUI); - final RunningTaskInfo taskInfo2 = - createTaskInfo(taskInfo1.taskId, taskInfo1.getWindowingMode()); - taskInfo2.displayId = taskInfo1.displayId; - taskInfo2.appCompatTaskInfo.cameraCompatTaskInfo.cameraCompatControlState = - CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED; - taskInfo2.isVisible = true; - mOrganizer.onTaskInfoChanged(taskInfo2); - verifyOnCompatInfoChangedInvokedWith(taskInfo2, taskListener); - - // CompatUIController#onCompatInfoChanged is called when requested state for a camera - // compat control changes for a visible task. - clearInvocations(mCompatUI); - final RunningTaskInfo taskInfo3 = - createTaskInfo(taskInfo1.taskId, taskInfo1.getWindowingMode()); - taskInfo3.displayId = taskInfo1.displayId; - taskInfo3.appCompatTaskInfo.cameraCompatTaskInfo.cameraCompatControlState = - CAMERA_COMPAT_CONTROL_TREATMENT_APPLIED; - taskInfo3.isVisible = true; - mOrganizer.onTaskInfoChanged(taskInfo3); - verifyOnCompatInfoChangedInvokedWith(taskInfo3, taskListener); - - // CompatUIController#onCompatInfoChanged is called when a top activity goes in size compat - // mode for a visible task that has a compat control. - clearInvocations(mCompatUI); - final RunningTaskInfo taskInfo4 = - createTaskInfo(taskInfo1.taskId, taskInfo1.getWindowingMode()); - taskInfo4.displayId = taskInfo1.displayId; - taskInfo4.appCompatTaskInfo.topActivityInSizeCompat = true; - taskInfo4.appCompatTaskInfo.cameraCompatTaskInfo.cameraCompatControlState = - CAMERA_COMPAT_CONTROL_TREATMENT_APPLIED; - taskInfo4.isVisible = true; - mOrganizer.onTaskInfoChanged(taskInfo4); - verifyOnCompatInfoChangedInvokedWith(taskInfo4, taskListener); - - // Task linster is null when a camera compat control is dimissed for a visible task. - clearInvocations(mCompatUI); - final RunningTaskInfo taskInfo5 = - createTaskInfo(taskInfo1.taskId, taskInfo1.getWindowingMode()); - taskInfo5.displayId = taskInfo1.displayId; - taskInfo5.appCompatTaskInfo.cameraCompatTaskInfo.cameraCompatControlState = - CAMERA_COMPAT_CONTROL_DISMISSED; - taskInfo5.isVisible = true; - mOrganizer.onTaskInfoChanged(taskInfo5); - verifyOnCompatInfoChangedInvokedWith(taskInfo5, null /* taskListener */); - - // Task linster is null when request a camera compat control for a invisible task. - clearInvocations(mCompatUI); - final RunningTaskInfo taskInfo6 = - createTaskInfo(taskInfo1.taskId, taskInfo1.getWindowingMode()); - taskInfo6.displayId = taskInfo1.displayId; - taskInfo6.appCompatTaskInfo.cameraCompatTaskInfo.cameraCompatControlState = - CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED; - taskInfo6.isVisible = false; - mOrganizer.onTaskInfoChanged(taskInfo6); - verifyOnCompatInfoChangedInvokedWith(taskInfo6, null /* taskListener */); - - clearInvocations(mCompatUI); - mOrganizer.onTaskVanished(taskInfo1); - verifyOnCompatInfoChangedInvokedWith(taskInfo1, null /* taskListener */); - } - - @Test public void testAddLocusListener() { RunningTaskInfo task1 = createTaskInfo(/* taskId= */ 1, WINDOWING_MODE_MULTI_WINDOW); task1.isVisible = true; diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayImeControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayImeControllerTest.java index 2c0aa12f22d2..764d5a97e3e1 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayImeControllerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayImeControllerTest.java @@ -83,7 +83,7 @@ public class DisplayImeControllerTest extends ShellTestCase { } }, mExecutor) { @Override - void removeImeSurface() { } + void removeImeSurface(int displayId) { } }.new PerDisplay(DEFAULT_DISPLAY, ROTATION_0); } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/ImeListenerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/ImeListenerTest.kt new file mode 100644 index 000000000000..3b0a0722968b --- /dev/null +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/ImeListenerTest.kt @@ -0,0 +1,152 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.wm.shell.common + +import android.content.res.Configuration +import android.content.res.Resources +import android.graphics.Insets +import android.graphics.Rect +import android.testing.AndroidTestingRunner +import android.view.DisplayCutout +import android.view.DisplayInfo +import android.view.InsetsSource.ID_IME +import android.view.InsetsState +import android.view.Surface +import android.view.WindowInsets.Type +import androidx.test.filters.SmallTest +import com.android.internal.R +import com.android.wm.shell.ShellTestCase +import junit.framework.Assert.assertEquals +import junit.framework.Assert.assertFalse +import junit.framework.Assert.assertTrue +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mock +import org.mockito.Mockito +import org.mockito.kotlin.whenever + + +@SmallTest +@RunWith(AndroidTestingRunner::class) +class ImeListenerTest : ShellTestCase() { + private lateinit var imeListener: CachingImeListener + private lateinit var displayLayout: DisplayLayout + + @Mock private lateinit var displayController: DisplayController + @Before + fun setUp() { + val resources = createResources(40, 50, false) + val displayInfo = createDisplayInfo(1000, 1500, 0, Surface.ROTATION_0) + displayLayout = DisplayLayout(displayInfo, resources, false, false) + whenever(displayController.getDisplayLayout(DEFAULT_DISPLAY_ID)).thenReturn(displayLayout) + imeListener = CachingImeListener(displayController, DEFAULT_DISPLAY_ID) + } + + @Test + fun testImeAppears() { + val insetsState = createInsetsStateWithIme(true, DEFAULT_IME_HEIGHT) + imeListener.insetsChanged(insetsState) + assertTrue("Ime insets source should become visible", imeListener.cachedImeVisible) + assertEquals(DEFAULT_IME_HEIGHT, imeListener.cachedImeHeight) + } + + @Test + fun testImeAppears_thenDisappears() { + // Send insetsState with an IME as a visible source. + val insetsStateWithIme = createInsetsStateWithIme(true, DEFAULT_IME_HEIGHT) + imeListener.insetsChanged(insetsStateWithIme) + + // Send insetsState without IME. + val insetsStateWithoutIme = createInsetsStateWithIme(false, 0) + imeListener.insetsChanged(insetsStateWithoutIme) + + assertFalse("Ime insets source should become invisible", + imeListener.cachedImeVisible) + assertEquals(0, imeListener.cachedImeHeight) + } + + private fun createInsetsStateWithIme(isVisible: Boolean, imeHeight: Int): InsetsState { + val stableBounds = Rect() + displayLayout.getStableBounds(stableBounds) + val insetsState = InsetsState() + + val insetsSource = insetsState.getOrCreateSource(ID_IME, Type.ime()) + insetsSource.setVisible(isVisible) + insetsSource.setFrame(stableBounds.left, stableBounds.bottom - imeHeight, + stableBounds.right, stableBounds.bottom) + return insetsState + } + + private fun createDisplayInfo(width: Int, height: Int, cutoutHeight: Int, + rotation: Int): DisplayInfo { + val info = DisplayInfo() + info.logicalWidth = width + info.logicalHeight = height + info.rotation = rotation + if (cutoutHeight > 0) { + info.displayCutout = DisplayCutout( + Insets.of(0, cutoutHeight, 0, 0) /* safeInsets */, + null /* boundLeft */, + Rect(width / 2 - cutoutHeight, 0, width / 2 + cutoutHeight, + cutoutHeight) /* boundTop */, null /* boundRight */, + null /* boundBottom */) + } else { + info.displayCutout = DisplayCutout.NO_CUTOUT + } + info.logicalDensityDpi = 300 + return info + } + + private fun createResources(navLand: Int, navPort: Int, navMoves: Boolean): Resources { + val cfg = Configuration() + cfg.uiMode = Configuration.UI_MODE_TYPE_NORMAL + val res = Mockito.mock(Resources::class.java) + Mockito.doReturn(navLand).whenever(res).getDimensionPixelSize( + R.dimen.navigation_bar_height_landscape_car_mode) + Mockito.doReturn(navPort).whenever(res).getDimensionPixelSize( + R.dimen.navigation_bar_height_car_mode) + Mockito.doReturn(navLand).whenever(res).getDimensionPixelSize( + R.dimen.navigation_bar_width_car_mode) + Mockito.doReturn(navLand).whenever(res).getDimensionPixelSize( + R.dimen.navigation_bar_height_landscape) + Mockito.doReturn(navPort).whenever(res).getDimensionPixelSize( + R.dimen.navigation_bar_height) + Mockito.doReturn(navLand).whenever(res).getDimensionPixelSize( + R.dimen.navigation_bar_width) + Mockito.doReturn(navMoves).whenever(res).getBoolean(R.bool.config_navBarCanMove) + Mockito.doReturn(cfg).whenever(res).configuration + return res + } + + private class CachingImeListener( + displayController: DisplayController, + displayId: Int + ) : ImeListener(displayController, displayId) { + var cachedImeVisible = false + var cachedImeHeight = 0 + public override fun onImeVisibilityChanged(imeVisible: Boolean, imeHeight: Int) { + cachedImeVisible = imeVisible + cachedImeHeight = imeHeight + } + } + + companion object { + private const val DEFAULT_DISPLAY_ID = 0 + private const val DEFAULT_IME_HEIGHT = 500 + } +}
\ No newline at end of file diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIControllerTest.java index fc7a7770b8ca..77e22cd17f6f 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIControllerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIControllerTest.java @@ -16,8 +16,6 @@ package com.android.wm.shell.compatui; -import static android.app.CameraCompatTaskInfo.CAMERA_COMPAT_CONTROL_HIDDEN; -import static android.app.CameraCompatTaskInfo.CAMERA_COMPAT_CONTROL_TREATMENT_APPLIED; import static android.view.WindowInsets.Type.navigationBars; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; @@ -34,7 +32,6 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import android.app.ActivityManager.RunningTaskInfo; -import android.app.CameraCompatTaskInfo.CameraCompatControlState; import android.app.TaskInfo; import android.content.Context; import android.content.res.Configuration; @@ -199,8 +196,7 @@ public class CompatUIControllerTest extends ShellTestCase { @Test @RequiresFlagsDisabled(Flags.FLAG_APP_COMPAT_UI_FRAMEWORK) public void testOnCompatInfoChanged() { - TaskInfo taskInfo = createTaskInfo(DISPLAY_ID, TASK_ID, /* hasSizeCompat= */ true, - CAMERA_COMPAT_CONTROL_HIDDEN); + TaskInfo taskInfo = createTaskInfo(DISPLAY_ID, TASK_ID, /* hasSizeCompat= */ true); // Verify that the compat controls are added with non-null task listener. mController.onCompatInfoChanged(new CompatUIInfo(taskInfo, mMockTaskListener)); @@ -214,8 +210,7 @@ public class CompatUIControllerTest extends ShellTestCase { // Verify that the compat controls and letterbox education are updated with new size compat // info. clearInvocations(mMockCompatLayout, mMockLetterboxEduLayout, mController); - taskInfo = createTaskInfo(DISPLAY_ID, TASK_ID, /* hasSizeCompat= */ true, - CAMERA_COMPAT_CONTROL_TREATMENT_APPLIED); + taskInfo = createTaskInfo(DISPLAY_ID, TASK_ID, /* hasSizeCompat= */ true); mController.onCompatInfoChanged(new CompatUIInfo(taskInfo, mMockTaskListener)); verify(mMockCompatLayout).updateCompatInfo(taskInfo, mMockTaskListener, @@ -228,7 +223,7 @@ public class CompatUIControllerTest extends ShellTestCase { // Verify that compat controls and letterbox education are removed with null task listener. clearInvocations(mMockCompatLayout, mMockLetterboxEduLayout, mController); mController.onCompatInfoChanged(new CompatUIInfo(createTaskInfo(DISPLAY_ID, TASK_ID, - /* hasSizeCompat= */ true, CAMERA_COMPAT_CONTROL_HIDDEN), + /* hasSizeCompat= */ true), /* taskListener= */ null)); verify(mMockCompatLayout).release(); @@ -243,8 +238,7 @@ public class CompatUIControllerTest extends ShellTestCase { doReturn(false).when(mMockLetterboxEduLayout).createLayout(anyBoolean()); doReturn(false).when(mMockRestartDialogLayout).createLayout(anyBoolean()); - TaskInfo taskInfo = createTaskInfo(DISPLAY_ID, TASK_ID, /* hasSizeCompat= */ true, - CAMERA_COMPAT_CONTROL_HIDDEN); + TaskInfo taskInfo = createTaskInfo(DISPLAY_ID, TASK_ID, /* hasSizeCompat= */ true); mController.onCompatInfoChanged(new CompatUIInfo(taskInfo, mMockTaskListener)); verify(mController).createCompatUiWindowManager(any(), eq(taskInfo), eq(mMockTaskListener)); @@ -274,8 +268,7 @@ public class CompatUIControllerTest extends ShellTestCase { doReturn(false).when(mMockLetterboxEduLayout).updateCompatInfo(any(), any(), anyBoolean()); doReturn(false).when(mMockRestartDialogLayout).updateCompatInfo(any(), any(), anyBoolean()); - TaskInfo taskInfo = createTaskInfo(DISPLAY_ID, TASK_ID, /* hasSizeCompat= */ true, - CAMERA_COMPAT_CONTROL_HIDDEN); + TaskInfo taskInfo = createTaskInfo(DISPLAY_ID, TASK_ID, /* hasSizeCompat= */ true); mController.onCompatInfoChanged(new CompatUIInfo(taskInfo, mMockTaskListener)); verify(mController).createCompatUiWindowManager(any(), eq(taskInfo), eq(mMockTaskListener)); @@ -326,7 +319,7 @@ public class CompatUIControllerTest extends ShellTestCase { public void testOnDisplayRemoved() { mController.onDisplayAdded(DISPLAY_ID); mController.onCompatInfoChanged(new CompatUIInfo(createTaskInfo(DISPLAY_ID, TASK_ID, - /* hasSizeCompat= */ true, CAMERA_COMPAT_CONTROL_HIDDEN), mMockTaskListener)); + /* hasSizeCompat= */ true), mMockTaskListener)); mController.onDisplayRemoved(DISPLAY_ID + 1); @@ -348,7 +341,7 @@ public class CompatUIControllerTest extends ShellTestCase { @RequiresFlagsDisabled(Flags.FLAG_APP_COMPAT_UI_FRAMEWORK) public void testOnDisplayConfigurationChanged() { mController.onCompatInfoChanged(new CompatUIInfo(createTaskInfo(DISPLAY_ID, TASK_ID, - /* hasSizeCompat= */ true, CAMERA_COMPAT_CONTROL_HIDDEN), mMockTaskListener)); + /* hasSizeCompat= */ true), mMockTaskListener)); mController.onDisplayConfigurationChanged(DISPLAY_ID + 1, new Configuration()); @@ -368,7 +361,7 @@ public class CompatUIControllerTest extends ShellTestCase { public void testInsetsChanged() { mController.onDisplayAdded(DISPLAY_ID); mController.onCompatInfoChanged(new CompatUIInfo(createTaskInfo(DISPLAY_ID, TASK_ID, - /* hasSizeCompat= */ true, CAMERA_COMPAT_CONTROL_HIDDEN), mMockTaskListener)); + /* hasSizeCompat= */ true), mMockTaskListener)); InsetsState insetsState = new InsetsState(); InsetsSource insetsSource = new InsetsSource( InsetsSource.createId(null, 0, navigationBars()), navigationBars()); @@ -395,7 +388,7 @@ public class CompatUIControllerTest extends ShellTestCase { @RequiresFlagsDisabled(Flags.FLAG_APP_COMPAT_UI_FRAMEWORK) public void testChangeLayoutsVisibilityOnImeShowHide() { mController.onCompatInfoChanged(new CompatUIInfo(createTaskInfo(DISPLAY_ID, TASK_ID, - /* hasSizeCompat= */ true, CAMERA_COMPAT_CONTROL_HIDDEN), mMockTaskListener)); + /* hasSizeCompat= */ true), mMockTaskListener)); // Verify that the restart button is hidden after IME is showing. mController.onImeVisibilityChanged(DISPLAY_ID, /* isShowing= */ true); @@ -405,8 +398,7 @@ public class CompatUIControllerTest extends ShellTestCase { verify(mMockRestartDialogLayout).updateVisibility(false); // Verify button remains hidden while IME is showing. - TaskInfo taskInfo = createTaskInfo(DISPLAY_ID, TASK_ID, /* hasSizeCompat= */ true, - CAMERA_COMPAT_CONTROL_HIDDEN); + TaskInfo taskInfo = createTaskInfo(DISPLAY_ID, TASK_ID, /* hasSizeCompat= */ true); mController.onCompatInfoChanged(new CompatUIInfo(taskInfo, mMockTaskListener)); verify(mMockCompatLayout).updateCompatInfo(taskInfo, mMockTaskListener, @@ -428,7 +420,7 @@ public class CompatUIControllerTest extends ShellTestCase { @RequiresFlagsDisabled(Flags.FLAG_APP_COMPAT_UI_FRAMEWORK) public void testChangeLayoutsVisibilityOnKeyguardShowingChanged() { mController.onCompatInfoChanged(new CompatUIInfo(createTaskInfo(DISPLAY_ID, TASK_ID, - /* hasSizeCompat= */ true, CAMERA_COMPAT_CONTROL_HIDDEN), mMockTaskListener)); + /* hasSizeCompat= */ true), mMockTaskListener)); // Verify that the restart button is hidden after keyguard becomes showing. mController.onKeyguardVisibilityChanged(true, false, false); @@ -438,8 +430,7 @@ public class CompatUIControllerTest extends ShellTestCase { verify(mMockRestartDialogLayout).updateVisibility(false); // Verify button remains hidden while keyguard is showing. - TaskInfo taskInfo = createTaskInfo(DISPLAY_ID, TASK_ID, /* hasSizeCompat= */ true, - CAMERA_COMPAT_CONTROL_HIDDEN); + TaskInfo taskInfo = createTaskInfo(DISPLAY_ID, TASK_ID, /* hasSizeCompat= */ true); mController.onCompatInfoChanged(new CompatUIInfo(taskInfo, mMockTaskListener)); verify(mMockCompatLayout).updateCompatInfo(taskInfo, mMockTaskListener, @@ -461,7 +452,7 @@ public class CompatUIControllerTest extends ShellTestCase { @RequiresFlagsDisabled(Flags.FLAG_APP_COMPAT_UI_FRAMEWORK) public void testLayoutsRemainHiddenOnKeyguardShowingFalseWhenImeIsShowing() { mController.onCompatInfoChanged(new CompatUIInfo(createTaskInfo(DISPLAY_ID, TASK_ID, - /* hasSizeCompat= */ true, CAMERA_COMPAT_CONTROL_HIDDEN), mMockTaskListener)); + /* hasSizeCompat= */ true), mMockTaskListener)); mController.onImeVisibilityChanged(DISPLAY_ID, /* isShowing= */ true); mController.onKeyguardVisibilityChanged(true, false, false); @@ -491,7 +482,7 @@ public class CompatUIControllerTest extends ShellTestCase { @RequiresFlagsDisabled(Flags.FLAG_APP_COMPAT_UI_FRAMEWORK) public void testLayoutsRemainHiddenOnImeHideWhenKeyguardIsShowing() { mController.onCompatInfoChanged(new CompatUIInfo(createTaskInfo(DISPLAY_ID, TASK_ID, - /* hasSizeCompat= */ true, CAMERA_COMPAT_CONTROL_HIDDEN), mMockTaskListener)); + /* hasSizeCompat= */ true), mMockTaskListener)); mController.onImeVisibilityChanged(DISPLAY_ID, /* isShowing= */ true); mController.onKeyguardVisibilityChanged(true, false, false); @@ -520,8 +511,7 @@ public class CompatUIControllerTest extends ShellTestCase { @Test @RequiresFlagsDisabled(Flags.FLAG_APP_COMPAT_UI_FRAMEWORK) public void testRestartLayoutRecreatedIfNeeded() { - final TaskInfo taskInfo = createTaskInfo(DISPLAY_ID, TASK_ID, - /* hasSizeCompat= */ true, CAMERA_COMPAT_CONTROL_HIDDEN); + final TaskInfo taskInfo = createTaskInfo(DISPLAY_ID, TASK_ID, /* hasSizeCompat= */ true); doReturn(true).when(mMockRestartDialogLayout) .needsToBeRecreated(any(TaskInfo.class), any(ShellTaskOrganizer.TaskListener.class)); @@ -536,8 +526,7 @@ public class CompatUIControllerTest extends ShellTestCase { @Test @RequiresFlagsDisabled(Flags.FLAG_APP_COMPAT_UI_FRAMEWORK) public void testRestartLayoutNotRecreatedIfNotNeeded() { - final TaskInfo taskInfo = createTaskInfo(DISPLAY_ID, TASK_ID, - /* hasSizeCompat= */ true, CAMERA_COMPAT_CONTROL_HIDDEN); + final TaskInfo taskInfo = createTaskInfo(DISPLAY_ID, TASK_ID, /* hasSizeCompat= */ true); doReturn(false).when(mMockRestartDialogLayout) .needsToBeRecreated(any(TaskInfo.class), any(ShellTaskOrganizer.TaskListener.class)); @@ -557,9 +546,8 @@ public class CompatUIControllerTest extends ShellTestCase { Assert.assertTrue(mController.hasShownUserAspectRatioSettingsButton()); // Create new task - final TaskInfo taskInfo = createTaskInfo(DISPLAY_ID, TASK_ID, - /* hasSizeCompat= */ true, CAMERA_COMPAT_CONTROL_HIDDEN, /* isVisible */ true, - /* isFocused */ true); + final TaskInfo taskInfo = createTaskInfo(DISPLAY_ID, TASK_ID, /* hasSizeCompat= */ true, + /* isVisible */ true, /* isFocused */ true); // Simulate new task being shown mController.updateActiveTaskInfo(taskInfo); @@ -574,9 +562,8 @@ public class CompatUIControllerTest extends ShellTestCase { @RequiresFlagsDisabled(Flags.FLAG_APP_COMPAT_UI_FRAMEWORK) public void testUpdateActiveTaskInfo_newTask_notVisibleOrFocused_notUpdated() { // Create new task - final TaskInfo taskInfo = createTaskInfo(DISPLAY_ID, TASK_ID, - /* hasSizeCompat= */ true, CAMERA_COMPAT_CONTROL_HIDDEN, /* isVisible */ true, - /* isFocused */ true); + final TaskInfo taskInfo = createTaskInfo(DISPLAY_ID, TASK_ID, /* hasSizeCompat= */ true, + /* isVisible */ true, /* isFocused */ true); // Simulate task being shown mController.updateActiveTaskInfo(taskInfo); @@ -593,9 +580,8 @@ public class CompatUIControllerTest extends ShellTestCase { final int newTaskId = TASK_ID + 1; // Create visible but NOT focused task - final TaskInfo taskInfo1 = createTaskInfo(DISPLAY_ID, newTaskId, - /* hasSizeCompat= */ true, CAMERA_COMPAT_CONTROL_HIDDEN, /* isVisible */ true, - /* isFocused */ false); + final TaskInfo taskInfo1 = createTaskInfo(DISPLAY_ID, newTaskId, /* hasSizeCompat= */ true, + /* isVisible */ true, /* isFocused */ false); // Simulate new task being shown mController.updateActiveTaskInfo(taskInfo1); @@ -606,9 +592,8 @@ public class CompatUIControllerTest extends ShellTestCase { Assert.assertTrue(mController.hasShownUserAspectRatioSettingsButton()); // Create focused but NOT visible task - final TaskInfo taskInfo2 = createTaskInfo(DISPLAY_ID, newTaskId, - /* hasSizeCompat= */ true, CAMERA_COMPAT_CONTROL_HIDDEN, /* isVisible */ false, - /* isFocused */ true); + final TaskInfo taskInfo2 = createTaskInfo(DISPLAY_ID, newTaskId, /* hasSizeCompat= */ true, + /* isVisible */ false, /* isFocused */ true); // Simulate new task being shown mController.updateActiveTaskInfo(taskInfo2); @@ -619,9 +604,8 @@ public class CompatUIControllerTest extends ShellTestCase { Assert.assertTrue(mController.hasShownUserAspectRatioSettingsButton()); // Create NOT focused but NOT visible task - final TaskInfo taskInfo3 = createTaskInfo(DISPLAY_ID, newTaskId, - /* hasSizeCompat= */ true, CAMERA_COMPAT_CONTROL_HIDDEN, /* isVisible */ false, - /* isFocused */ false); + final TaskInfo taskInfo3 = createTaskInfo(DISPLAY_ID, newTaskId, /* hasSizeCompat= */ true, + /* isVisible */ false, /* isFocused */ false); // Simulate new task being shown mController.updateActiveTaskInfo(taskInfo3); @@ -636,9 +620,8 @@ public class CompatUIControllerTest extends ShellTestCase { @RequiresFlagsDisabled(Flags.FLAG_APP_COMPAT_UI_FRAMEWORK) public void testUpdateActiveTaskInfo_sameTask_notUpdated() { // Create new task - final TaskInfo taskInfo = createTaskInfo(DISPLAY_ID, TASK_ID, - /* hasSizeCompat= */ true, CAMERA_COMPAT_CONTROL_HIDDEN, /* isVisible */ true, - /* isFocused */ true); + final TaskInfo taskInfo = createTaskInfo(DISPLAY_ID, TASK_ID, /* hasSizeCompat= */ true, + /* isVisible */ true, /* isFocused */ true); // Simulate new task being shown mController.updateActiveTaskInfo(taskInfo); @@ -665,9 +648,8 @@ public class CompatUIControllerTest extends ShellTestCase { @RequiresFlagsDisabled(Flags.FLAG_APP_COMPAT_UI_FRAMEWORK) public void testUpdateActiveTaskInfo_transparentTask_notUpdated() { // Create new task - final TaskInfo taskInfo = createTaskInfo(DISPLAY_ID, TASK_ID, - /* hasSizeCompat= */ true, CAMERA_COMPAT_CONTROL_HIDDEN, /* isVisible */ true, - /* isFocused */ true); + final TaskInfo taskInfo = createTaskInfo(DISPLAY_ID, TASK_ID, /* hasSizeCompat= */ true, + /* isVisible */ true, /* isFocused */ true); // Simulate new task being shown mController.updateActiveTaskInfo(taskInfo); @@ -684,9 +666,8 @@ public class CompatUIControllerTest extends ShellTestCase { final int newTaskId = TASK_ID + 1; // Create transparent task - final TaskInfo taskInfo1 = createTaskInfo(DISPLAY_ID, newTaskId, - /* hasSizeCompat= */ true, CAMERA_COMPAT_CONTROL_HIDDEN, /* isVisible */ true, - /* isFocused */ true, /* isTopActivityTransparent */ true); + final TaskInfo taskInfo1 = createTaskInfo(DISPLAY_ID, newTaskId, /* hasSizeCompat= */ true, + /* isVisible */ true, /* isFocused */ true, /* isTopActivityTransparent */ true); // Simulate new task being shown mController.updateActiveTaskInfo(taskInfo1); @@ -699,8 +680,7 @@ public class CompatUIControllerTest extends ShellTestCase { @Test public void testLetterboxEduLayout_notCreatedWhenLetterboxEducationIsDisabled() { - TaskInfo taskInfo = createTaskInfo(DISPLAY_ID, TASK_ID, /* hasSizeCompat= */ true, - CAMERA_COMPAT_CONTROL_HIDDEN); + TaskInfo taskInfo = createTaskInfo(DISPLAY_ID, TASK_ID, /* hasSizeCompat= */ true); taskInfo.appCompatTaskInfo.isLetterboxEducationEnabled = false; mController.onCompatInfoChanged(new CompatUIInfo(taskInfo, mMockTaskListener)); @@ -709,29 +689,23 @@ public class CompatUIControllerTest extends ShellTestCase { eq(mMockTaskListener)); } - private static TaskInfo createTaskInfo(int displayId, int taskId, boolean hasSizeCompat, - @CameraCompatControlState int cameraCompatControlState) { - return createTaskInfo(displayId, taskId, hasSizeCompat, cameraCompatControlState, - /* isVisible */ false, /* isFocused */ false, - /* isTopActivityTransparent */ false); + private static TaskInfo createTaskInfo(int displayId, int taskId, boolean hasSizeCompat) { + return createTaskInfo(displayId, taskId, hasSizeCompat, /* isVisible */ false, + /* isFocused */ false, /* isTopActivityTransparent */ false); } private static TaskInfo createTaskInfo(int displayId, int taskId, boolean hasSizeCompat, - @CameraCompatControlState int cameraCompatControlState, boolean isVisible, - boolean isFocused) { - return createTaskInfo(displayId, taskId, hasSizeCompat, cameraCompatControlState, + boolean isVisible, boolean isFocused) { + return createTaskInfo(displayId, taskId, hasSizeCompat, isVisible, isFocused, /* isTopActivityTransparent */ false); } private static TaskInfo createTaskInfo(int displayId, int taskId, boolean hasSizeCompat, - @CameraCompatControlState int cameraCompatControlState, boolean isVisible, - boolean isFocused, boolean isTopActivityTransparent) { + boolean isVisible, boolean isFocused, boolean isTopActivityTransparent) { RunningTaskInfo taskInfo = new RunningTaskInfo(); taskInfo.taskId = taskId; taskInfo.displayId = displayId; taskInfo.appCompatTaskInfo.topActivityInSizeCompat = hasSizeCompat; - taskInfo.appCompatTaskInfo.cameraCompatTaskInfo.cameraCompatControlState = - cameraCompatControlState; taskInfo.isVisible = isVisible; taskInfo.isFocused = isFocused; taskInfo.isTopActivityTransparent = isTopActivityTransparent; diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUILayoutTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUILayoutTest.java index 33d69f5c34c8..3b93861d6cd2 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUILayoutTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUILayoutTest.java @@ -16,20 +16,13 @@ package com.android.wm.shell.compatui; -import static android.app.CameraCompatTaskInfo.CAMERA_COMPAT_CONTROL_DISMISSED; -import static android.app.CameraCompatTaskInfo.CAMERA_COMPAT_CONTROL_HIDDEN; -import static android.app.CameraCompatTaskInfo.CAMERA_COMPAT_CONTROL_TREATMENT_APPLIED; -import static android.app.CameraCompatTaskInfo.CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED; - import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; -import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.verify; import android.app.ActivityManager; -import android.app.CameraCompatTaskInfo.CameraCompatControlState; import android.app.TaskInfo; import android.graphics.Rect; import android.platform.test.annotations.RequiresFlagsDisabled; @@ -52,7 +45,6 @@ import com.android.wm.shell.common.DisplayLayout; import com.android.wm.shell.common.SyncTransactionQueue; import com.android.wm.shell.compatui.CompatUIController.CompatUIHintsState; import com.android.wm.shell.compatui.api.CompatUIEvent; -import com.android.wm.shell.compatui.impl.CompatUIEvents; import junit.framework.Assert; @@ -97,7 +89,7 @@ public class CompatUILayoutTest extends ShellTestCase { public void setUp() { MockitoAnnotations.initMocks(this); doReturn(100).when(mCompatUIConfiguration).getHideSizeCompatRestartButtonTolerance(); - mTaskInfo = createTaskInfo(/* hasSizeCompat= */ false, CAMERA_COMPAT_CONTROL_HIDDEN); + mTaskInfo = createTaskInfo(/* hasSizeCompat= */ false); mWindowManager = new CompatUIWindowManager(mContext, mTaskInfo, mSyncTransactionQueue, mCallback, mTaskListener, new DisplayLayout(), new CompatUIHintsState(), mCompatUIConfiguration, mOnRestartButtonClicked); @@ -151,113 +143,13 @@ public class CompatUILayoutTest extends ShellTestCase { verify(mLayout).setSizeCompatHintVisibility(/* show= */ false); } - @Test - @RequiresFlagsDisabled(Flags.FLAG_APP_COMPAT_UI_FRAMEWORK) - public void testUpdateCameraTreatmentButton_treatmentAppliedByDefault() { - mWindowManager.mCameraCompatControlState = CAMERA_COMPAT_CONTROL_TREATMENT_APPLIED; - mWindowManager.createLayout(/* canShow= */ true); - final ImageButton button = - mLayout.findViewById(R.id.camera_compat_treatment_button); - button.performClick(); - - verify(mWindowManager).onCameraTreatmentButtonClicked(); - verifyOnCameraControlStateUpdatedInvokedWith(TASK_ID, - CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED); - - button.performClick(); - - verifyOnCameraControlStateUpdatedInvokedWith(TASK_ID, - CAMERA_COMPAT_CONTROL_TREATMENT_APPLIED); - } - - @Test - @RequiresFlagsDisabled(Flags.FLAG_APP_COMPAT_UI_FRAMEWORK) - public void testUpdateCameraTreatmentButton_treatmentSuggestedByDefault() { - mWindowManager.mCameraCompatControlState = CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED; - mWindowManager.createLayout(/* canShow= */ true); - final ImageButton button = - mLayout.findViewById(R.id.camera_compat_treatment_button); - button.performClick(); - - verify(mWindowManager).onCameraTreatmentButtonClicked(); - verifyOnCameraControlStateUpdatedInvokedWith(TASK_ID, - CAMERA_COMPAT_CONTROL_TREATMENT_APPLIED); - - button.performClick(); - - verifyOnCameraControlStateUpdatedInvokedWith(TASK_ID, - CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED); - } - - @Test - @RequiresFlagsDisabled(Flags.FLAG_APP_COMPAT_UI_FRAMEWORK) - public void testOnCameraDismissButtonClicked() { - mWindowManager.mCameraCompatControlState = CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED; - mWindowManager.createLayout(/* canShow= */ true); - final ImageButton button = - mLayout.findViewById(R.id.camera_compat_dismiss_button); - button.performClick(); - - verify(mWindowManager).onCameraDismissButtonClicked(); - verifyOnCameraControlStateUpdatedInvokedWith(TASK_ID, CAMERA_COMPAT_CONTROL_DISMISSED); - verify(mLayout).setCameraControlVisibility(/* show */ false); - } - - @Test - @RequiresFlagsDisabled(Flags.FLAG_APP_COMPAT_UI_FRAMEWORK) - public void testOnLongClickForCameraTreatmentButton() { - doNothing().when(mWindowManager).onCameraButtonLongClicked(); - - final ImageButton button = - mLayout.findViewById(R.id.camera_compat_treatment_button); - button.performLongClick(); - - verify(mWindowManager).onCameraButtonLongClicked(); - } - - @Test - @RequiresFlagsDisabled(Flags.FLAG_APP_COMPAT_UI_FRAMEWORK) - public void testOnLongClickForCameraDismissButton() { - doNothing().when(mWindowManager).onCameraButtonLongClicked(); - - final ImageButton button = mLayout.findViewById(R.id.camera_compat_dismiss_button); - button.performLongClick(); - - verify(mWindowManager).onCameraButtonLongClicked(); - } - - @Test - @RequiresFlagsDisabled(Flags.FLAG_APP_COMPAT_UI_FRAMEWORK) - public void testOnClickForCameraCompatHint() { - mWindowManager.mCameraCompatControlState = CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED; - mWindowManager.createLayout(/* canShow= */ true); - final LinearLayout hint = mLayout.findViewById(R.id.camera_compat_hint); - hint.performClick(); - - verify(mLayout).setCameraCompatHintVisibility(/* show= */ false); - } - - private static TaskInfo createTaskInfo(boolean hasSizeCompat, - @CameraCompatControlState int cameraCompatControlState) { + private static TaskInfo createTaskInfo(boolean hasSizeCompat) { ActivityManager.RunningTaskInfo taskInfo = new ActivityManager.RunningTaskInfo(); taskInfo.taskId = TASK_ID; taskInfo.appCompatTaskInfo.topActivityInSizeCompat = hasSizeCompat; - taskInfo.appCompatTaskInfo.cameraCompatTaskInfo.cameraCompatControlState = - cameraCompatControlState; taskInfo.appCompatTaskInfo.topActivityLetterboxHeight = 1000; taskInfo.appCompatTaskInfo.topActivityLetterboxWidth = 1000; taskInfo.configuration.windowConfiguration.setBounds(new Rect(0, 0, 2000, 2000)); return taskInfo; } - - private void verifyOnCameraControlStateUpdatedInvokedWith(int taskId, int state) { - final ArgumentCaptor<CompatUIEvent> captureValue = ArgumentCaptor.forClass( - CompatUIEvent.class); - verify(mCallback).accept(captureValue.capture()); - final CompatUIEvents.CameraControlStateUpdated compatUIEvent = - (CompatUIEvents.CameraControlStateUpdated) captureValue.getValue(); - Assert.assertEquals((compatUIEvent).getTaskId(), taskId); - Assert.assertEquals((compatUIEvent).getState(), state); - clearInvocations(mCallback); - } } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIWindowManagerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIWindowManagerTest.java index eb3da8f65b5d..c5033f3ae64b 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIWindowManagerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIWindowManagerTest.java @@ -16,10 +16,6 @@ package com.android.wm.shell.compatui; -import static android.app.CameraCompatTaskInfo.CAMERA_COMPAT_CONTROL_DISMISSED; -import static android.app.CameraCompatTaskInfo.CAMERA_COMPAT_CONTROL_HIDDEN; -import static android.app.CameraCompatTaskInfo.CAMERA_COMPAT_CONTROL_TREATMENT_APPLIED; -import static android.app.CameraCompatTaskInfo.CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED; import static android.platform.test.flag.junit.SetFlagsRule.DefaultInitValueType.DEVICE_DEFAULT; import static android.view.WindowInsets.Type.navigationBars; import static android.view.WindowManager.LARGE_SCREEN_SMALLEST_SCREEN_WIDTH_DP; @@ -36,10 +32,10 @@ import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import android.app.ActivityManager; -import android.app.CameraCompatTaskInfo; import android.app.TaskInfo; import android.content.res.Configuration; import android.graphics.Rect; @@ -65,7 +61,6 @@ import com.android.wm.shell.common.DisplayLayout; import com.android.wm.shell.common.SyncTransactionQueue; import com.android.wm.shell.compatui.CompatUIController.CompatUIHintsState; import com.android.wm.shell.compatui.api.CompatUIEvent; -import com.android.wm.shell.compatui.impl.CompatUIEvents; import junit.framework.Assert; @@ -115,7 +110,7 @@ public class CompatUIWindowManagerTest extends ShellTestCase { public void setUp() { MockitoAnnotations.initMocks(this); doReturn(100).when(mCompatUIConfiguration).getHideSizeCompatRestartButtonTolerance(); - mTaskInfo = createTaskInfo(/* hasSizeCompat= */ false, CAMERA_COMPAT_CONTROL_HIDDEN); + mTaskInfo = createTaskInfo(/* hasSizeCompat= */ false); final DisplayInfo displayInfo = new DisplayInfo(); displayInfo.logicalWidth = TASK_WIDTH; @@ -186,45 +181,6 @@ public class CompatUIWindowManagerTest extends ShellTestCase { @Test @RequiresFlagsDisabled(FLAG_APP_COMPAT_UI_FRAMEWORK) - public void testCreateCameraCompatControl() { - // Doesn't create layout if show is false. - mWindowManager.mCameraCompatControlState = CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED; - assertTrue(mWindowManager.createLayout(/* canShow= */ false)); - - verify(mWindowManager, never()).inflateLayout(); - - // Doesn't create hint popup. - mWindowManager.mCompatUIHintsState.mHasShownCameraCompatHint = true; - assertTrue(mWindowManager.createLayout(/* canShow= */ true)); - - verify(mWindowManager).inflateLayout(); - verify(mLayout).setCameraControlVisibility(/* show= */ true); - verify(mLayout, never()).setCameraCompatHintVisibility(/* show= */ true); - - // Creates hint popup. - clearInvocations(mWindowManager); - clearInvocations(mLayout); - mWindowManager.release(); - mWindowManager.mCompatUIHintsState.mHasShownCameraCompatHint = false; - assertTrue(mWindowManager.createLayout(/* canShow= */ true)); - - verify(mWindowManager).inflateLayout(); - assertNotNull(mLayout); - verify(mLayout).setCameraControlVisibility(/* show= */ true); - verify(mLayout).setCameraCompatHintVisibility(/* show= */ true); - assertTrue(mWindowManager.mCompatUIHintsState.mHasShownCameraCompatHint); - - // Returns false and doesn't create layout if Camera Compat state is hidden - clearInvocations(mWindowManager); - mWindowManager.release(); - mWindowManager.mCameraCompatControlState = CAMERA_COMPAT_CONTROL_HIDDEN; - assertFalse(mWindowManager.createLayout(/* canShow= */ true)); - - verify(mWindowManager, never()).inflateLayout(); - } - - @Test - @RequiresFlagsDisabled(FLAG_APP_COMPAT_UI_FRAMEWORK) public void testRelease() { mWindowManager.mHasSizeCompat = true; mWindowManager.createLayout(/* canShow= */ true); @@ -241,10 +197,11 @@ public class CompatUIWindowManagerTest extends ShellTestCase { public void testUpdateCompatInfo() { mWindowManager.mHasSizeCompat = true; mWindowManager.createLayout(/* canShow= */ true); + verify(mLayout).setRestartButtonVisibility(/* show= */ true); // No diff clearInvocations(mWindowManager); - TaskInfo taskInfo = createTaskInfo(/* hasSizeCompat= */ true, CAMERA_COMPAT_CONTROL_HIDDEN); + TaskInfo taskInfo = createTaskInfo(/* hasSizeCompat= */ true); doReturn(true).when(mWindowManager).shouldShowSizeCompatRestartButton(any()); assertTrue(mWindowManager.updateCompatInfo(taskInfo, mTaskListener, /* canShow= */ true)); @@ -261,58 +218,25 @@ public class CompatUIWindowManagerTest extends ShellTestCase { verify(mWindowManager).release(); verify(mWindowManager).createLayout(/* canShow= */ true); - // Change Camera Compat state, show a control. - clearInvocations(mWindowManager); - clearInvocations(mLayout); - taskInfo = createTaskInfo(/* hasSizeCompat= */ true, - CAMERA_COMPAT_CONTROL_TREATMENT_APPLIED); - assertTrue(mWindowManager.updateCompatInfo(taskInfo, newTaskListener, /* canShow= */ true)); - - verify(mLayout).setCameraControlVisibility(/* show= */ true); - verify(mLayout).updateCameraTreatmentButton( - CAMERA_COMPAT_CONTROL_TREATMENT_APPLIED); - - // Change Camera Compat state, update a control. - clearInvocations(mWindowManager); - clearInvocations(mLayout); - taskInfo = createTaskInfo(/* hasSizeCompat= */ true, - CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED); - assertTrue(mWindowManager.updateCompatInfo(taskInfo, newTaskListener, /* canShow= */ true)); - - verify(mLayout).setCameraControlVisibility(/* show= */ true); - verify(mLayout).updateCameraTreatmentButton( - CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED); - - // Change has Size Compat to false, hides restart button. + // Change has Size Compat to false, no more CompatIU. clearInvocations(mWindowManager); clearInvocations(mLayout); - taskInfo = createTaskInfo(/* hasSizeCompat= */ false, - CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED); - assertTrue(mWindowManager.updateCompatInfo(taskInfo, newTaskListener, /* canShow= */ true)); - - verify(mLayout).setRestartButtonVisibility(/* show= */ false); + taskInfo = createTaskInfo(/* hasSizeCompat= */ false); + assertFalse(mWindowManager.updateCompatInfo(taskInfo, newTaskListener, + /* canShow= */ true)); // Change has Size Compat to true, shows restart button. clearInvocations(mWindowManager); clearInvocations(mLayout); - taskInfo = createTaskInfo(/* hasSizeCompat= */ true, - CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED); - assertTrue(mWindowManager.updateCompatInfo(taskInfo, newTaskListener, /* canShow= */ true)); - - verify(mLayout).setRestartButtonVisibility(/* show= */ true); - - // Change Camera Compat state to dismissed, hide a control. - clearInvocations(mWindowManager); - clearInvocations(mLayout); - taskInfo = createTaskInfo(/* hasSizeCompat= */ true, CAMERA_COMPAT_CONTROL_DISMISSED); + taskInfo = createTaskInfo(/* hasSizeCompat= */ true); assertTrue(mWindowManager.updateCompatInfo(taskInfo, newTaskListener, /* canShow= */ true)); - verify(mLayout).setCameraControlVisibility(/* show= */ false); + verify(mLayout, times(2)).setRestartButtonVisibility(/* show= */ true); // Change task bounds, update position. clearInvocations(mWindowManager); clearInvocations(mLayout); - taskInfo = createTaskInfo(/* hasSizeCompat= */ true, CAMERA_COMPAT_CONTROL_HIDDEN); + taskInfo = createTaskInfo(/* hasSizeCompat= */ true); taskInfo.configuration.windowConfiguration.setBounds(new Rect(0, 1000, 0, 2000)); assertTrue(mWindowManager.updateCompatInfo(taskInfo, newTaskListener, /* canShow= */ true)); @@ -321,7 +245,7 @@ public class CompatUIWindowManagerTest extends ShellTestCase { // Change has Size Compat to false, release layout. clearInvocations(mWindowManager); clearInvocations(mLayout); - taskInfo = createTaskInfo(/* hasSizeCompat= */ false, CAMERA_COMPAT_CONTROL_HIDDEN); + taskInfo = createTaskInfo(/* hasSizeCompat= */ false); assertFalse( mWindowManager.updateCompatInfo(taskInfo, newTaskListener, /* canShow= */ true)); @@ -338,15 +262,14 @@ public class CompatUIWindowManagerTest extends ShellTestCase { // Change topActivityInSizeCompat to false and pass canShow true, layout shouldn't be // inflated clearInvocations(mWindowManager); - TaskInfo taskInfo = createTaskInfo(/* hasSizeCompat= */ false, - CAMERA_COMPAT_CONTROL_HIDDEN); + TaskInfo taskInfo = createTaskInfo(/* hasSizeCompat= */ false); mWindowManager.updateCompatInfo(taskInfo, mTaskListener, /* canShow= */ true); verify(mWindowManager, never()).inflateLayout(); // Change topActivityInSizeCompat to true and pass canShow true, layout should be inflated. clearInvocations(mWindowManager); - taskInfo = createTaskInfo(/* hasSizeCompat= */ true, CAMERA_COMPAT_CONTROL_HIDDEN); + taskInfo = createTaskInfo(/* hasSizeCompat= */ true); mWindowManager.updateCompatInfo(taskInfo, mTaskListener, /* canShow= */ true); verify(mWindowManager).inflateLayout(); @@ -443,37 +366,6 @@ public class CompatUIWindowManagerTest extends ShellTestCase { @Test @RequiresFlagsDisabled(FLAG_APP_COMPAT_UI_FRAMEWORK) - public void testOnCameraDismissButtonClicked() { - mWindowManager.mCameraCompatControlState = CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED; - mWindowManager.createLayout(/* canShow= */ true); - clearInvocations(mLayout); - mWindowManager.onCameraDismissButtonClicked(); - - verifyOnCameraControlStateUpdatedInvokedWith(TASK_ID, CAMERA_COMPAT_CONTROL_DISMISSED); - verify(mLayout).setCameraControlVisibility(/* show= */ false); - } - - @Test - @RequiresFlagsDisabled(FLAG_APP_COMPAT_UI_FRAMEWORK) - public void testOnCameraTreatmentButtonClicked() { - mWindowManager.mCameraCompatControlState = CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED; - mWindowManager.createLayout(/* canShow= */ true); - clearInvocations(mLayout); - mWindowManager.onCameraTreatmentButtonClicked(); - - verifyOnCameraControlStateUpdatedInvokedWith(TASK_ID, - CAMERA_COMPAT_CONTROL_TREATMENT_APPLIED); - verify(mLayout).updateCameraTreatmentButton(CAMERA_COMPAT_CONTROL_TREATMENT_APPLIED); - - mWindowManager.onCameraTreatmentButtonClicked(); - - verifyOnCameraControlStateUpdatedInvokedWith(TASK_ID, - CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED); - verify(mLayout).updateCameraTreatmentButton(CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED); - } - - @Test - @RequiresFlagsDisabled(FLAG_APP_COMPAT_UI_FRAMEWORK) public void testOnRestartButtonClicked() { mWindowManager.onRestartButtonClicked(); @@ -505,22 +397,6 @@ public class CompatUIWindowManagerTest extends ShellTestCase { @Test @RequiresFlagsDisabled(FLAG_APP_COMPAT_UI_FRAMEWORK) - public void testOnCameraControlLongClicked_showHint() { - // Not create hint popup. - mWindowManager.mCameraCompatControlState = CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED; - mWindowManager.mCompatUIHintsState.mHasShownCameraCompatHint = true; - mWindowManager.createLayout(/* canShow= */ true); - - verify(mWindowManager).inflateLayout(); - verify(mLayout, never()).setCameraCompatHintVisibility(/* show= */ true); - - mWindowManager.onCameraButtonLongClicked(); - - verify(mLayout).setCameraCompatHintVisibility(/* show= */ true); - } - - @Test - @RequiresFlagsDisabled(FLAG_APP_COMPAT_UI_FRAMEWORK) public void testWhenDockedStateHasChanged_needsToBeRecreated() { ActivityManager.RunningTaskInfo newTaskInfo = new ActivityManager.RunningTaskInfo(); newTaskInfo.configuration.uiMode |= Configuration.UI_MODE_TYPE_DESK; @@ -538,7 +414,7 @@ public class CompatUIWindowManagerTest extends ShellTestCase { mCompatUIConfiguration, mOnRestartButtonClicked); // Simulate rotation of activity in square display - TaskInfo taskInfo = createTaskInfo(true, CAMERA_COMPAT_CONTROL_HIDDEN); + TaskInfo taskInfo = createTaskInfo(true); taskInfo.appCompatTaskInfo.topActivityLetterboxHeight = TASK_HEIGHT; taskInfo.appCompatTaskInfo.topActivityLetterboxWidth = 1850; @@ -567,13 +443,10 @@ public class CompatUIWindowManagerTest extends ShellTestCase { assertTrue(mWindowManager.shouldShowSizeCompatRestartButton(taskInfo)); } - private static TaskInfo createTaskInfo(boolean hasSizeCompat, - @CameraCompatTaskInfo.CameraCompatControlState int cameraCompatControlState) { + private static TaskInfo createTaskInfo(boolean hasSizeCompat) { ActivityManager.RunningTaskInfo taskInfo = new ActivityManager.RunningTaskInfo(); taskInfo.taskId = TASK_ID; taskInfo.appCompatTaskInfo.topActivityInSizeCompat = hasSizeCompat; - taskInfo.appCompatTaskInfo.cameraCompatTaskInfo.cameraCompatControlState = - cameraCompatControlState; taskInfo.configuration.uiMode &= ~Configuration.UI_MODE_TYPE_DESK; // Letterboxed activity that takes half the screen should show size compat restart button taskInfo.appCompatTaskInfo.topActivityLetterboxHeight = 1000; @@ -582,15 +455,4 @@ public class CompatUIWindowManagerTest extends ShellTestCase { taskInfo.configuration.smallestScreenWidthDp = LARGE_SCREEN_SMALLEST_SCREEN_WIDTH_DP; return taskInfo; } - - private void verifyOnCameraControlStateUpdatedInvokedWith(int taskId, int state) { - final ArgumentCaptor<CompatUIEvent> captureValue = ArgumentCaptor.forClass( - CompatUIEvent.class); - verify(mCallback).accept(captureValue.capture()); - final CompatUIEvents.CameraControlStateUpdated compatUIEvent = - (CompatUIEvents.CameraControlStateUpdated) captureValue.getValue(); - Assert.assertEquals((compatUIEvent).getTaskId(), taskId); - Assert.assertEquals((compatUIEvent).getState(), state); - clearInvocations(mCallback); - } } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/UserAspectRatioSettingsLayoutTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/UserAspectRatioSettingsLayoutTest.java index 3fa21cee0d68..7a641960a2c5 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/UserAspectRatioSettingsLayoutTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/UserAspectRatioSettingsLayoutTest.java @@ -16,8 +16,6 @@ package com.android.wm.shell.compatui; -import static android.app.CameraCompatTaskInfo.CAMERA_COMPAT_CONTROL_HIDDEN; - import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; import static com.android.window.flags.Flags.FLAG_APP_COMPAT_UI_FRAMEWORK; @@ -26,7 +24,6 @@ import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.verify; import android.app.ActivityManager; -import android.app.CameraCompatTaskInfo.CameraCompatControlState; import android.app.TaskInfo; import android.content.ComponentName; import android.platform.test.annotations.RequiresFlagsDisabled; @@ -98,7 +95,7 @@ public class UserAspectRatioSettingsLayoutTest extends ShellTestCase { @Before public void setUp() { MockitoAnnotations.initMocks(this); - mTaskInfo = createTaskInfo(/* hasSizeCompat= */ false, CAMERA_COMPAT_CONTROL_HIDDEN); + mTaskInfo = createTaskInfo(/* hasSizeCompat= */ false); mWindowManager = new UserAspectRatioSettingsWindowManager(mContext, mTaskInfo, mSyncTransactionQueue, mTaskListener, new DisplayLayout(), new CompatUIController.CompatUIHintsState(), @@ -155,13 +152,10 @@ public class UserAspectRatioSettingsLayoutTest extends ShellTestCase { verify(mLayout).setUserAspectRatioSettingsHintVisibility(/* show= */ false); } - private static TaskInfo createTaskInfo(boolean hasSizeCompat, - @CameraCompatControlState int cameraCompatControlState) { + private static TaskInfo createTaskInfo(boolean hasSizeCompat) { ActivityManager.RunningTaskInfo taskInfo = new ActivityManager.RunningTaskInfo(); taskInfo.taskId = TASK_ID; taskInfo.appCompatTaskInfo.topActivityInSizeCompat = hasSizeCompat; - taskInfo.appCompatTaskInfo.cameraCompatTaskInfo.cameraCompatControlState = - cameraCompatControlState; taskInfo.realActivity = new ComponentName("com.mypackage.test", "TestActivity"); return taskInfo; } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepositoryTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepositoryTest.kt index 18b08bfb0f47..d3404f7bd261 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepositoryTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepositoryTest.kt @@ -41,32 +41,44 @@ class DesktopModeTaskRepositoryTest : ShellTestCase() { } @Test - fun addActiveTask_listenerNotifiedAndTaskIsActive() { + fun addActiveTask_notifiesListener() { val listener = TestListener() repo.addActiveTaskListener(listener) repo.addActiveTask(DEFAULT_DISPLAY, taskId = 1) + assertThat(listener.activeChangesOnDefaultDisplay).isEqualTo(1) + } + + @Test + fun addActiveTask_taskIsActive() { + val listener = TestListener() + repo.addActiveTaskListener(listener) + + repo.addActiveTask(DEFAULT_DISPLAY, taskId = 1) + assertThat(repo.isActiveTask(1)).isTrue() } @Test - fun addActiveTask_sameTaskDoesNotNotify() { + fun addSameActiveTaskTwice_notifiesOnce() { val listener = TestListener() repo.addActiveTaskListener(listener) repo.addActiveTask(DEFAULT_DISPLAY, taskId = 1) repo.addActiveTask(DEFAULT_DISPLAY, taskId = 1) + assertThat(listener.activeChangesOnDefaultDisplay).isEqualTo(1) } @Test - fun addActiveTask_multipleTasksAddedNotifiesForEach() { + fun addActiveTask_multipleTasksAdded_notifiesForAllTasks() { val listener = TestListener() repo.addActiveTaskListener(listener) repo.addActiveTask(DEFAULT_DISPLAY, taskId = 1) repo.addActiveTask(DEFAULT_DISPLAY, taskId = 2) + assertThat(listener.activeChangesOnDefaultDisplay).isEqualTo(2) } @@ -84,22 +96,35 @@ class DesktopModeTaskRepositoryTest : ShellTestCase() { } @Test - fun removeActiveTask_listenerNotifiedAndTaskNotActive() { + fun removeActiveTask_notifiesListener() { val listener = TestListener() repo.addActiveTaskListener(listener) - repo.addActiveTask(DEFAULT_DISPLAY, taskId = 1) + repo.removeActiveTask(1) + // Notify once for add and once for remove assertThat(listener.activeChangesOnDefaultDisplay).isEqualTo(2) + } + + @Test + fun removeActiveTask_taskNotActive() { + val listener = TestListener() + repo.addActiveTaskListener(listener) + repo.addActiveTask(DEFAULT_DISPLAY, taskId = 1) + + repo.removeActiveTask(1) + assertThat(repo.isActiveTask(1)).isFalse() } @Test - fun removeActiveTask_removeNotExistingTaskDoesNotNotify() { + fun removeActiveTask_nonExistingTask_doesNotNotify() { val listener = TestListener() repo.addActiveTaskListener(listener) + repo.removeActiveTask(99) + assertThat(listener.activeChangesOnDefaultDisplay).isEqualTo(0) } @@ -108,32 +133,38 @@ class DesktopModeTaskRepositoryTest : ShellTestCase() { val listener = TestListener() repo.addActiveTaskListener(listener) repo.addActiveTask(DEFAULT_DISPLAY, taskId = 1) + repo.removeActiveTask(1) + assertThat(listener.activeChangesOnSecondaryDisplay).isEqualTo(0) assertThat(repo.isActiveTask(1)).isFalse() } @Test - fun isActiveTask_notExistingTaskReturnsFalse() { + fun isActiveTask_nonExistingTask_returnsFalse() { assertThat(repo.isActiveTask(99)).isFalse() } @Test - fun isOnlyVisibleNonClosingTask_noTasks() { + fun isOnlyVisibleNonClosingTask_noTasks_returnsFalse() { // No visible tasks assertThat(repo.isOnlyVisibleNonClosingTask(1)).isFalse() + } + + @Test + fun isClosingTask_noTasks_returnsFalse() { + // No visible tasks assertThat(repo.isClosingTask(1)).isFalse() } @Test - fun isOnlyVisibleNonClosingTask_singleVisibleNonClosingTask() { - repo.updateVisibleFreeformTasks(DEFAULT_DISPLAY, taskId = 1, visible = true) + fun updateTaskVisibility_singleVisibleNonClosingTask_updatesTasksCorrectly() { + repo.updateTaskVisibility(DEFAULT_DISPLAY, taskId = 1, visible = true) - // The only visible task assertThat(repo.isVisibleTask(1)).isTrue() assertThat(repo.isClosingTask(1)).isFalse() assertThat(repo.isOnlyVisibleNonClosingTask(1)).isTrue() - // Not a visible task + assertThat(repo.isVisibleTask(99)).isFalse() assertThat(repo.isClosingTask(99)).isFalse() assertThat(repo.isOnlyVisibleNonClosingTask(99)).isFalse() @@ -141,7 +172,7 @@ class DesktopModeTaskRepositoryTest : ShellTestCase() { @Test fun isOnlyVisibleNonClosingTask_singleVisibleClosingTask() { - repo.updateVisibleFreeformTasks(DEFAULT_DISPLAY, taskId = 1, visible = true) + repo.updateTaskVisibility(DEFAULT_DISPLAY, taskId = 1, visible = true) repo.addClosingTask(DEFAULT_DISPLAY, 1) // A visible task that's closing @@ -155,7 +186,7 @@ class DesktopModeTaskRepositoryTest : ShellTestCase() { @Test fun isOnlyVisibleNonClosingTask_singleVisibleMinimizedTask() { - repo.updateVisibleFreeformTasks(DEFAULT_DISPLAY, taskId = 1, visible = true) + repo.updateTaskVisibility(DEFAULT_DISPLAY, taskId = 1, visible = true) repo.minimizeTask(DEFAULT_DISPLAY, 1) // The visible task that's closing @@ -169,8 +200,8 @@ class DesktopModeTaskRepositoryTest : ShellTestCase() { @Test fun isOnlyVisibleNonClosingTask_multipleVisibleNonClosingTasks() { - repo.updateVisibleFreeformTasks(DEFAULT_DISPLAY, taskId = 1, visible = true) - repo.updateVisibleFreeformTasks(DEFAULT_DISPLAY, taskId = 2, visible = true) + repo.updateTaskVisibility(DEFAULT_DISPLAY, taskId = 1, visible = true) + repo.updateTaskVisibility(DEFAULT_DISPLAY, taskId = 2, visible = true) // Not the only task assertThat(repo.isVisibleTask(1)).isTrue() @@ -188,9 +219,9 @@ class DesktopModeTaskRepositoryTest : ShellTestCase() { @Test fun isOnlyVisibleNonClosingTask_multipleDisplays() { - repo.updateVisibleFreeformTasks(DEFAULT_DISPLAY, taskId = 1, visible = true) - repo.updateVisibleFreeformTasks(DEFAULT_DISPLAY, taskId = 2, visible = true) - repo.updateVisibleFreeformTasks(SECOND_DISPLAY, taskId = 3, visible = true) + repo.updateTaskVisibility(DEFAULT_DISPLAY, taskId = 1, visible = true) + repo.updateTaskVisibility(DEFAULT_DISPLAY, taskId = 2, visible = true) + repo.updateTaskVisibility(SECOND_DISPLAY, taskId = 3, visible = true) // Not the only task on DEFAULT_DISPLAY assertThat(repo.isVisibleTask(1)).isTrue() @@ -207,10 +238,11 @@ class DesktopModeTaskRepositoryTest : ShellTestCase() { } @Test - fun addListener_notifiesVisibleFreeformTask() { - repo.updateVisibleFreeformTasks(DEFAULT_DISPLAY, taskId = 1, visible = true) + fun addVisibleTasksListener_notifiesVisibleFreeformTask() { + repo.updateTaskVisibility(DEFAULT_DISPLAY, taskId = 1, visible = true) val listener = TestVisibilityListener() val executor = TestShellExecutor() + repo.addVisibleTasksListener(listener, executor) executor.flushAll() @@ -220,7 +252,7 @@ class DesktopModeTaskRepositoryTest : ShellTestCase() { @Test fun addListener_tasksOnDifferentDisplay_doesNotNotify() { - repo.updateVisibleFreeformTasks(SECOND_DISPLAY, taskId = 1, visible = true) + repo.updateTaskVisibility(SECOND_DISPLAY, taskId = 1, visible = true) val listener = TestVisibilityListener() val executor = TestShellExecutor() repo.addVisibleTasksListener(listener, executor) @@ -232,12 +264,13 @@ class DesktopModeTaskRepositoryTest : ShellTestCase() { } @Test - fun updateVisibleFreeformTasks_addVisibleTasksNotifiesListener() { + fun updateTaskVisibility_addVisibleTasksNotifiesListener() { val listener = TestVisibilityListener() val executor = TestShellExecutor() repo.addVisibleTasksListener(listener, executor) - repo.updateVisibleFreeformTasks(DEFAULT_DISPLAY, taskId = 1, visible = true) - repo.updateVisibleFreeformTasks(DEFAULT_DISPLAY, taskId = 2, visible = true) + + repo.updateTaskVisibility(DEFAULT_DISPLAY, taskId = 1, visible = true) + repo.updateTaskVisibility(DEFAULT_DISPLAY, taskId = 2, visible = true) executor.flushAll() assertThat(listener.visibleTasksCountOnDefaultDisplay).isEqualTo(2) @@ -245,12 +278,12 @@ class DesktopModeTaskRepositoryTest : ShellTestCase() { } @Test - fun updateVisibleFreeformTasks_addVisibleTaskNotifiesListenerForThatDisplay() { + fun updateTaskVisibility_addVisibleTaskNotifiesListenerForThatDisplay() { val listener = TestVisibilityListener() val executor = TestShellExecutor() repo.addVisibleTasksListener(listener, executor) - repo.updateVisibleFreeformTasks(DEFAULT_DISPLAY, taskId = 1, visible = true) + repo.updateTaskVisibility(DEFAULT_DISPLAY, taskId = 1, visible = true) executor.flushAll() assertThat(listener.visibleTasksCountOnDefaultDisplay).isEqualTo(1) @@ -258,7 +291,7 @@ class DesktopModeTaskRepositoryTest : ShellTestCase() { assertThat(listener.visibleTasksCountOnSecondaryDisplay).isEqualTo(0) assertThat(listener.visibleChangesOnSecondaryDisplay).isEqualTo(0) - repo.updateVisibleFreeformTasks(displayId = 1, taskId = 2, visible = true) + repo.updateTaskVisibility(displayId = 1, taskId = 2, visible = true) executor.flushAll() // Listener for secondary display is notified @@ -269,17 +302,17 @@ class DesktopModeTaskRepositoryTest : ShellTestCase() { } @Test - fun updateVisibleFreeformTasks_taskOnDefaultBecomesVisibleOnSecondDisplay_listenersNotified() { + fun updateTaskVisibility_taskOnDefaultBecomesVisibleOnSecondDisplay_listenersNotified() { val listener = TestVisibilityListener() val executor = TestShellExecutor() repo.addVisibleTasksListener(listener, executor) - repo.updateVisibleFreeformTasks(DEFAULT_DISPLAY, taskId = 1, visible = true) + repo.updateTaskVisibility(DEFAULT_DISPLAY, taskId = 1, visible = true) executor.flushAll() assertThat(listener.visibleTasksCountOnDefaultDisplay).isEqualTo(1) // Mark task 1 visible on secondary display - repo.updateVisibleFreeformTasks(displayId = 1, taskId = 1, visible = true) + repo.updateTaskVisibility(displayId = 1, taskId = 1, visible = true) executor.flushAll() // Default display should have 2 calls @@ -294,21 +327,22 @@ class DesktopModeTaskRepositoryTest : ShellTestCase() { } @Test - fun updateVisibleFreeformTasks_removeVisibleTasksNotifiesListener() { + fun updateTaskVisibility_removeVisibleTasksNotifiesListener() { val listener = TestVisibilityListener() val executor = TestShellExecutor() repo.addVisibleTasksListener(listener, executor) - repo.updateVisibleFreeformTasks(DEFAULT_DISPLAY, taskId = 1, visible = true) - repo.updateVisibleFreeformTasks(DEFAULT_DISPLAY, taskId = 2, visible = true) + repo.updateTaskVisibility(DEFAULT_DISPLAY, taskId = 1, visible = true) + repo.updateTaskVisibility(DEFAULT_DISPLAY, taskId = 2, visible = true) executor.flushAll() assertThat(listener.visibleTasksCountOnDefaultDisplay).isEqualTo(2) - repo.updateVisibleFreeformTasks(DEFAULT_DISPLAY, taskId = 1, visible = false) + + repo.updateTaskVisibility(DEFAULT_DISPLAY, taskId = 1, visible = false) executor.flushAll() assertThat(listener.visibleChangesOnDefaultDisplay).isEqualTo(3) - repo.updateVisibleFreeformTasks(DEFAULT_DISPLAY, taskId = 2, visible = false) + repo.updateTaskVisibility(DEFAULT_DISPLAY, taskId = 2, visible = false) executor.flushAll() assertThat(listener.visibleTasksCountOnDefaultDisplay).isEqualTo(0) @@ -320,16 +354,17 @@ class DesktopModeTaskRepositoryTest : ShellTestCase() { * This tests that task is removed from the last parent display when it vanishes. */ @Test - fun updateVisibleFreeformTasks_removeVisibleTasksRemovesTaskWithInvalidDisplay() { + fun updateTaskVisibility_removeVisibleTasksRemovesTaskWithInvalidDisplay() { val listener = TestVisibilityListener() val executor = TestShellExecutor() repo.addVisibleTasksListener(listener, executor) - repo.updateVisibleFreeformTasks(DEFAULT_DISPLAY, taskId = 1, visible = true) - repo.updateVisibleFreeformTasks(DEFAULT_DISPLAY, taskId = 2, visible = true) + repo.updateTaskVisibility(DEFAULT_DISPLAY, taskId = 1, visible = true) + repo.updateTaskVisibility(DEFAULT_DISPLAY, taskId = 2, visible = true) executor.flushAll() assertThat(listener.visibleTasksCountOnDefaultDisplay).isEqualTo(2) - repo.updateVisibleFreeformTasks(INVALID_DISPLAY, taskId = 1, visible = false) + + repo.updateTaskVisibility(INVALID_DISPLAY, taskId = 1, visible = false) executor.flushAll() assertThat(listener.visibleChangesOnDefaultDisplay).isEqualTo(3) @@ -337,65 +372,73 @@ class DesktopModeTaskRepositoryTest : ShellTestCase() { } @Test - fun visibleTaskCount_defaultDisplay_returnsCorrectCount() { + fun getVisibleTaskCount_defaultDisplay_returnsCorrectCount() { // No tasks, count is 0 - assertThat(repo.visibleTaskCount(DEFAULT_DISPLAY)).isEqualTo(0) + assertThat(repo.getVisibleTaskCount(DEFAULT_DISPLAY)).isEqualTo(0) // New task increments count to 1 - repo.updateVisibleFreeformTasks(DEFAULT_DISPLAY, taskId = 1, visible = true) - assertThat(repo.visibleTaskCount(DEFAULT_DISPLAY)).isEqualTo(1) + repo.updateTaskVisibility(DEFAULT_DISPLAY, taskId = 1, visible = true) + + assertThat(repo.getVisibleTaskCount(DEFAULT_DISPLAY)).isEqualTo(1) // Visibility update to same task does not increase count - repo.updateVisibleFreeformTasks(DEFAULT_DISPLAY, taskId = 1, visible = true) - assertThat(repo.visibleTaskCount(DEFAULT_DISPLAY)).isEqualTo(1) + repo.updateTaskVisibility(DEFAULT_DISPLAY, taskId = 1, visible = true) + + assertThat(repo.getVisibleTaskCount(DEFAULT_DISPLAY)).isEqualTo(1) // Second task visible increments count - repo.updateVisibleFreeformTasks(DEFAULT_DISPLAY, taskId = 2, visible = true) - assertThat(repo.visibleTaskCount(DEFAULT_DISPLAY)).isEqualTo(2) + repo.updateTaskVisibility(DEFAULT_DISPLAY, taskId = 2, visible = true) + + assertThat(repo.getVisibleTaskCount(DEFAULT_DISPLAY)).isEqualTo(2) // Hiding a task decrements count - repo.updateVisibleFreeformTasks(DEFAULT_DISPLAY, taskId = 1, visible = false) - assertThat(repo.visibleTaskCount(DEFAULT_DISPLAY)).isEqualTo(1) + repo.updateTaskVisibility(DEFAULT_DISPLAY, taskId = 1, visible = false) + assertThat(repo.getVisibleTaskCount(DEFAULT_DISPLAY)).isEqualTo(1) // Hiding all tasks leaves count at 0 - repo.updateVisibleFreeformTasks(DEFAULT_DISPLAY, taskId = 2, visible = false) - assertThat(repo.visibleTaskCount(displayId = 9)).isEqualTo(0) + repo.updateTaskVisibility(DEFAULT_DISPLAY, taskId = 2, visible = false) + assertThat(repo.getVisibleTaskCount(displayId = 9)).isEqualTo(0) // Hiding a not existing task, count remains at 0 - repo.updateVisibleFreeformTasks(DEFAULT_DISPLAY, taskId = 999, visible = false) - assertThat(repo.visibleTaskCount(DEFAULT_DISPLAY)).isEqualTo(0) + repo.updateTaskVisibility(DEFAULT_DISPLAY, taskId = 999, visible = false) + assertThat(repo.getVisibleTaskCount(DEFAULT_DISPLAY)).isEqualTo(0) } @Test - fun visibleTaskCount_multipleDisplays_returnsCorrectCount() { - assertThat(repo.visibleTaskCount(DEFAULT_DISPLAY)).isEqualTo(0) - assertThat(repo.visibleTaskCount(SECOND_DISPLAY)).isEqualTo(0) + fun getVisibleTaskCount_multipleDisplays_returnsCorrectCount() { + assertThat(repo.getVisibleTaskCount(DEFAULT_DISPLAY)).isEqualTo(0) + assertThat(repo.getVisibleTaskCount(SECOND_DISPLAY)).isEqualTo(0) // New task on default display increments count for that display only - repo.updateVisibleFreeformTasks(DEFAULT_DISPLAY, taskId = 1, visible = true) - assertThat(repo.visibleTaskCount(DEFAULT_DISPLAY)).isEqualTo(1) - assertThat(repo.visibleTaskCount(SECOND_DISPLAY)).isEqualTo(0) + repo.updateTaskVisibility(DEFAULT_DISPLAY, taskId = 1, visible = true) + + assertThat(repo.getVisibleTaskCount(DEFAULT_DISPLAY)).isEqualTo(1) + assertThat(repo.getVisibleTaskCount(SECOND_DISPLAY)).isEqualTo(0) // New task on secondary display, increments count for that display only - repo.updateVisibleFreeformTasks(SECOND_DISPLAY, taskId = 2, visible = true) - assertThat(repo.visibleTaskCount(DEFAULT_DISPLAY)).isEqualTo(1) - assertThat(repo.visibleTaskCount(SECOND_DISPLAY)).isEqualTo(1) + repo.updateTaskVisibility(SECOND_DISPLAY, taskId = 2, visible = true) + + assertThat(repo.getVisibleTaskCount(DEFAULT_DISPLAY)).isEqualTo(1) + assertThat(repo.getVisibleTaskCount(SECOND_DISPLAY)).isEqualTo(1) // Marking task visible on another display, updates counts for both displays - repo.updateVisibleFreeformTasks(SECOND_DISPLAY, taskId = 1, visible = true) - assertThat(repo.visibleTaskCount(DEFAULT_DISPLAY)).isEqualTo(0) - assertThat(repo.visibleTaskCount(SECOND_DISPLAY)).isEqualTo(2) + repo.updateTaskVisibility(SECOND_DISPLAY, taskId = 1, visible = true) + + assertThat(repo.getVisibleTaskCount(DEFAULT_DISPLAY)).isEqualTo(0) + assertThat(repo.getVisibleTaskCount(SECOND_DISPLAY)).isEqualTo(2) // Marking task that is on secondary display, hidden on default display, does not affect // secondary display - repo.updateVisibleFreeformTasks(DEFAULT_DISPLAY, taskId = 1, visible = false) - assertThat(repo.visibleTaskCount(DEFAULT_DISPLAY)).isEqualTo(0) - assertThat(repo.visibleTaskCount(SECOND_DISPLAY)).isEqualTo(2) + repo.updateTaskVisibility(DEFAULT_DISPLAY, taskId = 1, visible = false) + + assertThat(repo.getVisibleTaskCount(DEFAULT_DISPLAY)).isEqualTo(0) + assertThat(repo.getVisibleTaskCount(SECOND_DISPLAY)).isEqualTo(2) // Hiding a task on that display, decrements count - repo.updateVisibleFreeformTasks(SECOND_DISPLAY, taskId = 1, visible = false) - assertThat(repo.visibleTaskCount(DEFAULT_DISPLAY)).isEqualTo(0) - assertThat(repo.visibleTaskCount(SECOND_DISPLAY)).isEqualTo(1) + repo.updateTaskVisibility(SECOND_DISPLAY, taskId = 1, visible = false) + + assertThat(repo.getVisibleTaskCount(DEFAULT_DISPLAY)).isEqualTo(0) + assertThat(repo.getVisibleTaskCount(SECOND_DISPLAY)).isEqualTo(1) } @Test @@ -425,18 +468,116 @@ class DesktopModeTaskRepositoryTest : ShellTestCase() { } @Test + fun addOrMoveFreeformTaskToTop_taskIsMinimized_unminimizesTask() { + repo.addOrMoveFreeformTaskToTop(DEFAULT_DISPLAY, 5) + repo.addOrMoveFreeformTaskToTop(DEFAULT_DISPLAY, 6) + repo.addOrMoveFreeformTaskToTop(DEFAULT_DISPLAY, 7) + repo.minimizeTask(displayId = 0, taskId = 6) + + val tasks = repo.getFreeformTasksInZOrder(DEFAULT_DISPLAY) + assertThat(tasks).containsExactly(7, 6, 5).inOrder() + assertThat(repo.isMinimizedTask(taskId = 6)).isTrue() + } + + @Test + fun addOrMoveFreeformTaskToTop_taskIsUnminimized_noop() { + repo.addOrMoveFreeformTaskToTop(DEFAULT_DISPLAY, 5) + repo.addOrMoveFreeformTaskToTop(DEFAULT_DISPLAY, 6) + repo.addOrMoveFreeformTaskToTop(DEFAULT_DISPLAY, 7) + + val tasks = repo.getFreeformTasksInZOrder(DEFAULT_DISPLAY) + assertThat(tasks).containsExactly(7, 6, 5).inOrder() + assertThat(repo.isMinimizedTask(taskId = 6)).isFalse() + } + + @Test + fun removeFreeformTask_invalidDisplay_removesTaskFromFreeformTasks() { + repo.addOrMoveFreeformTaskToTop(DEFAULT_DISPLAY, taskId = 1) + + repo.removeFreeformTask(INVALID_DISPLAY, taskId = 1) + + val invalidDisplayTasks = repo.getFreeformTasksInZOrder(INVALID_DISPLAY) + assertThat(invalidDisplayTasks).isEmpty() + val validDisplayTasks = repo.getFreeformTasksInZOrder(DEFAULT_DISPLAY) + assertThat(validDisplayTasks).isEmpty() + } + + @Test + fun removeFreeformTask_validDisplay_removesTaskFromFreeformTasks() { + repo.addOrMoveFreeformTaskToTop(DEFAULT_DISPLAY, taskId = 1) + + repo.removeFreeformTask(DEFAULT_DISPLAY, taskId = 1) + + val tasks = repo.getFreeformTasksInZOrder(DEFAULT_DISPLAY) + assertThat(tasks).isEmpty() + } + + @Test + fun removeFreeformTask_validDisplay_differentDisplay_doesNotRemovesTask() { + repo.addOrMoveFreeformTaskToTop(DEFAULT_DISPLAY, taskId = 1) + + repo.removeFreeformTask(SECOND_DISPLAY, taskId = 1) + + val tasks = repo.getFreeformTasksInZOrder(DEFAULT_DISPLAY) + assertThat(tasks).containsExactly(1) + } + + @Test fun removeFreeformTask_removesTaskBoundsBeforeMaximize() { val taskId = 1 + repo.addActiveTask(THIRD_DISPLAY, taskId) + repo.addOrMoveFreeformTaskToTop(THIRD_DISPLAY, taskId) repo.saveBoundsBeforeMaximize(taskId, Rect(0, 0, 200, 200)) + repo.removeFreeformTask(THIRD_DISPLAY, taskId) + assertThat(repo.removeBoundsBeforeMaximize(taskId)).isNull() } @Test + fun removeFreeformTask_removesActiveTask() { + val taskId = 1 + val listener = TestListener() + repo.addActiveTaskListener(listener) + repo.addActiveTask(DEFAULT_DISPLAY, taskId) + repo.addOrMoveFreeformTaskToTop(DEFAULT_DISPLAY, taskId) + + repo.removeFreeformTask(THIRD_DISPLAY, taskId) + + assertThat(repo.isActiveTask(taskId)).isFalse() + assertThat(listener.activeChangesOnDefaultDisplay).isEqualTo(2) + } + + @Test + fun removeFreeformTask_unminimizesTask() { + val taskId = 1 + repo.addActiveTask(DEFAULT_DISPLAY, taskId) + repo.addOrMoveFreeformTaskToTop(DEFAULT_DISPLAY, taskId) + repo.minimizeTask(DEFAULT_DISPLAY, taskId) + + repo.removeFreeformTask(DEFAULT_DISPLAY, taskId) + + assertThat(repo.isMinimizedTask(taskId)).isFalse() + } + + @Test + fun removeFreeformTask_updatesTaskVisibility() { + val taskId = 1 + repo.addActiveTask(DEFAULT_DISPLAY, taskId) + repo.addOrMoveFreeformTaskToTop(DEFAULT_DISPLAY, taskId) + + repo.removeFreeformTask(THIRD_DISPLAY, taskId) + + assertThat(repo.isVisibleTask(taskId)).isFalse() + } + + @Test fun saveBoundsBeforeMaximize_boundsSavedByTaskId() { val taskId = 1 val bounds = Rect(0, 0, 200, 200) + repo.saveBoundsBeforeMaximize(taskId, bounds) + assertThat(repo.removeBoundsBeforeMaximize(taskId)).isEqualTo(bounds) } @@ -446,17 +587,20 @@ class DesktopModeTaskRepositoryTest : ShellTestCase() { val bounds = Rect(0, 0, 200, 200) repo.saveBoundsBeforeMaximize(taskId, bounds) repo.removeBoundsBeforeMaximize(taskId) - assertThat(repo.removeBoundsBeforeMaximize(taskId)).isNull() + + val boundsBeforeMaximize = repo.removeBoundsBeforeMaximize(taskId) + + assertThat(boundsBeforeMaximize).isNull() } @Test - fun minimizeTaskNotCalled_noTasksMinimized() { + fun isMinimizedTask_minimizeTaskNotCalled_noTasksMinimized() { assertThat(repo.isMinimizedTask(taskId = 0)).isFalse() assertThat(repo.isMinimizedTask(taskId = 1)).isFalse() } @Test - fun minimizeTask_onlyThatTaskIsMinimized() { + fun minimizeTask_minimizesCorrectTask() { repo.minimizeTask(displayId = 0, taskId = 0) assertThat(repo.isMinimizedTask(taskId = 0)).isTrue() @@ -465,8 +609,9 @@ class DesktopModeTaskRepositoryTest : ShellTestCase() { } @Test - fun unminimizeTask_taskNoLongerMinimized() { + fun unminimizeTask_unminimizesTask() { repo.minimizeTask(displayId = 0, taskId = 0) + repo.unminimizeTask(displayId = 0, taskId = 0) assertThat(repo.isMinimizedTask(taskId = 0)).isFalse() @@ -478,6 +623,7 @@ class DesktopModeTaskRepositoryTest : ShellTestCase() { fun unminimizeTask_nonExistentTask_doesntCrash() { repo.unminimizeTask(displayId = 0, taskId = 0) + // No change assertThat(repo.isMinimizedTask(taskId = 0)).isFalse() assertThat(repo.isMinimizedTask(taskId = 1)).isFalse() assertThat(repo.isMinimizedTask(taskId = 2)).isFalse() @@ -485,41 +631,44 @@ class DesktopModeTaskRepositoryTest : ShellTestCase() { @Test - fun updateVisibleFreeformTasks_toVisible_taskIsUnminimized() { + fun updateTaskVisibility_minimizedTaskBecomesVisible_unminimizesTask() { repo.minimizeTask(displayId = 10, taskId = 2) + repo.updateTaskVisibility(displayId = 10, taskId = 2, visible = true) - repo.updateVisibleFreeformTasks(displayId = 10, taskId = 2, visible = true) + val isMinimizedTask = repo.isMinimizedTask(taskId = 2) - assertThat(repo.isMinimizedTask(taskId = 2)).isFalse() + assertThat(isMinimizedTask).isFalse() } @Test - fun getActiveNonMinimizedTasksOrderedFrontToBack_returnsFreeformTasksInCorrectOrder() { + fun getActiveNonMinimizedOrderedTasks_returnsFreeformTasksInCorrectOrder() { repo.addActiveTask(displayId = DEFAULT_DISPLAY, taskId = 1) repo.addActiveTask(displayId = DEFAULT_DISPLAY, taskId = 2) repo.addActiveTask(displayId = DEFAULT_DISPLAY, taskId = 3) - // The front-most task will be the one added last through addOrMoveFreeformTaskToTop + // The front-most task will be the one added last through `addOrMoveFreeformTaskToTop` repo.addOrMoveFreeformTaskToTop(displayId = DEFAULT_DISPLAY, taskId = 3) repo.addOrMoveFreeformTaskToTop(displayId = 0, taskId = 2) repo.addOrMoveFreeformTaskToTop(displayId = 0, taskId = 1) - assertThat(repo.getActiveNonMinimizedTasksOrderedFrontToBack(displayId = 0)) - .containsExactly(1, 2, 3).inOrder() + val tasks = repo.getActiveNonMinimizedOrderedTasks(displayId = 0) + + assertThat(tasks).containsExactly(1, 2, 3).inOrder() } @Test - fun getActiveNonMinimizedTasksOrderedFrontToBack_minimizedTaskNotIncluded() { + fun getActiveNonMinimizedOrderedTasks_excludesMinimizedTasks() { repo.addActiveTask(displayId = DEFAULT_DISPLAY, taskId = 1) repo.addActiveTask(displayId = DEFAULT_DISPLAY, taskId = 2) repo.addActiveTask(displayId = DEFAULT_DISPLAY, taskId = 3) - // The front-most task will be the one added last through addOrMoveFreeformTaskToTop + // The front-most task will be the one added last through `addOrMoveFreeformTaskToTop` repo.addOrMoveFreeformTaskToTop(displayId = DEFAULT_DISPLAY, taskId = 3) repo.addOrMoveFreeformTaskToTop(displayId = DEFAULT_DISPLAY, taskId = 2) repo.addOrMoveFreeformTaskToTop(displayId = DEFAULT_DISPLAY, taskId = 1) repo.minimizeTask(displayId = DEFAULT_DISPLAY, taskId = 2) - assertThat(repo.getActiveNonMinimizedTasksOrderedFrontToBack( - displayId = DEFAULT_DISPLAY)).containsExactly(1, 3).inOrder() + val tasks = repo.getActiveNonMinimizedOrderedTasks(displayId = DEFAULT_DISPLAY) + + assertThat(tasks).containsExactly(1, 3).inOrder() } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicatorTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicatorTest.kt index bd39aa6ace42..2dea43b508ae 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicatorTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicatorTest.kt @@ -61,20 +61,23 @@ class DesktopModeVisualIndicatorTest : ShellTestCase() { @Test fun testFullscreenRegionCalculation() { - val transitionHeight = context.resources.getDimensionPixelSize( - R.dimen.desktop_mode_fullscreen_from_desktop_height) - val fromFreeformWidth = mContext.resources.getDimensionPixelSize( - R.dimen.desktop_mode_fullscreen_from_desktop_width - ) var testRegion = visualIndicator.calculateFullscreenRegion(displayLayout, WINDOWING_MODE_FULLSCREEN, CAPTION_HEIGHT) assertThat(testRegion.bounds).isEqualTo(Rect(0, -50, 2400, 2 * STABLE_INSETS.top)) testRegion = visualIndicator.calculateFullscreenRegion(displayLayout, WINDOWING_MODE_FREEFORM, CAPTION_HEIGHT) + + val transitionHeight = context.resources.getDimensionPixelSize( + R.dimen.desktop_mode_transition_region_thickness) + val toFullscreenScale = mContext.resources.getFloat( + R.dimen.desktop_mode_fullscreen_region_scale + ) + val toFullscreenWidth = displayLayout.width() * toFullscreenScale + assertThat(testRegion.bounds).isEqualTo(Rect( - DISPLAY_BOUNDS.width() / 2 - fromFreeformWidth / 2, + (DISPLAY_BOUNDS.width() / 2f - toFullscreenWidth / 2f).toInt(), -50, - DISPLAY_BOUNDS.width() / 2 + fromFreeformWidth / 2, + (DISPLAY_BOUNDS.width() / 2f + toFullscreenWidth / 2f).toInt(), transitionHeight)) testRegion = visualIndicator.calculateFullscreenRegion(displayLayout, WINDOWING_MODE_MULTI_WINDOW, CAPTION_HEIGHT) diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt index e66018f26d46..95d90176c6f9 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt @@ -43,6 +43,7 @@ import android.platform.test.annotations.EnableFlags import android.platform.test.flag.junit.SetFlagsRule import android.testing.AndroidTestingRunner import android.view.Display.DEFAULT_DISPLAY +import android.view.Gravity import android.view.SurfaceControl import android.view.WindowManager import android.view.WindowManager.TRANSIT_CHANGE @@ -70,6 +71,7 @@ import com.android.internal.jank.InteractionJankMonitor import com.android.window.flags.Flags import com.android.window.flags.Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE import com.android.wm.shell.MockToken +import com.android.wm.shell.R import com.android.wm.shell.RootTaskDisplayAreaOrganizer import com.android.wm.shell.ShellTaskOrganizer import com.android.wm.shell.ShellTestCase @@ -174,7 +176,7 @@ class DesktopTasksControllerTest : ShellTestCase() { private lateinit var mockitoSession: StaticMockitoSession private lateinit var controller: DesktopTasksController private lateinit var shellInit: ShellInit - private lateinit var desktopModeTaskRepository: DesktopModeTaskRepository + private lateinit var taskRepository: DesktopModeTaskRepository private lateinit var desktopTasksLimiter: DesktopTasksLimiter private lateinit var recentsTransitionStateListener: RecentsTransitionStateListener @@ -185,12 +187,12 @@ class DesktopTasksControllerTest : ShellTestCase() { private val DISPLAY_DIMENSION_SHORT = 1600 private val DISPLAY_DIMENSION_LONG = 2560 - private val DEFAULT_LANDSCAPE_BOUNDS = Rect(320, 200, 2240, 1400) - private val DEFAULT_PORTRAIT_BOUNDS = Rect(200, 320, 1400, 2240) - private val RESIZABLE_LANDSCAPE_BOUNDS = Rect(25, 680, 1575, 1880) - private val RESIZABLE_PORTRAIT_BOUNDS = Rect(680, 200, 1880, 1400) - private val UNRESIZABLE_LANDSCAPE_BOUNDS = Rect(25, 699, 1575, 1861) - private val UNRESIZABLE_PORTRAIT_BOUNDS = Rect(830, 200, 1730, 1400) + private val DEFAULT_LANDSCAPE_BOUNDS = Rect(320, 75, 2240, 1275) + private val DEFAULT_PORTRAIT_BOUNDS = Rect(200, 165, 1400, 2085) + private val RESIZABLE_LANDSCAPE_BOUNDS = Rect(25, 435, 1575, 1635) + private val RESIZABLE_PORTRAIT_BOUNDS = Rect(680, 75, 1880, 1275) + private val UNRESIZABLE_LANDSCAPE_BOUNDS = Rect(25, 449, 1575, 1611) + private val UNRESIZABLE_PORTRAIT_BOUNDS = Rect(830, 75, 1730, 1275) @Before fun setUp() { @@ -202,14 +204,15 @@ class DesktopTasksControllerTest : ShellTestCase() { doReturn(true).`when` { DesktopModeStatus.isDesktopModeSupported(any()) } shellInit = spy(ShellInit(testExecutor)) - desktopModeTaskRepository = DesktopModeTaskRepository() + taskRepository = DesktopModeTaskRepository() desktopTasksLimiter = DesktopTasksLimiter( transitions, - desktopModeTaskRepository, + taskRepository, shellTaskOrganizer, MAX_TASK_LIMIT, - ) + mockInteractionJankMonitor, + mContext) whenever(shellTaskOrganizer.getRunningTasks(anyInt())).thenAnswer { runningTasks } whenever(transitions.startTransition(anyInt(), any(), isNull())).thenAnswer { Binder() } @@ -250,7 +253,7 @@ class DesktopTasksControllerTest : ShellTestCase() { exitDesktopTransitionHandler, toggleResizeDesktopTaskTransitionHandler, dragToDesktopTransitionHandler, - desktopModeTaskRepository, + taskRepository, desktopModeLoggerTransitionObserver, launchAdjacentController, recentsTransitionHandler, @@ -528,7 +531,7 @@ class DesktopTasksControllerTest : ShellTestCase() { markTaskHidden(freeformTask) markTaskHidden(minimizedTask) - desktopModeTaskRepository.minimizeTask(DEFAULT_DISPLAY, minimizedTask.taskId) + taskRepository.minimizeTask(DEFAULT_DISPLAY, minimizedTask.taskId) controller.showDesktopApps(DEFAULT_DISPLAY, RemoteTransition(TestRemoteTransition())) val wct = getLatestWct(type = TRANSIT_TO_FRONT, handlerClass = OneShotRemoteHandler::class.java) @@ -547,7 +550,7 @@ class DesktopTasksControllerTest : ShellTestCase() { markTaskHidden(freeformTask) markTaskHidden(minimizedTask) - desktopModeTaskRepository.minimizeTask(DEFAULT_DISPLAY, minimizedTask.taskId) + taskRepository.minimizeTask(DEFAULT_DISPLAY, minimizedTask.taskId) controller.showDesktopApps(DEFAULT_DISPLAY, RemoteTransition(TestRemoteTransition())) val wct = getLatestWct(type = TRANSIT_TO_FRONT, handlerClass = OneShotRemoteHandler::class.java) @@ -590,6 +593,161 @@ class DesktopTasksControllerTest : ShellTestCase() { } @Test + fun addMoveToDesktopChanges_gravityLeft_noBoundsApplied() { + setUpLandscapeDisplay() + val task = setUpFullscreenTask(gravity = Gravity.LEFT) + val wct = WindowContainerTransaction() + controller.addMoveToDesktopChanges(wct, task) + + val finalBounds = findBoundsChange(wct, task) + assertThat(finalBounds).isEqualTo(Rect()) + } + + @Test + fun addMoveToDesktopChanges_gravityRight_noBoundsApplied() { + setUpLandscapeDisplay() + val task = setUpFullscreenTask(gravity = Gravity.RIGHT) + val wct = WindowContainerTransaction() + controller.addMoveToDesktopChanges(wct, task) + + val finalBounds = findBoundsChange(wct, task) + assertThat(finalBounds).isEqualTo(Rect()) + } + + @Test + fun addMoveToDesktopChanges_gravityTop_noBoundsApplied() { + setUpLandscapeDisplay() + val task = setUpFullscreenTask(gravity = Gravity.TOP) + val wct = WindowContainerTransaction() + controller.addMoveToDesktopChanges(wct, task) + + val finalBounds = findBoundsChange(wct, task) + assertThat(finalBounds).isEqualTo(Rect()) + } + + @Test + fun addMoveToDesktopChanges_gravityBottom_noBoundsApplied() { + setUpLandscapeDisplay() + val task = setUpFullscreenTask(gravity = Gravity.BOTTOM) + val wct = WindowContainerTransaction() + controller.addMoveToDesktopChanges(wct, task) + + val finalBounds = findBoundsChange(wct, task) + assertThat(finalBounds).isEqualTo(Rect()) + } + + @Test + @EnableFlags(Flags.FLAG_ENABLE_CASCADING_WINDOWS) + fun addMoveToDesktopChanges_positionBottomRight() { + setUpLandscapeDisplay() + val stableBounds = Rect() + displayLayout.getStableBoundsForDesktopMode(stableBounds) + + setUpFreeformTask(bounds = DEFAULT_LANDSCAPE_BOUNDS) + + val task = setUpFullscreenTask() + val wct = WindowContainerTransaction() + controller.addMoveToDesktopChanges(wct, task) + + val finalBounds = findBoundsChange(wct, task) + assertThat(stableBounds.getDesktopTaskPosition(finalBounds!!)) + .isEqualTo(DesktopTaskPosition.BottomRight) + } + + @Test + @EnableFlags(Flags.FLAG_ENABLE_CASCADING_WINDOWS) + fun addMoveToDesktopChanges_positionTopLeft() { + setUpLandscapeDisplay() + val stableBounds = Rect() + displayLayout.getStableBoundsForDesktopMode(stableBounds) + + addFreeformTaskAtPosition(DesktopTaskPosition.BottomRight, stableBounds) + + val task = setUpFullscreenTask() + val wct = WindowContainerTransaction() + controller.addMoveToDesktopChanges(wct, task) + + val finalBounds = findBoundsChange(wct, task) + assertThat(stableBounds.getDesktopTaskPosition(finalBounds!!)) + .isEqualTo(DesktopTaskPosition.TopLeft) + } + + @Test + @EnableFlags(Flags.FLAG_ENABLE_CASCADING_WINDOWS) + fun addMoveToDesktopChanges_positionBottomLeft() { + setUpLandscapeDisplay() + val stableBounds = Rect() + displayLayout.getStableBoundsForDesktopMode(stableBounds) + + addFreeformTaskAtPosition(DesktopTaskPosition.TopLeft, stableBounds) + + val task = setUpFullscreenTask() + val wct = WindowContainerTransaction() + controller.addMoveToDesktopChanges(wct, task) + + val finalBounds = findBoundsChange(wct, task) + assertThat(stableBounds.getDesktopTaskPosition(finalBounds!!)) + .isEqualTo(DesktopTaskPosition.BottomLeft) + } + + @Test + @EnableFlags(Flags.FLAG_ENABLE_CASCADING_WINDOWS) + fun addMoveToDesktopChanges_positionTopRight() { + setUpLandscapeDisplay() + val stableBounds = Rect() + displayLayout.getStableBoundsForDesktopMode(stableBounds) + + addFreeformTaskAtPosition(DesktopTaskPosition.BottomLeft, stableBounds) + + val task = setUpFullscreenTask() + val wct = WindowContainerTransaction() + controller.addMoveToDesktopChanges(wct, task) + + val finalBounds = findBoundsChange(wct, task) + assertThat(stableBounds.getDesktopTaskPosition(finalBounds!!)) + .isEqualTo(DesktopTaskPosition.TopRight) + } + + @Test + @EnableFlags(Flags.FLAG_ENABLE_CASCADING_WINDOWS) + fun addMoveToDesktopChanges_positionResetsToCenter() { + setUpLandscapeDisplay() + val stableBounds = Rect() + displayLayout.getStableBoundsForDesktopMode(stableBounds) + + addFreeformTaskAtPosition(DesktopTaskPosition.TopRight, stableBounds) + + val task = setUpFullscreenTask() + val wct = WindowContainerTransaction() + controller.addMoveToDesktopChanges(wct, task) + + val finalBounds = findBoundsChange(wct, task) + assertThat(stableBounds.getDesktopTaskPosition(finalBounds!!)) + .isEqualTo(DesktopTaskPosition.Center) + } + + @Test + @EnableFlags(Flags.FLAG_ENABLE_CASCADING_WINDOWS) + fun addMoveToDesktopChanges_defaultToCenterIfFree() { + setUpLandscapeDisplay() + val stableBounds = Rect() + displayLayout.getStableBoundsForDesktopMode(stableBounds) + + val minTouchTarget = context.resources.getDimensionPixelSize( + R.dimen.freeform_required_visible_empty_space_in_header) + addFreeformTaskAtPosition(DesktopTaskPosition.Center, stableBounds, + Rect(0, 0, 1600, 1200), Point(0, minTouchTarget + 1)) + + val task = setUpFullscreenTask() + val wct = WindowContainerTransaction() + controller.addMoveToDesktopChanges(wct, task) + + val finalBounds = findBoundsChange(wct, task) + assertThat(stableBounds.getDesktopTaskPosition(finalBounds!!)) + .isEqualTo(DesktopTaskPosition.Center) + } + + @Test fun moveToDesktop_tdaFullscreen_windowingModeSetToFreeform() { val task = setUpFullscreenTask() val tda = rootTaskDisplayAreaOrganizer.getDisplayAreaInfo(DEFAULT_DISPLAY)!! @@ -838,7 +996,7 @@ class DesktopTasksControllerTest : ShellTestCase() { val task = setUpFreeformTask() val wallpaperToken = MockToken().token() - desktopModeTaskRepository.wallpaperActivityToken = wallpaperToken + taskRepository.wallpaperActivityToken = wallpaperToken assertNotNull(rootTaskDisplayAreaOrganizer.getDisplayAreaInfo(DEFAULT_DISPLAY)) .configuration.windowConfiguration.windowingMode = WINDOWING_MODE_FULLSCREEN @@ -867,7 +1025,7 @@ class DesktopTasksControllerTest : ShellTestCase() { val task = setUpFreeformTask() val wallpaperToken = MockToken().token() - desktopModeTaskRepository.wallpaperActivityToken = wallpaperToken + taskRepository.wallpaperActivityToken = wallpaperToken assertNotNull(rootTaskDisplayAreaOrganizer.getDisplayAreaInfo(DEFAULT_DISPLAY)) .configuration.windowConfiguration.windowingMode = WINDOWING_MODE_FREEFORM @@ -887,7 +1045,7 @@ class DesktopTasksControllerTest : ShellTestCase() { setUpFreeformTask() val wallpaperToken = MockToken().token() - desktopModeTaskRepository.wallpaperActivityToken = wallpaperToken + taskRepository.wallpaperActivityToken = wallpaperToken assertNotNull(rootTaskDisplayAreaOrganizer.getDisplayAreaInfo(DEFAULT_DISPLAY)) .configuration.windowConfiguration.windowingMode = WINDOWING_MODE_FULLSCREEN @@ -1028,7 +1186,7 @@ class DesktopTasksControllerTest : ShellTestCase() { fun onDesktopWindowClose_singleActiveTask_hasWallpaperActivityToken() { val task = setUpFreeformTask() val wallpaperToken = MockToken().token() - desktopModeTaskRepository.wallpaperActivityToken = wallpaperToken + taskRepository.wallpaperActivityToken = wallpaperToken val wct = WindowContainerTransaction() controller.onDesktopWindowClose(wct, displayId = DEFAULT_DISPLAY, taskId = task.taskId) @@ -1040,8 +1198,8 @@ class DesktopTasksControllerTest : ShellTestCase() { fun onDesktopWindowClose_singleActiveTask_isClosing() { val task = setUpFreeformTask() val wallpaperToken = MockToken().token() - desktopModeTaskRepository.wallpaperActivityToken = wallpaperToken - desktopModeTaskRepository.addClosingTask(DEFAULT_DISPLAY, task.taskId) + taskRepository.wallpaperActivityToken = wallpaperToken + taskRepository.addClosingTask(DEFAULT_DISPLAY, task.taskId) val wct = WindowContainerTransaction() controller.onDesktopWindowClose(wct, displayId = DEFAULT_DISPLAY, taskId = task.taskId) @@ -1053,8 +1211,8 @@ class DesktopTasksControllerTest : ShellTestCase() { fun onDesktopWindowClose_singleActiveTask_isMinimized() { val task = setUpFreeformTask() val wallpaperToken = MockToken().token() - desktopModeTaskRepository.wallpaperActivityToken = wallpaperToken - desktopModeTaskRepository.minimizeTask(DEFAULT_DISPLAY, task.taskId) + taskRepository.wallpaperActivityToken = wallpaperToken + taskRepository.minimizeTask(DEFAULT_DISPLAY, task.taskId) val wct = WindowContainerTransaction() controller.onDesktopWindowClose(wct, displayId = DEFAULT_DISPLAY, taskId = task.taskId) @@ -1067,7 +1225,7 @@ class DesktopTasksControllerTest : ShellTestCase() { val task1 = setUpFreeformTask() setUpFreeformTask() val wallpaperToken = MockToken().token() - desktopModeTaskRepository.wallpaperActivityToken = wallpaperToken + taskRepository.wallpaperActivityToken = wallpaperToken val wct = WindowContainerTransaction() controller.onDesktopWindowClose(wct, displayId = DEFAULT_DISPLAY, taskId = task1.taskId) @@ -1080,8 +1238,8 @@ class DesktopTasksControllerTest : ShellTestCase() { val task1 = setUpFreeformTask() val task2 = setUpFreeformTask() val wallpaperToken = MockToken().token() - desktopModeTaskRepository.wallpaperActivityToken = wallpaperToken - desktopModeTaskRepository.addClosingTask(DEFAULT_DISPLAY, task2.taskId) + taskRepository.wallpaperActivityToken = wallpaperToken + taskRepository.addClosingTask(DEFAULT_DISPLAY, task2.taskId) val wct = WindowContainerTransaction() controller.onDesktopWindowClose(wct, displayId = DEFAULT_DISPLAY, taskId = task1.taskId) @@ -1094,8 +1252,8 @@ class DesktopTasksControllerTest : ShellTestCase() { val task1 = setUpFreeformTask() val task2 = setUpFreeformTask() val wallpaperToken = MockToken().token() - desktopModeTaskRepository.wallpaperActivityToken = wallpaperToken - desktopModeTaskRepository.minimizeTask(DEFAULT_DISPLAY, task2.taskId) + taskRepository.wallpaperActivityToken = wallpaperToken + taskRepository.minimizeTask(DEFAULT_DISPLAY, task2.taskId) val wct = WindowContainerTransaction() controller.onDesktopWindowClose(wct, displayId = DEFAULT_DISPLAY, taskId = task1.taskId) @@ -1501,7 +1659,7 @@ class DesktopTasksControllerTest : ShellTestCase() { fun handleRequest_backTransition_singleTaskWithToken_noWallpaper_noBackNav_doesNotHandle() { val task = setUpFreeformTask() - desktopModeTaskRepository.wallpaperActivityToken = MockToken().token() + taskRepository.wallpaperActivityToken = MockToken().token() val result = controller.handleRequest(Binder(), createTransition(task, type = TRANSIT_TO_BACK)) assertNull(result, "Should not handle request") @@ -1516,7 +1674,7 @@ class DesktopTasksControllerTest : ShellTestCase() { val task = setUpFreeformTask() val wallpaperToken = MockToken().token() - desktopModeTaskRepository.wallpaperActivityToken = wallpaperToken + taskRepository.wallpaperActivityToken = wallpaperToken val result = controller.handleRequest(Binder(), createTransition(task, type = TRANSIT_TO_BACK)) // Should create remove wallpaper transaction @@ -1531,7 +1689,7 @@ class DesktopTasksControllerTest : ShellTestCase() { val task = setUpFreeformTask() val wallpaperToken = MockToken().token() - desktopModeTaskRepository.wallpaperActivityToken = wallpaperToken + taskRepository.wallpaperActivityToken = wallpaperToken val result = controller.handleRequest(Binder(), createTransition(task, type = TRANSIT_TO_BACK)) // Should create remove wallpaper transaction @@ -1547,7 +1705,7 @@ class DesktopTasksControllerTest : ShellTestCase() { val task1 = setUpFreeformTask() setUpFreeformTask() - desktopModeTaskRepository.wallpaperActivityToken = MockToken().token() + taskRepository.wallpaperActivityToken = MockToken().token() val result = controller.handleRequest(Binder(), createTransition(task1, type = TRANSIT_TO_BACK)) assertNull(result, "Should not handle request") @@ -1562,7 +1720,7 @@ class DesktopTasksControllerTest : ShellTestCase() { val task1 = setUpFreeformTask() setUpFreeformTask() - desktopModeTaskRepository.wallpaperActivityToken = MockToken().token() + taskRepository.wallpaperActivityToken = MockToken().token() val result = controller.handleRequest(Binder(), createTransition(task1, type = TRANSIT_TO_BACK)) assertNotNull(result, "Should handle request").assertRemoveAt(index = 0, task1.token) @@ -1575,7 +1733,7 @@ class DesktopTasksControllerTest : ShellTestCase() { val task1 = setUpFreeformTask() setUpFreeformTask() - desktopModeTaskRepository.wallpaperActivityToken = MockToken().token() + taskRepository.wallpaperActivityToken = MockToken().token() val result = controller.handleRequest(Binder(), createTransition(task1, type = TRANSIT_TO_BACK)) assertNull(result, "Should not handle request") @@ -1591,8 +1749,8 @@ class DesktopTasksControllerTest : ShellTestCase() { val task2 = setUpFreeformTask(displayId = DEFAULT_DISPLAY) val wallpaperToken = MockToken().token() - desktopModeTaskRepository.wallpaperActivityToken = wallpaperToken - desktopModeTaskRepository.addClosingTask(displayId = DEFAULT_DISPLAY, taskId = task2.taskId) + taskRepository.wallpaperActivityToken = wallpaperToken + taskRepository.addClosingTask(displayId = DEFAULT_DISPLAY, taskId = task2.taskId) val result = controller.handleRequest(Binder(), createTransition(task1, type = TRANSIT_TO_BACK)) // Should create remove wallpaper transaction @@ -1608,8 +1766,8 @@ class DesktopTasksControllerTest : ShellTestCase() { val task2 = setUpFreeformTask(displayId = DEFAULT_DISPLAY) val wallpaperToken = MockToken().token() - desktopModeTaskRepository.wallpaperActivityToken = wallpaperToken - desktopModeTaskRepository.addClosingTask(displayId = DEFAULT_DISPLAY, taskId = task2.taskId) + taskRepository.wallpaperActivityToken = wallpaperToken + taskRepository.addClosingTask(displayId = DEFAULT_DISPLAY, taskId = task2.taskId) val result = controller.handleRequest(Binder(), createTransition(task1, type = TRANSIT_TO_BACK)) // Should create remove wallpaper transaction @@ -1626,8 +1784,8 @@ class DesktopTasksControllerTest : ShellTestCase() { val task2 = setUpFreeformTask(displayId = DEFAULT_DISPLAY) val wallpaperToken = MockToken().token() - desktopModeTaskRepository.wallpaperActivityToken = wallpaperToken - desktopModeTaskRepository.minimizeTask(displayId = DEFAULT_DISPLAY, taskId = task2.taskId) + taskRepository.wallpaperActivityToken = wallpaperToken + taskRepository.minimizeTask(displayId = DEFAULT_DISPLAY, taskId = task2.taskId) val result = controller.handleRequest(Binder(), createTransition(task1, type = TRANSIT_TO_BACK)) // Should create remove wallpaper transaction @@ -1643,8 +1801,8 @@ class DesktopTasksControllerTest : ShellTestCase() { val task2 = setUpFreeformTask(displayId = DEFAULT_DISPLAY) val wallpaperToken = MockToken().token() - desktopModeTaskRepository.wallpaperActivityToken = wallpaperToken - desktopModeTaskRepository.minimizeTask(displayId = DEFAULT_DISPLAY, taskId = task2.taskId) + taskRepository.wallpaperActivityToken = wallpaperToken + taskRepository.minimizeTask(displayId = DEFAULT_DISPLAY, taskId = task2.taskId) val result = controller.handleRequest(Binder(), createTransition(task1, type = TRANSIT_TO_BACK)) // Should create remove wallpaper transaction @@ -1661,11 +1819,11 @@ class DesktopTasksControllerTest : ShellTestCase() { val task2 = setUpFreeformTask(displayId = DEFAULT_DISPLAY) val wallpaperToken = MockToken().token() - desktopModeTaskRepository.wallpaperActivityToken = wallpaperToken - desktopModeTaskRepository.minimizeTask(displayId = DEFAULT_DISPLAY, taskId = task2.taskId) + taskRepository.wallpaperActivityToken = wallpaperToken + taskRepository.minimizeTask(displayId = DEFAULT_DISPLAY, taskId = task2.taskId) // Task is being minimized so mark it as not visible. - desktopModeTaskRepository - .updateVisibleFreeformTasks(displayId = DEFAULT_DISPLAY, task2.taskId, false) + taskRepository + .updateTaskVisibility(displayId = DEFAULT_DISPLAY, task2.taskId, false) val result = controller.handleRequest(Binder(), createTransition(task2, type = TRANSIT_TO_BACK)) assertNull(result, "Should not handle request") @@ -1716,7 +1874,7 @@ class DesktopTasksControllerTest : ShellTestCase() { fun handleRequest_closeTransition_singleTaskWithToken_noWallpaper_noBackNav_doesNotHandle() { val task = setUpFreeformTask() - desktopModeTaskRepository.wallpaperActivityToken = MockToken().token() + taskRepository.wallpaperActivityToken = MockToken().token() val result = controller.handleRequest(Binder(), createTransition(task, type = TRANSIT_CLOSE)) assertNull(result, "Should not handle request") @@ -1731,7 +1889,7 @@ class DesktopTasksControllerTest : ShellTestCase() { val task = setUpFreeformTask() val wallpaperToken = MockToken().token() - desktopModeTaskRepository.wallpaperActivityToken = wallpaperToken + taskRepository.wallpaperActivityToken = wallpaperToken val result = controller.handleRequest(Binder(), createTransition(task, type = TRANSIT_CLOSE)) // Should create remove wallpaper transaction @@ -1746,7 +1904,7 @@ class DesktopTasksControllerTest : ShellTestCase() { val task = setUpFreeformTask() val wallpaperToken = MockToken().token() - desktopModeTaskRepository.wallpaperActivityToken = wallpaperToken + taskRepository.wallpaperActivityToken = wallpaperToken val result = controller.handleRequest(Binder(), createTransition(task, type = TRANSIT_CLOSE)) // Should create remove wallpaper transaction @@ -1762,7 +1920,7 @@ class DesktopTasksControllerTest : ShellTestCase() { val task1 = setUpFreeformTask() setUpFreeformTask() - desktopModeTaskRepository.wallpaperActivityToken = MockToken().token() + taskRepository.wallpaperActivityToken = MockToken().token() val result = controller.handleRequest(Binder(), createTransition(task1, type = TRANSIT_CLOSE)) assertNull(result, "Should not handle request") @@ -1777,7 +1935,7 @@ class DesktopTasksControllerTest : ShellTestCase() { val task1 = setUpFreeformTask() setUpFreeformTask() - desktopModeTaskRepository.wallpaperActivityToken = MockToken().token() + taskRepository.wallpaperActivityToken = MockToken().token() val result = controller.handleRequest(Binder(), createTransition(task1, type = TRANSIT_CLOSE)) assertNotNull(result, "Should handle request") @@ -1791,7 +1949,7 @@ class DesktopTasksControllerTest : ShellTestCase() { val task1 = setUpFreeformTask() setUpFreeformTask() - desktopModeTaskRepository.wallpaperActivityToken = MockToken().token() + taskRepository.wallpaperActivityToken = MockToken().token() val result = controller.handleRequest(Binder(), createTransition(task1, type = TRANSIT_CLOSE)) assertNull(result, "Should not handle request") @@ -1807,8 +1965,8 @@ class DesktopTasksControllerTest : ShellTestCase() { val task2 = setUpFreeformTask(displayId = DEFAULT_DISPLAY) val wallpaperToken = MockToken().token() - desktopModeTaskRepository.wallpaperActivityToken = wallpaperToken - desktopModeTaskRepository.addClosingTask(displayId = DEFAULT_DISPLAY, taskId = task2.taskId) + taskRepository.wallpaperActivityToken = wallpaperToken + taskRepository.addClosingTask(displayId = DEFAULT_DISPLAY, taskId = task2.taskId) val result = controller.handleRequest(Binder(), createTransition(task1, type = TRANSIT_CLOSE)) // Should create remove wallpaper transaction @@ -1824,8 +1982,8 @@ class DesktopTasksControllerTest : ShellTestCase() { val task2 = setUpFreeformTask(displayId = DEFAULT_DISPLAY) val wallpaperToken = MockToken().token() - desktopModeTaskRepository.wallpaperActivityToken = wallpaperToken - desktopModeTaskRepository.addClosingTask(displayId = DEFAULT_DISPLAY, taskId = task2.taskId) + taskRepository.wallpaperActivityToken = wallpaperToken + taskRepository.addClosingTask(displayId = DEFAULT_DISPLAY, taskId = task2.taskId) val result = controller.handleRequest(Binder(), createTransition(task1, type = TRANSIT_CLOSE)) // Should create remove wallpaper transaction @@ -1842,8 +2000,8 @@ class DesktopTasksControllerTest : ShellTestCase() { val task2 = setUpFreeformTask(displayId = DEFAULT_DISPLAY) val wallpaperToken = MockToken().token() - desktopModeTaskRepository.wallpaperActivityToken = wallpaperToken - desktopModeTaskRepository.minimizeTask(displayId = DEFAULT_DISPLAY, taskId = task2.taskId) + taskRepository.wallpaperActivityToken = wallpaperToken + taskRepository.minimizeTask(displayId = DEFAULT_DISPLAY, taskId = task2.taskId) val result = controller.handleRequest(Binder(), createTransition(task1, type = TRANSIT_CLOSE)) // Should create remove wallpaper transaction @@ -1859,8 +2017,8 @@ class DesktopTasksControllerTest : ShellTestCase() { val task2 = setUpFreeformTask(displayId = DEFAULT_DISPLAY) val wallpaperToken = MockToken().token() - desktopModeTaskRepository.wallpaperActivityToken = wallpaperToken - desktopModeTaskRepository.minimizeTask(displayId = DEFAULT_DISPLAY, taskId = task2.taskId) + taskRepository.wallpaperActivityToken = wallpaperToken + taskRepository.minimizeTask(displayId = DEFAULT_DISPLAY, taskId = task2.taskId) val result = controller.handleRequest(Binder(), createTransition(task1, type = TRANSIT_CLOSE)) // Should create remove wallpaper transaction @@ -1877,11 +2035,11 @@ class DesktopTasksControllerTest : ShellTestCase() { val task2 = setUpFreeformTask(displayId = DEFAULT_DISPLAY) val wallpaperToken = MockToken().token() - desktopModeTaskRepository.wallpaperActivityToken = wallpaperToken - desktopModeTaskRepository.minimizeTask(displayId = DEFAULT_DISPLAY, taskId = task2.taskId) + taskRepository.wallpaperActivityToken = wallpaperToken + taskRepository.minimizeTask(displayId = DEFAULT_DISPLAY, taskId = task2.taskId) // Task is being minimized so mark it as not visible. - desktopModeTaskRepository - .updateVisibleFreeformTasks(displayId = DEFAULT_DISPLAY, task2.taskId, false) + taskRepository + .updateTaskVisibility(displayId = DEFAULT_DISPLAY, task2.taskId, false) val result = controller.handleRequest(Binder(), createTransition(task2, type = TRANSIT_TO_BACK)) assertNull(result, "Should not handle request") @@ -1975,9 +2133,9 @@ class DesktopTasksControllerTest : ShellTestCase() { task1.isFocused = false task2.isFocused = true task3.isFocused = false - desktopModeTaskRepository.wallpaperActivityToken = wallpaperToken - desktopModeTaskRepository.minimizeTask(DEFAULT_DISPLAY, task1.taskId) - desktopModeTaskRepository.updateVisibleFreeformTasks(DEFAULT_DISPLAY, task3.taskId, + taskRepository.wallpaperActivityToken = wallpaperToken + taskRepository.minimizeTask(DEFAULT_DISPLAY, task1.taskId) + taskRepository.updateTaskVisibility(DEFAULT_DISPLAY, task3.taskId, visible = false) controller.enterFullscreen(DEFAULT_DISPLAY, transitionSource = UNKNOWN) @@ -1998,7 +2156,7 @@ class DesktopTasksControllerTest : ShellTestCase() { task1.isFocused = false task2.isFocused = true task3.isFocused = false - desktopModeTaskRepository.wallpaperActivityToken = wallpaperToken + taskRepository.wallpaperActivityToken = wallpaperToken controller.enterFullscreen(DEFAULT_DISPLAY, transitionSource = UNKNOWN) val wct = getLatestExitDesktopWct() @@ -2247,9 +2405,9 @@ class DesktopTasksControllerTest : ShellTestCase() { task1.isFocused = false task2.isFocused = true task3.isFocused = false - desktopModeTaskRepository.wallpaperActivityToken = wallpaperToken - desktopModeTaskRepository.minimizeTask(DEFAULT_DISPLAY, task1.taskId) - desktopModeTaskRepository.updateVisibleFreeformTasks(DEFAULT_DISPLAY, task3.taskId, + taskRepository.wallpaperActivityToken = wallpaperToken + taskRepository.minimizeTask(DEFAULT_DISPLAY, task1.taskId) + taskRepository.updateTaskVisibility(DEFAULT_DISPLAY, task3.taskId, visible = false) controller.enterSplit(DEFAULT_DISPLAY, leftOrTop = false) @@ -2275,7 +2433,7 @@ class DesktopTasksControllerTest : ShellTestCase() { task1.isFocused = false task2.isFocused = true task3.isFocused = false - desktopModeTaskRepository.wallpaperActivityToken = wallpaperToken + taskRepository.wallpaperActivityToken = wallpaperToken controller.enterSplit(DEFAULT_DISPLAY, leftOrTop = false) @@ -2327,7 +2485,7 @@ class DesktopTasksControllerTest : ShellTestCase() { val task = setUpFreeformTask(DEFAULT_DISPLAY, bounds) controller.toggleDesktopTaskSize(task) - assertThat(desktopModeTaskRepository.removeBoundsBeforeMaximize(task.taskId)).isEqualTo(bounds) + assertThat(taskRepository.removeBoundsBeforeMaximize(task.taskId)).isEqualTo(bounds) } @Test @@ -2400,12 +2558,24 @@ class DesktopTasksControllerTest : ShellTestCase() { controller.toggleDesktopTaskSize(task) // Assert last bounds before maximize removed after use - assertThat(desktopModeTaskRepository.removeBoundsBeforeMaximize(task.taskId)).isNull() + assertThat(taskRepository.removeBoundsBeforeMaximize(task.taskId)).isNull() } private val desktopWallpaperIntent: Intent get() = Intent(context, DesktopWallpaperActivity::class.java) + private fun addFreeformTaskAtPosition( + pos: DesktopTaskPosition, + stableBounds: Rect, + bounds: Rect = DEFAULT_LANDSCAPE_BOUNDS, + offsetPos: Point = Point(0, 0) + ): RunningTaskInfo { + val offset = pos.getTopLeftCoordinates(stableBounds, bounds) + val prevTaskBounds = Rect(bounds) + prevTaskBounds.offsetTo(offset.x + offsetPos.x, offset.y + offsetPos.y) + return setUpFreeformTask(bounds = prevTaskBounds) + } + private fun setUpFreeformTask( displayId: Int = DEFAULT_DISPLAY, bounds: Rect? = null @@ -2414,9 +2584,9 @@ class DesktopTasksControllerTest : ShellTestCase() { val activityInfo = ActivityInfo() task.topActivityInfo = activityInfo whenever(shellTaskOrganizer.getRunningTaskInfo(task.taskId)).thenReturn(task) - desktopModeTaskRepository.addActiveTask(displayId, task.taskId) - desktopModeTaskRepository.updateVisibleFreeformTasks(displayId, task.taskId, visible = true) - desktopModeTaskRepository.addOrMoveFreeformTaskToTop(displayId, task.taskId) + taskRepository.addActiveTask(displayId, task.taskId) + taskRepository.updateTaskVisibility(displayId, task.taskId, visible = true) + taskRepository.addOrMoveFreeformTaskToTop(displayId, task.taskId) runningTasks.add(task) return task } @@ -2434,11 +2604,13 @@ class DesktopTasksControllerTest : ShellTestCase() { windowingMode: Int = WINDOWING_MODE_FULLSCREEN, deviceOrientation: Int = ORIENTATION_LANDSCAPE, screenOrientation: Int = SCREEN_ORIENTATION_UNSPECIFIED, - shouldLetterbox: Boolean = false + shouldLetterbox: Boolean = false, + gravity: Int = Gravity.NO_GRAVITY ): RunningTaskInfo { val task = createFullscreenTask(displayId) val activityInfo = ActivityInfo() activityInfo.screenOrientation = screenOrientation + activityInfo.windowLayout = ActivityInfo.WindowLayout(0, 0F, 0, 0F, gravity, 0, 0) with(task) { topActivityInfo = activityInfo isResizeable = isResizable @@ -2479,11 +2651,23 @@ class DesktopTasksControllerTest : ShellTestCase() { private fun setUpLandscapeDisplay() { whenever(displayLayout.width()).thenReturn(DISPLAY_DIMENSION_LONG) whenever(displayLayout.height()).thenReturn(DISPLAY_DIMENSION_SHORT) + val stableBounds = Rect(0, 0, DISPLAY_DIMENSION_LONG, + DISPLAY_DIMENSION_SHORT - Companion.TASKBAR_FRAME_HEIGHT + ) + whenever(displayLayout.getStableBoundsForDesktopMode(any())).thenAnswer { i -> + (i.arguments.first() as Rect).set(stableBounds) + } } private fun setUpPortraitDisplay() { whenever(displayLayout.width()).thenReturn(DISPLAY_DIMENSION_SHORT) whenever(displayLayout.height()).thenReturn(DISPLAY_DIMENSION_LONG) + val stableBounds = Rect(0, 0, DISPLAY_DIMENSION_SHORT, + DISPLAY_DIMENSION_LONG - Companion.TASKBAR_FRAME_HEIGHT + ) + whenever(displayLayout.getStableBoundsForDesktopMode(any())).thenAnswer { i -> + (i.arguments.first() as Rect).set(stableBounds) + } } private fun setUpSplitScreenTask(displayId: Int = DEFAULT_DISPLAY): RunningTaskInfo { @@ -2495,12 +2679,12 @@ class DesktopTasksControllerTest : ShellTestCase() { } private fun markTaskVisible(task: RunningTaskInfo) { - desktopModeTaskRepository.updateVisibleFreeformTasks( + taskRepository.updateTaskVisibility( task.displayId, task.taskId, visible = true) } private fun markTaskHidden(task: RunningTaskInfo) { - desktopModeTaskRepository.updateVisibleFreeformTasks( + taskRepository.updateTaskVisibility( task.displayId, task.taskId, visible = false) } @@ -2601,6 +2785,7 @@ class DesktopTasksControllerTest : ShellTestCase() { const val SECOND_DISPLAY = 2 val STABLE_BOUNDS = Rect(0, 0, 1000, 1000) const val MAX_TASK_LIMIT = 6 + private const val TASKBAR_FRAME_HEIGHT = 200 } } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksLimiterTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksLimiterTest.kt index 70f3bf8828fa..2d0e428c45cb 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksLimiterTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksLimiterTest.kt @@ -30,6 +30,8 @@ import androidx.test.filters.SmallTest import com.android.dx.mockito.inline.extended.ExtendedMockito import com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn import com.android.dx.mockito.inline.extended.StaticMockitoSession +import com.android.internal.jank.Cuj.CUJ_DESKTOP_MODE_MINIMIZE_WINDOW +import com.android.internal.jank.InteractionJankMonitor import com.android.wm.shell.ShellTaskOrganizer import com.android.wm.shell.ShellTestCase import com.android.wm.shell.desktopmode.DesktopTestHelpers.Companion.createFreeformTask @@ -47,6 +49,8 @@ import org.junit.runner.RunWith import org.mockito.Mock import org.mockito.Mockito.any import org.mockito.Mockito.`when` +import org.mockito.kotlin.eq +import org.mockito.kotlin.verify import org.mockito.quality.Strictness @@ -65,6 +69,7 @@ class DesktopTasksLimiterTest : ShellTestCase() { @Mock lateinit var shellTaskOrganizer: ShellTaskOrganizer @Mock lateinit var transitions: Transitions + @Mock lateinit var interactionJankMonitor: InteractionJankMonitor private lateinit var mockitoSession: StaticMockitoSession private lateinit var desktopTasksLimiter: DesktopTasksLimiter @@ -79,7 +84,8 @@ class DesktopTasksLimiterTest : ShellTestCase() { desktopTaskRepo = DesktopModeTaskRepository() desktopTasksLimiter = - DesktopTasksLimiter(transitions, desktopTaskRepo, shellTaskOrganizer, MAX_TASK_LIMIT) + DesktopTasksLimiter(transitions, desktopTaskRepo, shellTaskOrganizer, MAX_TASK_LIMIT, + interactionJankMonitor, mContext) } @After @@ -90,14 +96,16 @@ class DesktopTasksLimiterTest : ShellTestCase() { @Test fun createDesktopTasksLimiter_withZeroLimit_shouldThrow() { assertFailsWith<IllegalArgumentException> { - DesktopTasksLimiter(transitions, desktopTaskRepo, shellTaskOrganizer, 0) + DesktopTasksLimiter(transitions, desktopTaskRepo, shellTaskOrganizer, 0, + interactionJankMonitor, mContext) } } @Test fun createDesktopTasksLimiter_withNegativeLimit_shouldThrow() { assertFailsWith<IllegalArgumentException> { - DesktopTasksLimiter(transitions, desktopTaskRepo, shellTaskOrganizer, -5) + DesktopTasksLimiter(transitions, desktopTaskRepo, shellTaskOrganizer, -5, + interactionJankMonitor, mContext) } } @@ -325,7 +333,8 @@ class DesktopTasksLimiterTest : ShellTestCase() { @Test fun getTaskToMinimizeIfNeeded_tasksAboveLimit_otherLimit_returnsBackTask() { desktopTasksLimiter = - DesktopTasksLimiter(transitions, desktopTaskRepo, shellTaskOrganizer, MAX_TASK_LIMIT2) + DesktopTasksLimiter(transitions, desktopTaskRepo, shellTaskOrganizer, MAX_TASK_LIMIT2, + interactionJankMonitor, mContext) val tasks = (1..MAX_TASK_LIMIT2 + 1).map { setUpFreeformTask() } val minimizedTask = desktopTasksLimiter.getTaskToMinimizeIfNeeded( @@ -347,6 +356,91 @@ class DesktopTasksLimiterTest : ShellTestCase() { assertThat(minimizedTask).isEqualTo(tasks.last()) } + @Test + fun minimizeTransitionReadyAndFinished_logsJankInstrumentationBeginAndEnd() { + (1..<MAX_TASK_LIMIT).forEach { _ -> setUpFreeformTask() } + val transition = Binder() + val task = setUpFreeformTask() + desktopTasksLimiter.addPendingMinimizeChange( + transition, displayId = DEFAULT_DISPLAY, taskId = task.taskId) + + desktopTasksLimiter.getTransitionObserver().onTransitionReady( + transition, + TransitionInfoBuilder(TRANSIT_OPEN).build(), + StubTransaction() /* startTransaction */, + StubTransaction() /* finishTransaction */) + + desktopTasksLimiter.getTransitionObserver().onTransitionStarting(transition) + + verify(interactionJankMonitor).begin( + any(), + eq(mContext), + eq(CUJ_DESKTOP_MODE_MINIMIZE_WINDOW)) + + desktopTasksLimiter.getTransitionObserver().onTransitionFinished( + transition, + /* aborted = */ false) + + verify(interactionJankMonitor).end(eq(CUJ_DESKTOP_MODE_MINIMIZE_WINDOW)) + } + + @Test + fun minimizeTransitionReadyAndAborted_logsJankInstrumentationBeginAndCancel() { + (1..<MAX_TASK_LIMIT).forEach { _ -> setUpFreeformTask() } + val transition = Binder() + val task = setUpFreeformTask() + desktopTasksLimiter.addPendingMinimizeChange( + transition, displayId = DEFAULT_DISPLAY, taskId = task.taskId) + + desktopTasksLimiter.getTransitionObserver().onTransitionReady( + transition, + TransitionInfoBuilder(TRANSIT_OPEN).build(), + StubTransaction() /* startTransaction */, + StubTransaction() /* finishTransaction */) + + desktopTasksLimiter.getTransitionObserver().onTransitionStarting(transition) + + verify(interactionJankMonitor).begin( + any(), + eq(mContext), + eq(CUJ_DESKTOP_MODE_MINIMIZE_WINDOW)) + + desktopTasksLimiter.getTransitionObserver().onTransitionFinished( + transition, + /* aborted = */ true) + + verify(interactionJankMonitor).cancel(eq(CUJ_DESKTOP_MODE_MINIMIZE_WINDOW)) + } + + @Test + fun minimizeTransitionReadyAndMerged_logsJankInstrumentationBeginAndEnd() { + (1..<MAX_TASK_LIMIT).forEach { _ -> setUpFreeformTask() } + val mergedTransition = Binder() + val newTransition = Binder() + val task = setUpFreeformTask() + desktopTasksLimiter.addPendingMinimizeChange( + mergedTransition, displayId = DEFAULT_DISPLAY, taskId = task.taskId) + + desktopTasksLimiter.getTransitionObserver().onTransitionReady( + mergedTransition, + TransitionInfoBuilder(TRANSIT_OPEN).build(), + StubTransaction() /* startTransaction */, + StubTransaction() /* finishTransaction */) + + desktopTasksLimiter.getTransitionObserver().onTransitionStarting(mergedTransition) + + verify(interactionJankMonitor).begin( + any(), + eq(mContext), + eq(CUJ_DESKTOP_MODE_MINIMIZE_WINDOW)) + + desktopTasksLimiter.getTransitionObserver().onTransitionMerged( + mergedTransition, + newTransition) + + verify(interactionJankMonitor).end(eq(CUJ_DESKTOP_MODE_MINIMIZE_WINDOW)) + } + private fun setUpFreeformTask( displayId: Int = DEFAULT_DISPLAY, ): RunningTaskInfo { @@ -358,7 +452,7 @@ class DesktopTasksLimiterTest : ShellTestCase() { } private fun markTaskVisible(task: RunningTaskInfo) { - desktopTaskRepo.updateVisibleFreeformTasks( + desktopTaskRepo.updateTaskVisibility( task.displayId, task.taskId, visible = true @@ -366,7 +460,7 @@ class DesktopTasksLimiterTest : ShellTestCase() { } private fun markTaskHidden(task: RunningTaskInfo) { - desktopTaskRepo.updateVisibleFreeformTasks( + desktopTaskRepo.updateTaskVisibility( task.displayId, task.taskId, visible = false diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java index 409b87723e79..81e6d071045a 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java @@ -442,6 +442,27 @@ public class ShellTransitionTests extends ShellTestCase { } @Test + public void testTransitionFilterAnimOverride() { + TransitionFilter filter = new TransitionFilter(); + filter.mRequirements = + new TransitionFilter.Requirement[]{new TransitionFilter.Requirement()}; + filter.mRequirements[0].mCustomAnimation = true; + filter.mRequirements[0].mModes = new int[]{TRANSIT_OPEN, TRANSIT_TO_FRONT}; + + final RunningTaskInfo taskInf = createTaskInfo(1); + final TransitionInfo openTask = new TransitionInfoBuilder(TRANSIT_OPEN) + .addChange(TRANSIT_OPEN, taskInf).build(); + assertFalse(filter.matches(openTask)); + + final TransitionInfo.AnimationOptions overOpts = + TransitionInfo.AnimationOptions.makeCustomAnimOptions("pakname", 0, 0, 0, true); + final TransitionInfo openTaskOpts = new TransitionInfoBuilder(TRANSIT_OPEN) + .addChange(TRANSIT_OPEN, taskInf).build(); + openTaskOpts.getChanges().get(0).setAnimationOptions(overOpts); + assertTrue(filter.matches(openTaskOpts)); + } + + @Test public void testRegisteredRemoteTransition() { Transitions transitions = createTestTransitions(); transitions.replaceDefaultHandlerForTest(mDefaultHandler); diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt index 01c4f3ad6870..e26416047c56 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt @@ -103,6 +103,8 @@ import org.mockito.kotlin.whenever import org.mockito.quality.Strictness import java.util.Optional import java.util.function.Supplier +import junit.framework.Assert.assertFalse +import junit.framework.Assert.assertTrue /** * Tests of [DesktopModeWindowDecorViewModel] @@ -206,25 +208,13 @@ class DesktopModeWindowDecorViewModelTests : ShellTestCase() { val decoration = setUpMockDecorationForTask(task) onTaskOpening(task, taskSurface) + assertTrue(windowDecorByTaskIdSpy.contains(task.taskId)) task.setWindowingMode(WINDOWING_MODE_UNDEFINED) task.setActivityType(ACTIVITY_TYPE_UNDEFINED) onTaskChanging(task, taskSurface) - verify(mockDesktopModeWindowDecorFactory).create( - mContext, - mockDisplayController, - mockSplitScreenController, - mockTaskOrganizer, - task, - taskSurface, - mockMainHandler, - bgExecutor, - mockMainChoreographer, - mockSyncQueue, - mockRootTaskDisplayAreaOrganizer, - mockGenericLinksParser - ) + assertFalse(windowDecorByTaskIdSpy.contains(task.taskId)) verify(decoration).close() } @@ -238,38 +228,12 @@ class DesktopModeWindowDecorViewModelTests : ShellTestCase() { setUpMockDecorationForTask(task) onTaskChanging(task, taskSurface) - verify(mockDesktopModeWindowDecorFactory, never()).create( - mContext, - mockDisplayController, - mockSplitScreenController, - mockTaskOrganizer, - task, - taskSurface, - mockMainHandler, - bgExecutor, - mockMainChoreographer, - mockSyncQueue, - mockRootTaskDisplayAreaOrganizer, - mockGenericLinksParser - ) + assertFalse(windowDecorByTaskIdSpy.contains(task.taskId)) task.setWindowingMode(WINDOWING_MODE_FREEFORM) task.setActivityType(ACTIVITY_TYPE_STANDARD) onTaskChanging(task, taskSurface) - verify(mockDesktopModeWindowDecorFactory, times(1)).create( - mContext, - mockDisplayController, - mockSplitScreenController, - mockTaskOrganizer, - task, - taskSurface, - mockMainHandler, - bgExecutor, - mockMainChoreographer, - mockSyncQueue, - mockRootTaskDisplayAreaOrganizer, - mockGenericLinksParser - ) + assertTrue(windowDecorByTaskIdSpy.contains(task.taskId)) } @Test @@ -364,9 +328,7 @@ class DesktopModeWindowDecorViewModelTests : ShellTestCase() { task.setWindowingMode(ACTIVITY_TYPE_UNDEFINED) onTaskChanging(task) - verify(mockDesktopModeWindowDecorFactory, never()) - .create(any(), any(), any(), any(), eq(task), any(), any(), any(), any(), any(), - any(), any()) + assertFalse(windowDecorByTaskIdSpy.contains(task.taskId)) } @Test @@ -386,9 +348,7 @@ class DesktopModeWindowDecorViewModelTests : ShellTestCase() { setUpMockDecorationsForTasks(task) onTaskOpening(task) - verify(mockDesktopModeWindowDecorFactory) - .create(any(), any(), any(), any(), eq(task), any(), any(), any(), any(), - any(), any(), any()) + assertTrue(windowDecorByTaskIdSpy.contains(task.taskId)) } finally { mockitoSession.finishMocking() } @@ -404,9 +364,7 @@ class DesktopModeWindowDecorViewModelTests : ShellTestCase() { } onTaskOpening(task) - verify(mockDesktopModeWindowDecorFactory, never()) - .create(any(), any(), any(), any(), eq(task), any(), any(), any(), any(), any(), - any(), any()) + assertFalse(windowDecorByTaskIdSpy.contains(task.taskId)) } @Test @@ -422,9 +380,7 @@ class DesktopModeWindowDecorViewModelTests : ShellTestCase() { onTaskOpening(task) - verify(mockDesktopModeWindowDecorFactory, never()) - .create(any(), any(), any(), any(), eq(task), any(), any(), any(), any(), any(), - any(), any()) + assertFalse(windowDecorByTaskIdSpy.contains(task.taskId)) } @Test @@ -520,9 +476,7 @@ class DesktopModeWindowDecorViewModelTests : ShellTestCase() { doReturn(false).`when` { DesktopModeStatus.isDesktopModeSupported(any()) } onTaskOpening(task) - verify(mockDesktopModeWindowDecorFactory, never()) - .create(any(), any(), any(), any(), eq(task), any(), any(), any(), any(), any(), - any(), any()) + assertFalse(windowDecorByTaskIdSpy.contains(task.taskId)) } finally { mockitoSession.finishMocking() } @@ -545,9 +499,7 @@ class DesktopModeWindowDecorViewModelTests : ShellTestCase() { setUpMockDecorationsForTasks(task) onTaskOpening(task) - verify(mockDesktopModeWindowDecorFactory) - .create(any(), any(), any(), any(), eq(task), any(), any(), any(), any(), any(), - any(), any()) + assertTrue(windowDecorByTaskIdSpy.contains(task.taskId)) } finally { mockitoSession.finishMocking() } @@ -569,9 +521,7 @@ class DesktopModeWindowDecorViewModelTests : ShellTestCase() { setUpMockDecorationsForTasks(task) onTaskOpening(task) - verify(mockDesktopModeWindowDecorFactory) - .create(any(), any(), any(), any(), eq(task), any(), any(), any(), any(), any(), - any(), any()) + assertTrue(windowDecorByTaskIdSpy.contains(task.taskId)) } finally { mockitoSession.finishMocking() } @@ -693,7 +643,7 @@ class DesktopModeWindowDecorViewModelTests : ShellTestCase() { @WindowConfiguration.WindowingMode windowingMode: Int, activityType: Int = ACTIVITY_TYPE_STANDARD, focused: Boolean = true, - activityInfo: ActivityInfo = ActivityInfo() + activityInfo: ActivityInfo = ActivityInfo(), ): RunningTaskInfo { return TestRunningTaskInfoBuilder() .setDisplayId(displayId) @@ -709,8 +659,8 @@ class DesktopModeWindowDecorViewModelTests : ShellTestCase() { private fun setUpMockDecorationForTask(task: RunningTaskInfo): DesktopModeWindowDecoration { val decoration = mock(DesktopModeWindowDecoration::class.java) whenever( - mockDesktopModeWindowDecorFactory.create(any(), any(), any(), any(), eq(task), any(), - any(), any(), any(), any(), any(), any()) + mockDesktopModeWindowDecorFactory.create(any(), any(), any(), any(), any(), eq(task), + any(), any(), any(), any(), any(), any(), any()) ).thenReturn(decoration) decoration.mTaskInfo = task whenever(decoration.isFocused).thenReturn(task.isFocused) diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java index cee9307379ea..04b1eed02950 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java @@ -826,10 +826,10 @@ public class DesktopModeWindowDecorationTests extends ShellTestCase { ActivityManager.RunningTaskInfo taskInfo, MaximizeMenuFactory maximizeMenuFactory) { final DesktopModeWindowDecoration windowDecor = new DesktopModeWindowDecoration(mContext, - mMockDisplayController, mMockSplitScreenController, mMockShellTaskOrganizer, - taskInfo, mMockSurfaceControl, mMockHandler, mBgExecutor, mMockChoreographer, - mMockSyncQueue, mMockRootTaskDisplayAreaOrganizer, mMockGenericLinksParser, - SurfaceControl.Builder::new, mMockTransactionSupplier, + mContext, mMockDisplayController, mMockSplitScreenController, + mMockShellTaskOrganizer, taskInfo, mMockSurfaceControl, mMockHandler, mBgExecutor, + mMockChoreographer, mMockSyncQueue, mMockRootTaskDisplayAreaOrganizer, + mMockGenericLinksParser, SurfaceControl.Builder::new, mMockTransactionSupplier, WindowContainerTransaction::new, SurfaceControl::new, mMockSurfaceControlViewHostFactory, maximizeMenuFactory, mMockHandleMenuFactory); windowDecor.setCaptionListeners(mMockTouchEventListener, mMockTouchEventListener, diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java index ca6e03c45e7e..e6e2d0928240 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java @@ -51,6 +51,7 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static org.mockito.quality.Strictness.LENIENT; +import android.annotation.NonNull; import android.app.ActivityManager; import android.content.Context; import android.content.res.Resources; @@ -893,8 +894,8 @@ public class WindowDecorationTests extends ShellTestCase { } private TestWindowDecoration createWindowDecoration(ActivityManager.RunningTaskInfo taskInfo) { - return new TestWindowDecoration(mContext, mMockDisplayController, mMockShellTaskOrganizer, - taskInfo, mMockTaskSurface, + return new TestWindowDecoration(mContext, mContext, mMockDisplayController, + mMockShellTaskOrganizer, taskInfo, mMockTaskSurface, new MockObjectSupplier<>(mMockSurfaceControlBuilders, () -> createMockSurfaceControlBuilder(mock(SurfaceControl.class))), new MockObjectSupplier<>(mMockSurfaceControlTransactions, @@ -932,7 +933,8 @@ public class WindowDecorationTests extends ShellTestCase { } private class TestWindowDecoration extends WindowDecoration<TestView> { - TestWindowDecoration(Context context, DisplayController displayController, + TestWindowDecoration(Context context, @NonNull Context userContext, + DisplayController displayController, ShellTaskOrganizer taskOrganizer, ActivityManager.RunningTaskInfo taskInfo, SurfaceControl taskSurface, Supplier<SurfaceControl.Builder> surfaceControlBuilderSupplier, @@ -940,7 +942,7 @@ public class WindowDecorationTests extends ShellTestCase { Supplier<WindowContainerTransaction> windowContainerTransactionSupplier, Supplier<SurfaceControl> surfaceControlSupplier, SurfaceControlViewHostFactory surfaceControlViewHostFactory) { - super(context, displayController, taskOrganizer, taskInfo, taskSurface, + super(context, userContext, displayController, taskOrganizer, taskInfo, taskSurface, surfaceControlBuilderSupplier, surfaceControlTransactionSupplier, windowContainerTransactionSupplier, surfaceControlSupplier, surfaceControlViewHostFactory); diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp index e302fa8b1fc3..d71f3b6884ae 100644 --- a/libs/hwui/Android.bp +++ b/libs/hwui/Android.bp @@ -736,6 +736,7 @@ cc_defaults { cc_test { name: "hwui_unit_tests", + test_config: "tests/unit/AndroidTest.xml", defaults: [ "hwui_test_defaults", "android_graphics_apex", @@ -803,6 +804,7 @@ cc_test { cc_benchmark { name: "hwuimacro", + test_config: "tests/macrobench/AndroidTest.xml", defaults: ["hwui_test_defaults"], static_libs: ["libhwui"], @@ -822,6 +824,7 @@ cc_benchmark { cc_benchmark { name: "hwuimicro", + test_config: "tests/microbench/AndroidTest.xml", defaults: ["hwui_test_defaults"], static_libs: ["libhwui_static"], diff --git a/libs/hwui/Properties.cpp b/libs/hwui/Properties.cpp index 5d3bc89b40dd..d184f64b1c2c 100644 --- a/libs/hwui/Properties.cpp +++ b/libs/hwui/Properties.cpp @@ -101,6 +101,8 @@ float Properties::maxHdrHeadroomOn8bit = 5.f; // TODO: Refine this number bool Properties::clipSurfaceViews = false; bool Properties::hdr10bitPlus = false; +int Properties::timeoutMultiplier = 1; + StretchEffectBehavior Properties::stretchEffectBehavior = StretchEffectBehavior::ShaderHWUI; DrawingEnabled Properties::drawingEnabled = DrawingEnabled::NotInitialized; @@ -174,6 +176,8 @@ bool Properties::load() { base::GetBoolProperty("debug.hwui.clip_surfaceviews", hwui_flags::clip_surfaceviews()); hdr10bitPlus = hwui_flags::hdr_10bit_plus(); + timeoutMultiplier = android::base::GetIntProperty("ro.hw_timeout_multiplier", 1); + return (prevDebugLayersUpdates != debugLayersUpdates) || (prevDebugOverdraw != debugOverdraw); } diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h index d3176f6879d2..e2646422030e 100644 --- a/libs/hwui/Properties.h +++ b/libs/hwui/Properties.h @@ -343,6 +343,8 @@ public: static bool clipSurfaceViews; static bool hdr10bitPlus; + static int timeoutMultiplier; + static StretchEffectBehavior getStretchEffectBehavior() { return stretchEffectBehavior; } diff --git a/libs/hwui/Readback.cpp b/libs/hwui/Readback.cpp index afe4c3896ed2..2f15722a23e0 100644 --- a/libs/hwui/Readback.cpp +++ b/libs/hwui/Readback.cpp @@ -91,8 +91,10 @@ void Readback::copySurfaceInto(ANativeWindow* window, const std::shared_ptr<Copy { ATRACE_NAME("sync_wait"); - if (sourceFence != -1 && sync_wait(sourceFence.get(), 500 /* ms */) != NO_ERROR) { - ALOGE("Timeout (500ms) exceeded waiting for buffer fence, abandoning readback attempt"); + int syncWaitTimeoutMs = 500 * Properties::timeoutMultiplier; + if (sourceFence != -1 && sync_wait(sourceFence.get(), syncWaitTimeoutMs) != NO_ERROR) { + ALOGE("Timeout (%dms) exceeded waiting for buffer fence, abandoning readback attempt", + syncWaitTimeoutMs); return request->onCopyFinished(CopyResult::Timeout); } } @@ -109,9 +111,8 @@ void Readback::copySurfaceInto(ANativeWindow* window, const std::shared_ptr<Copy sk_sp<SkColorSpace> colorSpace = DataSpaceToColorSpace(static_cast<android_dataspace>(dataspace)); - sk_sp<SkImage> image = - SkImages::DeferredFromAHardwareBuffer(sourceBuffer.get(), kPremul_SkAlphaType, - colorSpace); + sk_sp<SkImage> image = SkImages::DeferredFromAHardwareBuffer(sourceBuffer.get(), + kPremul_SkAlphaType, colorSpace); if (!image.get()) { return request->onCopyFinished(CopyResult::UnknownError); diff --git a/libs/hwui/tests/macrobench/AndroidTest.xml b/libs/hwui/tests/macrobench/AndroidTest.xml new file mode 100644 index 000000000000..5b8576d444cd --- /dev/null +++ b/libs/hwui/tests/macrobench/AndroidTest.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright 2024 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<configuration description="Config for hwuimacro"> + <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer"> + <option name="cleanup" value="true" /> + <option name="push" value="hwuimacro->/data/local/tmp/benchmarktest/hwuimacro" /> + </target_preparer> + <option name="test-suite-tag" value="apct" /> + <option name="not-shardable" value="true" /> + <test class="com.android.tradefed.testtype.GoogleBenchmarkTest" > + <option name="native-benchmark-device-path" value="/data/local/tmp/benchmarktest" /> + <option name="benchmark-module-name" value="hwuimacro" /> + <option name="file-exclusion-filter-regex" value=".*\.config$" /> + </test> +</configuration> diff --git a/libs/hwui/tests/macrobench/how_to_run.txt b/libs/hwui/tests/macrobench/how_to_run.txt index 3c3d36a8977f..59ef25a3aacc 100644 --- a/libs/hwui/tests/macrobench/how_to_run.txt +++ b/libs/hwui/tests/macrobench/how_to_run.txt @@ -3,3 +3,7 @@ adb push $OUT/data/benchmarktest/hwuimacro/hwuimacro /data/benchmarktest/hwuimac adb shell /data/benchmarktest/hwuimacro/hwuimacro shadowgrid2 --onscreen Pass --help to get help + +OR (if you don't need to pass arguments) + +atest hwuimacro diff --git a/libs/hwui/AndroidTest.xml b/libs/hwui/tests/microbench/AndroidTest.xml index 75f61f5f7f9d..d67305dfa323 100644 --- a/libs/hwui/AndroidTest.xml +++ b/libs/hwui/tests/microbench/AndroidTest.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2017 The Android Open Source Project +<!-- Copyright 2024 The Android Open Source Project Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -16,24 +16,13 @@ <configuration description="Config for hwuimicro"> <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer"> <option name="cleanup" value="true" /> - <option name="push" value="hwui_unit_tests->/data/local/tmp/nativetest/hwui_unit_tests" /> <option name="push" value="hwuimicro->/data/local/tmp/benchmarktest/hwuimicro" /> - <option name="push" value="hwuimacro->/data/local/tmp/benchmarktest/hwuimacro" /> </target_preparer> <option name="test-suite-tag" value="apct" /> <option name="not-shardable" value="true" /> - <test class="com.android.tradefed.testtype.GTest" > - <option name="native-test-device-path" value="/data/local/tmp/nativetest" /> - <option name="module-name" value="hwui_unit_tests" /> - </test> <test class="com.android.tradefed.testtype.GoogleBenchmarkTest" > <option name="native-benchmark-device-path" value="/data/local/tmp/benchmarktest" /> <option name="benchmark-module-name" value="hwuimicro" /> <option name="file-exclusion-filter-regex" value=".*\.config$" /> </test> - <test class="com.android.tradefed.testtype.GoogleBenchmarkTest" > - <option name="native-benchmark-device-path" value="/data/local/tmp/benchmarktest" /> - <option name="benchmark-module-name" value="hwuimacro" /> - <option name="file-exclusion-filter-regex" value=".*\.config$" /> - </test> </configuration> diff --git a/libs/hwui/tests/microbench/how_to_run.txt b/libs/hwui/tests/microbench/how_to_run.txt index 915fe5d959f9..c7ddc1a70cd7 100755 --- a/libs/hwui/tests/microbench/how_to_run.txt +++ b/libs/hwui/tests/microbench/how_to_run.txt @@ -1,3 +1,7 @@ mmm -j8 frameworks/base/libs/hwui && adb push $OUT/data/benchmarktest/hwuimicro/hwuimicro /data/benchmarktest/hwuimicro/hwuimicro && adb shell /data/benchmarktest/hwuimicro/hwuimicro + +OR + +atest hwuimicro diff --git a/libs/hwui/tests/unit/AndroidTest.xml b/libs/hwui/tests/unit/AndroidTest.xml new file mode 100644 index 000000000000..dc586c9b740c --- /dev/null +++ b/libs/hwui/tests/unit/AndroidTest.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright 2024 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<configuration description="Config for hwui_unit_tests"> + <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer"> + <option name="cleanup" value="true" /> + <option name="push" value="hwui_unit_tests->/data/local/tmp/nativetest/hwui_unit_tests" /> + </target_preparer> + <option name="test-suite-tag" value="apct" /> + <option name="not-shardable" value="true" /> + <test class="com.android.tradefed.testtype.GTest" > + <option name="native-test-device-path" value="/data/local/tmp/nativetest" /> + <option name="module-name" value="hwui_unit_tests" /> + </test> +</configuration> diff --git a/libs/hwui/tests/unit/how_to_run.txt b/libs/hwui/tests/unit/how_to_run.txt index c11d6eb33358..1a35adf6b11b 100755 --- a/libs/hwui/tests/unit/how_to_run.txt +++ b/libs/hwui/tests/unit/how_to_run.txt @@ -2,3 +2,11 @@ mmm -j8 frameworks/base/libs/hwui && adb push $ANDROID_PRODUCT_OUT/data/nativetest/hwui_unit_tests/hwui_unit_tests \ /data/nativetest/hwui_unit_tests/hwui_unit_tests && adb shell /data/nativetest/hwui_unit_tests/hwui_unit_tests + +OR + +atest hwui_unit_tests + +OR, if you need arguments, they can be passed as native-test-flags, as in: + +atest hwui_unit_tests -- --test-arg com.android.tradefed.testtype.GTest:native-test-flag:"--renderer=skiavk" diff --git a/libs/hwui/tests/unit/main.cpp b/libs/hwui/tests/unit/main.cpp index 76cbc8abc808..3fd15c4c9c51 100644 --- a/libs/hwui/tests/unit/main.cpp +++ b/libs/hwui/tests/unit/main.cpp @@ -15,6 +15,7 @@ */ #include <getopt.h> +#include <log/log.h> #include <signal.h> #include "Properties.h" @@ -65,6 +66,19 @@ static RenderPipelineType parseRenderer(const char* renderer) { return RenderPipelineType::SkiaGL; } +static constexpr const char* renderPipelineTypeName(const RenderPipelineType renderPipelineType) { + switch (renderPipelineType) { + case RenderPipelineType::SkiaGL: + return "SkiaGL"; + case RenderPipelineType::SkiaVulkan: + return "SkiaVulkan"; + case RenderPipelineType::SkiaCpu: + return "SkiaCpu"; + case RenderPipelineType::NotInitialized: + return "NotInitialized"; + } +} + struct Options { RenderPipelineType renderer = RenderPipelineType::SkiaGL; }; @@ -118,6 +132,7 @@ int main(int argc, char* argv[]) { auto opts = parseOptions(argc, argv); Properties::overrideRenderPipelineType(opts.renderer); + ALOGI("Starting HWUI unit tests with %s pipeline", renderPipelineTypeName(opts.renderer)); // Run the tests testing::InitGoogleTest(&argc, argv); |