summaryrefslogtreecommitdiff
path: root/libs
diff options
context:
space:
mode:
Diffstat (limited to 'libs')
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java106
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java74
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/extensions/layout/WindowLayoutComponentImpl.java25
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/util/ExtensionHelper.java17
-rw-r--r--libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/EmbeddingTestUtils.java14
-rw-r--r--libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizerTest.java11
-rw-r--r--libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java16
-rw-r--r--libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskContainerTest.java48
-rw-r--r--libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskFragmentContainerTest.java24
-rw-r--r--libs/WindowManager/Shell/res/values-ro/strings.xml10
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/RootTaskDisplayAreaOrganizer.java8
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java5
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeController.java33
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java5
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java11
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionObserver.java39
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/fullscreen/FullscreenTaskListener.java11
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java13
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipKeepClearAlgorithm.java7
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java49
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java7
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java95
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitscreenEventLogger.java44
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java12
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeControllerTest.java35
25 files changed, 521 insertions, 198 deletions
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
index 126f8350839c..138eee41f109 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
@@ -19,6 +19,7 @@ package androidx.window.extensions.embedding;
import static android.app.ActivityManager.START_SUCCESS;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+import static android.view.Display.DEFAULT_DISPLAY;
import static android.window.TaskFragmentOrganizer.KEY_ERROR_CALLBACK_OP_TYPE;
import static android.window.TaskFragmentOrganizer.KEY_ERROR_CALLBACK_TASK_FRAGMENT_INFO;
import static android.window.TaskFragmentOrganizer.KEY_ERROR_CALLBACK_THROWABLE;
@@ -46,6 +47,7 @@ import android.app.Activity;
import android.app.ActivityClient;
import android.app.ActivityOptions;
import android.app.ActivityThread;
+import android.app.Application;
import android.app.Instrumentation;
import android.content.ComponentName;
import android.content.Context;
@@ -63,18 +65,23 @@ import android.util.Pair;
import android.util.Size;
import android.util.SparseArray;
import android.window.TaskFragmentInfo;
+import android.window.TaskFragmentParentInfo;
import android.window.TaskFragmentTransaction;
import android.window.WindowContainerTransaction;
import androidx.annotation.GuardedBy;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import androidx.window.common.CommonFoldingFeature;
import androidx.window.common.EmptyLifecycleCallbacksAdapter;
+import androidx.window.extensions.WindowExtensionsProvider;
+import androidx.window.extensions.layout.WindowLayoutComponentImpl;
import com.android.internal.annotations.VisibleForTesting;
import java.util.ArrayList;
import java.util.List;
+import java.util.Objects;
import java.util.Set;
import java.util.concurrent.Executor;
import java.util.function.Consumer;
@@ -105,26 +112,65 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
@GuardedBy("mLock")
final SparseArray<TaskContainer> mTaskContainers = new SparseArray<>();
- // Callback to Jetpack to notify about changes to split states.
- @NonNull
+ /** Callback to Jetpack to notify about changes to split states. */
+ @Nullable
private Consumer<List<SplitInfo>> mEmbeddingCallback;
private final List<SplitInfo> mLastReportedSplitStates = new ArrayList<>();
private final Handler mHandler;
final Object mLock = new Object();
private final ActivityStartMonitor mActivityStartMonitor;
+ @NonNull
+ final WindowLayoutComponentImpl mWindowLayoutComponent;
public SplitController() {
+ this((WindowLayoutComponentImpl) Objects.requireNonNull(WindowExtensionsProvider
+ .getWindowExtensions().getWindowLayoutComponent()));
+ }
+
+ @VisibleForTesting
+ SplitController(@NonNull WindowLayoutComponentImpl windowLayoutComponent) {
final MainThreadExecutor executor = new MainThreadExecutor();
mHandler = executor.mHandler;
mPresenter = new SplitPresenter(executor, this);
- ActivityThread activityThread = ActivityThread.currentActivityThread();
+ final ActivityThread activityThread = ActivityThread.currentActivityThread();
+ final Application application = activityThread.getApplication();
// Register a callback to be notified about activities being created.
- activityThread.getApplication().registerActivityLifecycleCallbacks(
- new LifecycleCallbacks());
+ application.registerActivityLifecycleCallbacks(new LifecycleCallbacks());
// Intercept activity starts to route activities to new containers if necessary.
Instrumentation instrumentation = activityThread.getInstrumentation();
+
mActivityStartMonitor = new ActivityStartMonitor();
instrumentation.addMonitor(mActivityStartMonitor);
+ mWindowLayoutComponent = windowLayoutComponent;
+ mWindowLayoutComponent.addFoldingStateChangedCallback(new FoldingFeatureListener());
+ }
+
+ private class FoldingFeatureListener implements Consumer<List<CommonFoldingFeature>> {
+ @Override
+ public void accept(List<CommonFoldingFeature> foldingFeatures) {
+ synchronized (mLock) {
+ final WindowContainerTransaction wct = new WindowContainerTransaction();
+ for (int i = 0; i < mTaskContainers.size(); i++) {
+ final TaskContainer taskContainer = mTaskContainers.valueAt(i);
+ if (!taskContainer.isVisible()) {
+ continue;
+ }
+ if (taskContainer.getDisplayId() != DEFAULT_DISPLAY) {
+ continue;
+ }
+ // TODO(b/238948678): Support reporting display features in all windowing modes.
+ if (taskContainer.isInMultiWindow()) {
+ continue;
+ }
+ if (taskContainer.isEmpty()) {
+ continue;
+ }
+ updateContainersInTask(wct, taskContainer);
+ updateAnimationOverride(taskContainer);
+ }
+ mPresenter.applyTransaction(wct);
+ }
+ }
}
/** Updates the embedding rules applied to future activity launches. */
@@ -191,7 +237,8 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
onTaskFragmentVanished(wct, info);
break;
case TYPE_TASK_FRAGMENT_PARENT_INFO_CHANGED:
- onTaskFragmentParentInfoChanged(wct, taskId, change.getTaskConfiguration());
+ onTaskFragmentParentInfoChanged(wct, taskId,
+ change.getTaskFragmentParentInfo());
break;
case TYPE_TASK_FRAGMENT_ERROR:
final Bundle errorBundle = change.getErrorBundle();
@@ -346,22 +393,33 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
*
* @param wct The {@link WindowContainerTransaction} to make any changes with if needed.
* @param taskId Id of the parent Task that is changed.
- * @param parentConfig Config of the parent Task.
+ * @param parentInfo {@link TaskFragmentParentInfo} of the parent Task.
*/
@VisibleForTesting
@GuardedBy("mLock")
void onTaskFragmentParentInfoChanged(@NonNull WindowContainerTransaction wct,
- int taskId, @NonNull Configuration parentConfig) {
- onTaskConfigurationChanged(taskId, parentConfig);
- if (isInPictureInPicture(parentConfig)) {
- // No need to update presentation in PIP until the Task exit PIP.
- return;
- }
+ int taskId, @NonNull TaskFragmentParentInfo parentInfo) {
final TaskContainer taskContainer = getTaskContainer(taskId);
if (taskContainer == null || taskContainer.isEmpty()) {
Log.e(TAG, "onTaskFragmentParentInfoChanged on empty Task id=" + taskId);
return;
}
+ taskContainer.updateTaskFragmentParentInfo(parentInfo);
+ if (!taskContainer.isVisible()) {
+ // Don't update containers if the task is not visible. We only update containers when
+ // parentInfo#isVisibleRequested is true.
+ return;
+ }
+ onTaskContainerInfoChanged(taskContainer, parentInfo.getConfiguration());
+ if (isInPictureInPicture(parentInfo.getConfiguration())) {
+ // No need to update presentation in PIP until the Task exit PIP.
+ return;
+ }
+ updateContainersInTask(wct, taskContainer);
+ }
+
+ private void updateContainersInTask(@NonNull WindowContainerTransaction wct,
+ @NonNull TaskContainer taskContainer) {
// Update all TaskFragments in the Task. Make a copy of the list since some may be
// removed on updating.
final List<TaskFragmentContainer> containers =
@@ -486,6 +544,7 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
}
/** Called on receiving {@link #onTaskFragmentVanished} for cleanup. */
+ @GuardedBy("mLock")
private void cleanupTaskFragment(@NonNull IBinder taskFragmentToken) {
for (int i = mTaskContainers.size() - 1; i >= 0; i--) {
final TaskContainer taskContainer = mTaskContainers.valueAt(i);
@@ -501,14 +560,11 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
}
}
- private void onTaskConfigurationChanged(int taskId, @NonNull Configuration config) {
- final TaskContainer taskContainer = mTaskContainers.get(taskId);
- if (taskContainer == null) {
- return;
- }
+ @GuardedBy("mLock")
+ private void onTaskContainerInfoChanged(@NonNull TaskContainer taskContainer,
+ @NonNull Configuration config) {
final boolean wasInPip = taskContainer.isInPictureInPicture();
final boolean isInPIp = isInPictureInPicture(config);
- taskContainer.setWindowingMode(config.windowConfiguration.getWindowingMode());
// We need to check the animation override when enter/exit PIP or has bounds changed.
boolean shouldUpdateAnimationOverride = wasInPip != isInPIp;
@@ -532,8 +588,7 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
// Animation will be handled by WM Shell with Shell transition enabled.
return;
}
- if (!taskContainer.isTaskBoundsInitialized()
- || !taskContainer.isWindowingModeInitialized()) {
+ if (!taskContainer.isTaskBoundsInitialized()) {
// We don't know about the Task bounds/windowingMode yet.
return;
}
@@ -1020,6 +1075,7 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
/**
* Returns an empty expanded {@link TaskFragmentContainer} that we can launch an activity into.
*/
+ @GuardedBy("mLock")
@Nullable
private TaskFragmentContainer createEmptyExpandedContainer(
@NonNull WindowContainerTransaction wct, @NonNull Intent intent, int taskId,
@@ -1101,12 +1157,14 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
return newContainer(pendingAppearedActivity, pendingAppearedActivity, taskId);
}
+ @GuardedBy("mLock")
TaskFragmentContainer newContainer(@NonNull Activity pendingAppearedActivity,
@NonNull Activity activityInTask, int taskId) {
return newContainer(pendingAppearedActivity, null /* pendingAppearedIntent */,
activityInTask, taskId);
}
+ @GuardedBy("mLock")
TaskFragmentContainer newContainer(@NonNull Intent pendingAppearedIntent,
@NonNull Activity activityInTask, int taskId) {
return newContainer(null /* pendingAppearedActivity */, pendingAppearedIntent,
@@ -1130,7 +1188,7 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
throw new IllegalArgumentException("activityInTask must not be null,");
}
if (!mTaskContainers.contains(taskId)) {
- mTaskContainers.put(taskId, new TaskContainer(taskId));
+ mTaskContainers.put(taskId, new TaskContainer(taskId, activityInTask));
}
final TaskContainer taskContainer = mTaskContainers.get(taskId);
final TaskFragmentContainer container = new TaskFragmentContainer(pendingAppearedActivity,
@@ -1142,10 +1200,6 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
Log.w(TAG, "Can't find bounds from activity=" + activityInTask);
}
}
- if (!taskContainer.isWindowingModeInitialized()) {
- taskContainer.setWindowingMode(activityInTask.getResources().getConfiguration()
- .windowConfiguration.getWindowingMode());
- }
updateAnimationOverride(taskContainer);
return container;
}
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java
index b5636777568e..95486fa0e440 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java
@@ -24,10 +24,13 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import android.app.Activity;
import android.app.WindowConfiguration;
import android.app.WindowConfiguration.WindowingMode;
+import android.content.res.Configuration;
import android.graphics.Rect;
import android.os.IBinder;
import android.util.ArraySet;
import android.window.TaskFragmentInfo;
+import android.window.TaskFragmentParentInfo;
+import android.window.WindowContainerTransaction;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -42,13 +45,10 @@ class TaskContainer {
/** The unique task id. */
private final int mTaskId;
+ // TODO(b/240219484): consolidate to mConfiguration
/** Available window bounds of this Task. */
private final Rect mTaskBounds = new Rect();
- /** Windowing mode of this Task. */
- @WindowingMode
- private int mWindowingMode = WINDOWING_MODE_UNDEFINED;
-
/** Active TaskFragments in this Task. */
@NonNull
final List<TaskFragmentContainer> mContainers = new ArrayList<>();
@@ -57,24 +57,56 @@ class TaskContainer {
@NonNull
final List<SplitContainer> mSplitContainers = new ArrayList<>();
+ @NonNull
+ private final Configuration mConfiguration;
+
+ private int mDisplayId;
+
+ private boolean mIsVisible;
+
/**
* TaskFragments that the organizer has requested to be closed. They should be removed when
- * the organizer receives {@link SplitController#onTaskFragmentVanished(TaskFragmentInfo)} event
- * for them.
+ * the organizer receives
+ * {@link SplitController#onTaskFragmentVanished(WindowContainerTransaction, TaskFragmentInfo)}
+ * event for them.
*/
final Set<IBinder> mFinishedContainer = new ArraySet<>();
- TaskContainer(int taskId) {
+ /**
+ * The {@link TaskContainer} constructor
+ *
+ * @param taskId The ID of the Task, which must match {@link Activity#getTaskId()} with
+ * {@code activityInTask}.
+ * @param activityInTask The {@link Activity} in the Task with {@code taskId}. It is used to
+ * initialize the {@link TaskContainer} properties.
+ *
+ */
+ TaskContainer(int taskId, @NonNull Activity activityInTask) {
if (taskId == INVALID_TASK_ID) {
throw new IllegalArgumentException("Invalid Task id");
}
mTaskId = taskId;
+ // Make a copy in case the activity's config is updated, and updates the TaskContainer's
+ // config unexpectedly.
+ mConfiguration = new Configuration(activityInTask.getResources().getConfiguration());
+ mDisplayId = activityInTask.getDisplayId();
+ // Note that it is always called when there's a new Activity is started, which implies
+ // the host task is visible.
+ mIsVisible = true;
}
int getTaskId() {
return mTaskId;
}
+ int getDisplayId() {
+ return mDisplayId;
+ }
+
+ boolean isVisible() {
+ return mIsVisible;
+ }
+
@NonNull
Rect getTaskBounds() {
return mTaskBounds;
@@ -94,13 +126,16 @@ class TaskContainer {
return !mTaskBounds.isEmpty();
}
- void setWindowingMode(int windowingMode) {
- mWindowingMode = windowingMode;
+ @NonNull
+ Configuration getConfiguration() {
+ // Make a copy in case the config is updated unexpectedly.
+ return new Configuration(mConfiguration);
}
- /** Whether the Task windowing mode has been initialized. */
- boolean isWindowingModeInitialized() {
- return mWindowingMode != WINDOWING_MODE_UNDEFINED;
+ void updateTaskFragmentParentInfo(@NonNull TaskFragmentParentInfo info) {
+ mConfiguration.setTo(info.getConfiguration());
+ mDisplayId = info.getDisplayId();
+ mIsVisible = info.isVisibleRequested();
}
/**
@@ -123,13 +158,20 @@ class TaskContainer {
// DecorCaptionView won't work correctly. As a result, have the TaskFragment to be in the
// Task windowing mode if the Task is in multi window.
// TODO we won't need this anymore after we migrate Freeform caption to WM Shell.
- return WindowConfiguration.inMultiWindowMode(mWindowingMode)
- ? mWindowingMode
- : WINDOWING_MODE_MULTI_WINDOW;
+ return isInMultiWindow() ? getWindowingMode() : WINDOWING_MODE_MULTI_WINDOW;
}
boolean isInPictureInPicture() {
- return mWindowingMode == WINDOWING_MODE_PINNED;
+ return getWindowingMode() == WINDOWING_MODE_PINNED;
+ }
+
+ boolean isInMultiWindow() {
+ return WindowConfiguration.inMultiWindowMode(getWindowingMode());
+ }
+
+ @WindowingMode
+ private int getWindowingMode() {
+ return getConfiguration().windowConfiguration.getWindowingMode();
}
/** Whether there is any {@link TaskFragmentContainer} below this Task. */
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 f24401f0cd53..d78331737fdc 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/layout/WindowLayoutComponentImpl.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/layout/WindowLayoutComponentImpl.java
@@ -47,6 +47,7 @@ import androidx.window.common.RawFoldingFeatureProducer;
import androidx.window.util.DataProducer;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -80,6 +81,11 @@ public class WindowLayoutComponentImpl implements WindowLayoutComponent {
mFoldingFeatureProducer.addDataChangedCallback(this::onDisplayFeaturesChanged);
}
+ /** Registers to listen to {@link CommonFoldingFeature} changes */
+ public void addFoldingStateChangedCallback(Consumer<List<CommonFoldingFeature>> consumer) {
+ mFoldingFeatureProducer.addDataChangedCallback(consumer);
+ }
+
/**
* Adds a listener interested in receiving updates to {@link WindowLayoutInfo}
*
@@ -225,12 +231,23 @@ public class WindowLayoutComponentImpl implements WindowLayoutComponent {
*/
private List<DisplayFeature> getDisplayFeatures(
@NonNull @UiContext Context context, List<CommonFoldingFeature> storedFeatures) {
- List<DisplayFeature> features = new ArrayList<>();
if (!shouldReportDisplayFeatures(context)) {
+ return Collections.emptyList();
+ }
+ return getDisplayFeatures(context.getDisplayId(),
+ context.getResources().getConfiguration().windowConfiguration,
+ storedFeatures);
+ }
+
+ /** @see #getDisplayFeatures(Context, List) */
+ private List<DisplayFeature> getDisplayFeatures(int displayId,
+ @NonNull WindowConfiguration windowConfiguration,
+ List<CommonFoldingFeature> storedFeatures) {
+ List<DisplayFeature> features = new ArrayList<>();
+ if (displayId != DEFAULT_DISPLAY) {
return features;
}
- int displayId = context.getDisplay().getDisplayId();
for (CommonFoldingFeature baseFeature : storedFeatures) {
Integer state = convertToExtensionState(baseFeature.getState());
if (state == null) {
@@ -238,7 +255,7 @@ public class WindowLayoutComponentImpl implements WindowLayoutComponent {
}
Rect featureRect = baseFeature.getRect();
rotateRectToDisplayRotation(displayId, featureRect);
- transformToWindowSpaceRect(context, featureRect);
+ transformToWindowSpaceRect(windowConfiguration, featureRect);
if (!isZero(featureRect)) {
// TODO(b/228641877): Remove guarding when fixed.
@@ -263,6 +280,8 @@ public class WindowLayoutComponentImpl implements WindowLayoutComponent {
windowingMode = ActivityClient.getInstance().getTaskWindowingMode(
context.getActivityToken());
} else {
+ // TODO(b/242674941): use task windowing mode for window context that associates with
+ // activity.
windowingMode = context.getResources().getConfiguration().windowConfiguration
.getWindowingMode();
}
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/util/ExtensionHelper.java b/libs/WindowManager/Jetpack/src/androidx/window/util/ExtensionHelper.java
index 31bf96313a95..9e2611f392a3 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/util/ExtensionHelper.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/util/ExtensionHelper.java
@@ -21,6 +21,7 @@ import static android.view.Surface.ROTATION_180;
import static android.view.Surface.ROTATION_270;
import static android.view.Surface.ROTATION_90;
+import android.app.WindowConfiguration;
import android.content.Context;
import android.graphics.Rect;
import android.hardware.display.DisplayManagerGlobal;
@@ -89,13 +90,21 @@ public final class ExtensionHelper {
/** Transforms rectangle from absolute coordinate space to the window coordinate space. */
public static void transformToWindowSpaceRect(@NonNull @UiContext Context context,
Rect inOutRect) {
- Rect windowRect = getWindowBounds(context);
- if (!Rect.intersects(inOutRect, windowRect)) {
+ transformToWindowSpaceRect(getWindowBounds(context), inOutRect);
+ }
+
+ /** @see ExtensionHelper#transformToWindowSpaceRect(Context, Rect) */
+ public static void transformToWindowSpaceRect(@NonNull WindowConfiguration windowConfiguration,
+ Rect inOutRect) {
+ transformToWindowSpaceRect(windowConfiguration.getBounds(), inOutRect);
+ }
+
+ private static void transformToWindowSpaceRect(@NonNull Rect bounds, @NonNull Rect inOutRect) {
+ if (!inOutRect.intersect(bounds)) {
inOutRect.setEmpty();
return;
}
- inOutRect.intersect(windowRect);
- inOutRect.offset(-windowRect.left, -windowRect.top);
+ inOutRect.offset(-bounds.left, -bounds.top);
}
/**
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 effc1a3ef3ea..b835a050e34b 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
@@ -16,9 +16,12 @@
package androidx.window.extensions.embedding;
+import static android.view.Display.DEFAULT_DISPLAY;
+
import static androidx.window.extensions.embedding.SplitRule.FINISH_ALWAYS;
import static androidx.window.extensions.embedding.SplitRule.FINISH_NEVER;
+import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import android.annotation.NonNull;
@@ -26,6 +29,7 @@ import android.app.Activity;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
+import android.content.res.Resources;
import android.graphics.Point;
import android.graphics.Rect;
import android.util.Pair;
@@ -130,4 +134,14 @@ public class EmbeddingTestUtils {
primaryBounds.width() + 1, primaryBounds.height() + 1);
return aInfo;
}
+
+ static TaskContainer createTestTaskContainer() {
+ Resources resources = mock(Resources.class);
+ doReturn(new Configuration()).when(resources).getConfiguration();
+ Activity activity = mock(Activity.class);
+ doReturn(resources).when(activity).getResources();
+ doReturn(DEFAULT_DISPLAY).when(activity).getDisplayId();
+
+ return new TaskContainer(TASK_ID, activity);
+ }
}
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 58a627bafa16..957a24873998 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
@@ -19,6 +19,7 @@ package androidx.window.extensions.embedding;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static androidx.window.extensions.embedding.EmbeddingTestUtils.TASK_ID;
+import static androidx.window.extensions.embedding.EmbeddingTestUtils.createTestTaskContainer;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
@@ -26,12 +27,14 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import android.content.Intent;
import android.content.res.Configuration;
import android.graphics.Point;
+import android.os.Handler;
import android.platform.test.annotations.Presubmit;
import android.window.TaskFragmentInfo;
import android.window.TaskFragmentTransaction;
@@ -65,7 +68,10 @@ public class JetpackTaskFragmentOrganizerTest {
private WindowContainerTransaction mTransaction;
@Mock
private JetpackTaskFragmentOrganizer.TaskFragmentCallback mCallback;
+ @Mock
private SplitController mSplitController;
+ @Mock
+ private Handler mHandler;
private JetpackTaskFragmentOrganizer mOrganizer;
@Before
@@ -73,9 +79,8 @@ public class JetpackTaskFragmentOrganizerTest {
MockitoAnnotations.initMocks(this);
mOrganizer = new JetpackTaskFragmentOrganizer(Runnable::run, mCallback);
mOrganizer.registerOrganizer();
- mSplitController = new SplitController();
spyOn(mOrganizer);
- spyOn(mSplitController);
+ doReturn(mHandler).when(mSplitController).getHandler();
}
@Test
@@ -113,7 +118,7 @@ public class JetpackTaskFragmentOrganizerTest {
@Test
public void testExpandTaskFragment() {
- final TaskContainer taskContainer = new TaskContainer(TASK_ID);
+ final TaskContainer taskContainer = createTestTaskContainer();
final TaskFragmentContainer container = new TaskFragmentContainer(null /* activity */,
new Intent(), taskContainer, mSplitController);
final TaskFragmentInfo info = createMockInfo(container);
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java
index 58870a66feea..8a8b5d94e943 100644
--- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java
+++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java
@@ -19,6 +19,7 @@ package androidx.window.extensions.embedding;
import static android.app.ActivityManager.START_CANCELED;
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+import static android.view.Display.DEFAULT_DISPLAY;
import static android.window.TaskFragmentTransaction.TYPE_ACTIVITY_REPARENTED_TO_TASK;
import static android.window.TaskFragmentTransaction.TYPE_TASK_FRAGMENT_APPEARED;
import static android.window.TaskFragmentTransaction.TYPE_TASK_FRAGMENT_ERROR;
@@ -33,9 +34,11 @@ import static androidx.window.extensions.embedding.EmbeddingTestUtils.TASK_ID;
import static androidx.window.extensions.embedding.EmbeddingTestUtils.createActivityInfoWithMinDimensions;
import static androidx.window.extensions.embedding.EmbeddingTestUtils.createMockTaskFragmentInfo;
import static androidx.window.extensions.embedding.EmbeddingTestUtils.createSplitRule;
+import static androidx.window.extensions.embedding.EmbeddingTestUtils.createTestTaskContainer;
import static androidx.window.extensions.embedding.EmbeddingTestUtils.getSplitBounds;
import static androidx.window.extensions.embedding.SplitRule.FINISH_ALWAYS;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doCallRealMethod;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
@@ -75,6 +78,7 @@ import android.os.IBinder;
import android.platform.test.annotations.Presubmit;
import android.window.TaskFragmentInfo;
import android.window.TaskFragmentOrganizer;
+import android.window.TaskFragmentParentInfo;
import android.window.TaskFragmentTransaction;
import android.window.WindowContainerTransaction;
@@ -138,7 +142,7 @@ public class SplitControllerTest {
@Test
public void testGetTopActiveContainer() {
- final TaskContainer taskContainer = new TaskContainer(TASK_ID);
+ final TaskContainer taskContainer = createTestTaskContainer();
// tf1 has no running activity so is not active.
final TaskFragmentContainer tf1 = new TaskFragmentContainer(null /* activity */,
new Intent(), taskContainer, mSplitController);
@@ -198,6 +202,7 @@ public class SplitControllerTest {
@Test
public void testOnTaskFragmentAppearEmptyTimeout() {
final TaskFragmentContainer tf = mSplitController.newContainer(mActivity, TASK_ID);
+ doCallRealMethod().when(mSplitController).onTaskFragmentAppearEmptyTimeout(any(), any());
mSplitController.onTaskFragmentAppearEmptyTimeout(mTransaction, tf);
verify(mSplitPresenter).cleanupContainer(mTransaction, tf,
@@ -308,7 +313,7 @@ public class SplitControllerTest {
@Test
public void testOnStartActivityResultError() {
final Intent intent = new Intent();
- final TaskContainer taskContainer = new TaskContainer(TASK_ID);
+ final TaskContainer taskContainer = createTestTaskContainer();
final TaskFragmentContainer container = new TaskFragmentContainer(null /* activity */,
intent, taskContainer, mSplitController);
final SplitController.ActivityStartMonitor monitor =
@@ -1038,15 +1043,16 @@ public class SplitControllerTest {
@Test
public void testOnTransactionReady_taskFragmentParentInfoChanged() {
final TaskFragmentTransaction transaction = new TaskFragmentTransaction();
- final Configuration taskConfig = new Configuration();
+ final TaskFragmentParentInfo parentInfo = new TaskFragmentParentInfo(Configuration.EMPTY,
+ DEFAULT_DISPLAY, true);
transaction.addChange(new TaskFragmentTransaction.Change(
TYPE_TASK_FRAGMENT_PARENT_INFO_CHANGED)
.setTaskId(TASK_ID)
- .setTaskConfiguration(taskConfig));
+ .setTaskFragmentParentInfo(parentInfo));
mSplitController.onTransactionReady(transaction);
verify(mSplitController).onTaskFragmentParentInfoChanged(any(), eq(TASK_ID),
- eq(taskConfig));
+ eq(parentInfo));
verify(mSplitPresenter).onTransactionHandled(eq(transaction.getTransactionToken()), any(),
anyInt(), anyBoolean());
}
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskContainerTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskContainerTest.java
index dd67e48ef353..af9c6ba5c162 100644
--- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskContainerTest.java
+++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskContainerTest.java
@@ -21,9 +21,10 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
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 android.view.Display.DEFAULT_DISPLAY;
import static androidx.window.extensions.embedding.EmbeddingTestUtils.TASK_BOUNDS;
-import static androidx.window.extensions.embedding.EmbeddingTestUtils.TASK_ID;
+import static androidx.window.extensions.embedding.EmbeddingTestUtils.createTestTaskContainer;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -34,8 +35,10 @@ import static org.mockito.Mockito.mock;
import android.app.Activity;
import android.content.Intent;
+import android.content.res.Configuration;
import android.graphics.Rect;
import android.platform.test.annotations.Presubmit;
+import android.window.TaskFragmentParentInfo;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
@@ -66,7 +69,7 @@ public class TaskContainerTest {
@Test
public void testIsTaskBoundsInitialized() {
- final TaskContainer taskContainer = new TaskContainer(TASK_ID);
+ final TaskContainer taskContainer = createTestTaskContainer();
assertFalse(taskContainer.isTaskBoundsInitialized());
@@ -77,7 +80,7 @@ public class TaskContainerTest {
@Test
public void testSetTaskBounds() {
- final TaskContainer taskContainer = new TaskContainer(TASK_ID);
+ final TaskContainer taskContainer = createTestTaskContainer();
assertFalse(taskContainer.setTaskBounds(new Rect()));
@@ -87,30 +90,24 @@ public class TaskContainerTest {
}
@Test
- public void testIsWindowingModeInitialized() {
- final TaskContainer taskContainer = new TaskContainer(TASK_ID);
-
- assertFalse(taskContainer.isWindowingModeInitialized());
-
- taskContainer.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
-
- assertTrue(taskContainer.isWindowingModeInitialized());
- }
-
- @Test
public void testGetWindowingModeForSplitTaskFragment() {
- final TaskContainer taskContainer = new TaskContainer(TASK_ID);
+ final TaskContainer taskContainer = createTestTaskContainer();
final Rect splitBounds = new Rect(0, 0, 500, 1000);
+ final Configuration configuration = new Configuration();
assertEquals(WINDOWING_MODE_MULTI_WINDOW,
taskContainer.getWindowingModeForSplitTaskFragment(splitBounds));
- taskContainer.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
+ configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
+ taskContainer.updateTaskFragmentParentInfo(new TaskFragmentParentInfo(configuration,
+ DEFAULT_DISPLAY, true /* visible */));
assertEquals(WINDOWING_MODE_MULTI_WINDOW,
taskContainer.getWindowingModeForSplitTaskFragment(splitBounds));
- taskContainer.setWindowingMode(WINDOWING_MODE_FREEFORM);
+ configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FREEFORM);
+ taskContainer.updateTaskFragmentParentInfo(new TaskFragmentParentInfo(configuration,
+ DEFAULT_DISPLAY, true /* visible */));
assertEquals(WINDOWING_MODE_FREEFORM,
taskContainer.getWindowingModeForSplitTaskFragment(splitBounds));
@@ -123,22 +120,27 @@ public class TaskContainerTest {
@Test
public void testIsInPictureInPicture() {
- final TaskContainer taskContainer = new TaskContainer(TASK_ID);
+ final TaskContainer taskContainer = createTestTaskContainer();
+ final Configuration configuration = new Configuration();
assertFalse(taskContainer.isInPictureInPicture());
- taskContainer.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
+ configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
+ taskContainer.updateTaskFragmentParentInfo(new TaskFragmentParentInfo(configuration,
+ DEFAULT_DISPLAY, true /* visible */));
assertFalse(taskContainer.isInPictureInPicture());
- taskContainer.setWindowingMode(WINDOWING_MODE_PINNED);
+ configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_PINNED);
+ taskContainer.updateTaskFragmentParentInfo(new TaskFragmentParentInfo(configuration,
+ DEFAULT_DISPLAY, true /* visible */));
assertTrue(taskContainer.isInPictureInPicture());
}
@Test
public void testIsEmpty() {
- final TaskContainer taskContainer = new TaskContainer(TASK_ID);
+ final TaskContainer taskContainer = createTestTaskContainer();
assertTrue(taskContainer.isEmpty());
@@ -155,7 +157,7 @@ public class TaskContainerTest {
@Test
public void testGetTopTaskFragmentContainer() {
- final TaskContainer taskContainer = new TaskContainer(TASK_ID);
+ final TaskContainer taskContainer = createTestTaskContainer();
assertNull(taskContainer.getTopTaskFragmentContainer());
final TaskFragmentContainer tf0 = new TaskFragmentContainer(null /* activity */,
@@ -169,7 +171,7 @@ public class TaskContainerTest {
@Test
public void testGetTopNonFinishingActivity() {
- final TaskContainer taskContainer = new TaskContainer(TASK_ID);
+ final TaskContainer taskContainer = createTestTaskContainer();
assertNull(taskContainer.getTopNonFinishingActivity());
final TaskFragmentContainer tf0 = mock(TaskFragmentContainer.class);
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskFragmentContainerTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskFragmentContainerTest.java
index 082774e048a9..73428a2dc800 100644
--- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskFragmentContainerTest.java
+++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskFragmentContainerTest.java
@@ -16,8 +16,8 @@
package androidx.window.extensions.embedding;
-import static androidx.window.extensions.embedding.EmbeddingTestUtils.TASK_ID;
import static androidx.window.extensions.embedding.EmbeddingTestUtils.createMockTaskFragmentInfo;
+import static androidx.window.extensions.embedding.EmbeddingTestUtils.createTestTaskContainer;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
@@ -90,7 +90,7 @@ public class TaskFragmentContainerTest {
@Test
public void testNewContainer() {
- final TaskContainer taskContainer = new TaskContainer(TASK_ID);
+ final TaskContainer taskContainer = createTestTaskContainer();
// One of the activity and the intent must be non-null
assertThrows(IllegalArgumentException.class,
@@ -103,7 +103,7 @@ public class TaskFragmentContainerTest {
@Test
public void testFinish() {
- final TaskContainer taskContainer = new TaskContainer(TASK_ID);
+ final TaskContainer taskContainer = createTestTaskContainer();
final TaskFragmentContainer container = new TaskFragmentContainer(mActivity,
null /* pendingAppearedIntent */, taskContainer, mController);
doReturn(container).when(mController).getContainerWithActivity(mActivity);
@@ -136,7 +136,7 @@ public class TaskFragmentContainerTest {
@Test
public void testFinish_notFinishActivityThatIsReparenting() {
- final TaskContainer taskContainer = new TaskContainer(TASK_ID);
+ final TaskContainer taskContainer = createTestTaskContainer();
final TaskFragmentContainer container0 = new TaskFragmentContainer(mActivity,
null /* pendingAppearedIntent */, taskContainer, mController);
final TaskFragmentInfo info = createMockTaskFragmentInfo(container0, mActivity);
@@ -157,7 +157,7 @@ public class TaskFragmentContainerTest {
@Test
public void testSetInfo() {
- final TaskContainer taskContainer = new TaskContainer(TASK_ID);
+ final TaskContainer taskContainer = createTestTaskContainer();
// Pending activity should be cleared when it has appeared on server side.
final TaskFragmentContainer pendingActivityContainer = new TaskFragmentContainer(mActivity,
null /* pendingAppearedIntent */, taskContainer, mController);
@@ -185,7 +185,7 @@ public class TaskFragmentContainerTest {
@Test
public void testIsWaitingActivityAppear() {
- final TaskContainer taskContainer = new TaskContainer(TASK_ID);
+ final TaskContainer taskContainer = createTestTaskContainer();
final TaskFragmentContainer container = new TaskFragmentContainer(null /* activity */,
mIntent, taskContainer, mController);
@@ -207,7 +207,7 @@ public class TaskFragmentContainerTest {
@Test
public void testAppearEmptyTimeout() {
doNothing().when(mController).onTaskFragmentAppearEmptyTimeout(any(), any());
- final TaskContainer taskContainer = new TaskContainer(TASK_ID);
+ final TaskContainer taskContainer = createTestTaskContainer();
final TaskFragmentContainer container = new TaskFragmentContainer(null /* activity */,
mIntent, taskContainer, mController);
@@ -247,7 +247,7 @@ public class TaskFragmentContainerTest {
@Test
public void testCollectNonFinishingActivities() {
- final TaskContainer taskContainer = new TaskContainer(TASK_ID);
+ final TaskContainer taskContainer = createTestTaskContainer();
final TaskFragmentContainer container = new TaskFragmentContainer(null /* activity */,
mIntent, taskContainer, mController);
List<Activity> activities = container.collectNonFinishingActivities();
@@ -275,7 +275,7 @@ public class TaskFragmentContainerTest {
@Test
public void testAddPendingActivity() {
- final TaskContainer taskContainer = new TaskContainer(TASK_ID);
+ final TaskContainer taskContainer = createTestTaskContainer();
final TaskFragmentContainer container = new TaskFragmentContainer(null /* activity */,
mIntent, taskContainer, mController);
container.addPendingAppearedActivity(mActivity);
@@ -289,7 +289,7 @@ public class TaskFragmentContainerTest {
@Test
public void testIsAbove() {
- final TaskContainer taskContainer = new TaskContainer(TASK_ID);
+ final TaskContainer taskContainer = createTestTaskContainer();
final TaskFragmentContainer container0 = new TaskFragmentContainer(null /* activity */,
mIntent, taskContainer, mController);
final TaskFragmentContainer container1 = new TaskFragmentContainer(null /* activity */,
@@ -301,7 +301,7 @@ public class TaskFragmentContainerTest {
@Test
public void testGetBottomMostActivity() {
- final TaskContainer taskContainer = new TaskContainer(TASK_ID);
+ final TaskContainer taskContainer = createTestTaskContainer();
final TaskFragmentContainer container = new TaskFragmentContainer(null /* activity */,
mIntent, taskContainer, mController);
container.addPendingAppearedActivity(mActivity);
@@ -318,7 +318,7 @@ public class TaskFragmentContainerTest {
@Test
public void testOnActivityDestroyed() {
- final TaskContainer taskContainer = new TaskContainer(TASK_ID);
+ final TaskContainer taskContainer = createTestTaskContainer();
final TaskFragmentContainer container = new TaskFragmentContainer(null /* activity */,
mIntent, taskContainer, mController);
container.addPendingAppearedActivity(mActivity);
diff --git a/libs/WindowManager/Shell/res/values-ro/strings.xml b/libs/WindowManager/Shell/res/values-ro/strings.xml
index 3ec4f1b1264c..93fc93f29d50 100644
--- a/libs/WindowManager/Shell/res/values-ro/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ro/strings.xml
@@ -17,7 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="pip_phone_close" msgid="5783752637260411309">"Închideți"</string>
+ <string name="pip_phone_close" msgid="5783752637260411309">"ÃŽnchide"</string>
<string name="pip_phone_expand" msgid="2579292903468287504">"Extindeți"</string>
<string name="pip_phone_settings" msgid="5468987116750491918">"Setări"</string>
<string name="pip_phone_enter_split" msgid="7042877263880641911">"Accesați ecranul împărțit"</string>
@@ -30,7 +30,7 @@
<string name="pip_skip_to_prev" msgid="7172158111196394092">"Treceți la cel anterior"</string>
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Redimensionați"</string>
<string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Stocați"</string>
- <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Anulați stocarea"</string>
+ <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Anulează stocarea"</string>
<string name="dock_forced_resizable" msgid="1749750436092293116">"Este posibil ca aplicația să nu funcționeze cu ecranul împărțit."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Aplicația nu acceptă ecranul împărțit."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Este posibil ca aplicația să nu funcționeze pe un ecran secundar."</string>
@@ -52,7 +52,7 @@
<string name="accessibility_action_stop_one_handed" msgid="1369940261782179442">"Părăsiți modul cu o mână"</string>
<string name="bubbles_settings_button_description" msgid="1301286017420516912">"Setări pentru baloanele <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="bubble_overflow_button_content_description" msgid="8160974472718594382">"Suplimentar"</string>
- <string name="bubble_accessibility_action_add_back" msgid="1830101076853540953">"Adăugați înapoi în stivă"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="1830101076853540953">"Adaugă înapoi în stivă"</string>
<string name="bubble_content_description_single" msgid="8495748092720065813">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> de la <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
<string name="bubble_content_description_stack" msgid="8071515017164630429">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> de la <xliff:g id="APP_NAME">%2$s</xliff:g> și încă <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>"</string>
<string name="bubble_accessibility_action_move_top_left" msgid="2644118920500782758">"Mutați în stânga sus"</string>
@@ -60,7 +60,7 @@
<string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"Mutați în stânga jos"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Mutați în dreapta jos"</string>
<string name="bubbles_app_settings" msgid="3617224938701566416">"Setări <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
- <string name="bubble_dismiss_text" msgid="8816558050659478158">"Închideți balonul"</string>
+ <string name="bubble_dismiss_text" msgid="8816558050659478158">"ÃŽnchide balonul"</string>
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Nu afișați conversația în balon"</string>
<string name="bubbles_user_education_title" msgid="2112319053732691899">"Chat cu baloane"</string>
<string name="bubbles_user_education_description" msgid="4215862563054175407">"Conversațiile noi apar ca pictograme flotante sau baloane. Atingeți pentru a deschide balonul. Trageți pentru a-l muta."</string>
@@ -83,5 +83,5 @@
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Extindeți pentru mai multe informații"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Maximizați"</string>
<string name="minimize_button_text" msgid="271592547935841753">"Minimizează"</string>
- <string name="close_button_text" msgid="2913281996024033299">"Închideți"</string>
+ <string name="close_button_text" msgid="2913281996024033299">"ÃŽnchide"</string>
</resources>
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/RootTaskDisplayAreaOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/RootTaskDisplayAreaOrganizer.java
index 9230c22c5d95..ca977ed2cb94 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/RootTaskDisplayAreaOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/RootTaskDisplayAreaOrganizer.java
@@ -179,6 +179,14 @@ public class RootTaskDisplayAreaOrganizer extends DisplayAreaOrganizer {
}
/**
+ * Returns the {@link DisplayAreaInfo} of the {@link DisplayAreaInfo#displayId}.
+ */
+ @Nullable
+ public DisplayAreaInfo getDisplayAreaInfo(int displayId) {
+ return mDisplayAreasInfo.get(displayId);
+ }
+
+ /**
* Applies the {@link DisplayAreaInfo} to the {@link DisplayAreaContext} specified by
* {@link DisplayAreaInfo#displayId}.
*/
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 27d3e35fa07a..35e88e9abb3c 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
@@ -27,7 +27,6 @@ import com.android.internal.jank.InteractionJankMonitor;
import com.android.internal.logging.UiEventLogger;
import com.android.internal.statusbar.IStatusBarService;
import com.android.launcher3.icons.IconProvider;
-import com.android.wm.shell.RootDisplayAreaOrganizer;
import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.TaskViewTransitions;
@@ -599,13 +598,13 @@ public abstract class WMShellModule {
static Optional<DesktopModeController> provideDesktopModeController(
Context context, ShellInit shellInit,
ShellTaskOrganizer shellTaskOrganizer,
- RootDisplayAreaOrganizer rootDisplayAreaOrganizer,
+ RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer,
@ShellMainThread Handler mainHandler,
Transitions transitions
) {
if (DesktopMode.IS_SUPPORTED) {
return Optional.of(new DesktopModeController(context, shellInit, shellTaskOrganizer,
- rootDisplayAreaOrganizer, mainHandler, transitions));
+ rootTaskDisplayAreaOrganizer, mainHandler, transitions));
} else {
return Optional.empty();
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeController.java
index c07ce1065302..6e44d58cffae 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeController.java
@@ -22,19 +22,21 @@ import static android.view.WindowManager.TRANSIT_CHANGE;
import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE;
+import android.app.WindowConfiguration;
import android.content.Context;
import android.database.ContentObserver;
import android.net.Uri;
import android.os.Handler;
import android.os.UserHandle;
import android.provider.Settings;
+import android.window.DisplayAreaInfo;
import android.window.WindowContainerTransaction;
import androidx.annotation.Nullable;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.protolog.common.ProtoLog;
-import com.android.wm.shell.RootDisplayAreaOrganizer;
+import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.annotations.ShellMainThread;
import com.android.wm.shell.sysui.ShellInit;
@@ -47,18 +49,18 @@ public class DesktopModeController {
private final Context mContext;
private final ShellTaskOrganizer mShellTaskOrganizer;
- private final RootDisplayAreaOrganizer mRootDisplayAreaOrganizer;
+ private final RootTaskDisplayAreaOrganizer mRootTaskDisplayAreaOrganizer;
private final SettingsObserver mSettingsObserver;
private final Transitions mTransitions;
public DesktopModeController(Context context, ShellInit shellInit,
ShellTaskOrganizer shellTaskOrganizer,
- RootDisplayAreaOrganizer rootDisplayAreaOrganizer,
+ RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer,
@ShellMainThread Handler mainHandler,
Transitions transitions) {
mContext = context;
mShellTaskOrganizer = shellTaskOrganizer;
- mRootDisplayAreaOrganizer = rootDisplayAreaOrganizer;
+ mRootTaskDisplayAreaOrganizer = rootTaskDisplayAreaOrganizer;
mSettingsObserver = new SettingsObserver(mContext, mainHandler);
mTransitions = transitions;
shellInit.addInitCallback(this::onInit, this);
@@ -92,15 +94,32 @@ public class DesktopModeController {
wct.merge(mShellTaskOrganizer.prepareClearBoundsForStandardTasks(displayId),
true /* transfer */);
}
- wct.merge(mRootDisplayAreaOrganizer.prepareWindowingModeChange(displayId,
- targetWindowingMode), true /* transfer */);
+ prepareWindowingModeChange(wct, displayId, targetWindowingMode);
if (Transitions.ENABLE_SHELL_TRANSITIONS) {
mTransitions.startTransition(TRANSIT_CHANGE, wct, null);
} else {
- mRootDisplayAreaOrganizer.applyTransaction(wct);
+ mRootTaskDisplayAreaOrganizer.applyTransaction(wct);
}
}
+ private void prepareWindowingModeChange(WindowContainerTransaction wct,
+ int displayId, @WindowConfiguration.WindowingMode int windowingMode) {
+ DisplayAreaInfo displayAreaInfo = mRootTaskDisplayAreaOrganizer
+ .getDisplayAreaInfo(displayId);
+ if (displayAreaInfo == null) {
+ ProtoLog.e(WM_SHELL_DESKTOP_MODE,
+ "unable to update windowing mode for display %d display not found", displayId);
+ return;
+ }
+
+ ProtoLog.d(WM_SHELL_DESKTOP_MODE,
+ "setWindowingMode: displayId=%d current wmMode=%d new wmMode=%d", displayId,
+ displayAreaInfo.configuration.windowConfiguration.getWindowingMode(),
+ windowingMode);
+
+ wct.setWindowingMode(displayAreaInfo.token, windowingMode);
+ }
+
/**
* A {@link ContentObserver} for listening to changes to {@link Settings.System#DESKTOP_MODE}
*/
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java
index 435d8eaa563e..62bf5172e106 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java
@@ -17,6 +17,8 @@
package com.android.wm.shell.draganddrop;
import static android.app.ActivityTaskManager.INVALID_TASK_ID;
+import static android.app.ComponentOptions.KEY_PENDING_INTENT_BACKGROUND_ACTIVITY_ALLOWED;
+import static android.app.ComponentOptions.KEY_PENDING_INTENT_BACKGROUND_ACTIVITY_ALLOWED_BY_PERMISSION;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
@@ -263,6 +265,9 @@ public class DragAndDropPolicy {
mStarter.startShortcut(packageName, id, position, opts, user);
} else {
final PendingIntent launchIntent = intent.getParcelableExtra(EXTRA_PENDING_INTENT);
+ // Put BAL flags to avoid activity start aborted.
+ opts.putBoolean(KEY_PENDING_INTENT_BACKGROUND_ACTIVITY_ALLOWED, true);
+ opts.putBoolean(KEY_PENDING_INTENT_BACKGROUND_ACTIVITY_ALLOWED_BY_PERMISSION, true);
mStarter.startIntent(launchIntent, null /* fillIntent */, position, opts);
}
}
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 ac95d4bc63d1..f58719b225a4 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
@@ -191,15 +191,19 @@ public class FreeformTaskListener<T extends AutoCloseable>
*
* @param change the change of this task transition that needs to have the task layer as the
* leash
- * @return {@code true} if it adopts the window decoration; {@code false} otherwise
+ * @return {@code true} if it creates the window decoration; {@code false} otherwise
*/
- void createWindowDecoration(
+ boolean createWindowDecoration(
TransitionInfo.Change change,
SurfaceControl.Transaction startT,
SurfaceControl.Transaction finishT) {
final State<T> state = createOrUpdateTaskState(change.getTaskInfo(), change.getLeash());
+ if (state.mWindowDecoration != null) {
+ return false;
+ }
state.mWindowDecoration = mWindowDecorationViewModel.createWindowDecoration(
state.mTaskInfo, state.mLeash, startT, finishT);
+ return true;
}
/**
@@ -222,6 +226,9 @@ public class FreeformTaskListener<T extends AutoCloseable>
windowDecor =
mWindowDecorOfVanishedTasks.removeReturnOld(taskInfo.taskId);
}
+ if (windowDecor == null) {
+ return null;
+ }
mWindowDecorationViewModel.setupWindowDecorationForTransition(
taskInfo, startT, finishT, windowDecor);
return windowDecor;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionObserver.java b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionObserver.java
index a780ec102ea9..17d60671e964 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionObserver.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionObserver.java
@@ -26,6 +26,7 @@ import android.util.Log;
import android.view.SurfaceControl;
import android.view.WindowManager;
import android.window.TransitionInfo;
+import android.window.WindowContainerToken;
import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
@@ -80,6 +81,7 @@ public class FreeformTaskTransitionObserver implements Transitions.TransitionObs
@NonNull SurfaceControl.Transaction startT,
@NonNull SurfaceControl.Transaction finishT) {
final ArrayList<AutoCloseable> windowDecors = new ArrayList<>();
+ final ArrayList<WindowContainerToken> taskParents = new ArrayList<>();
for (TransitionInfo.Change change : info.getChanges()) {
if ((change.getFlags() & TransitionInfo.FLAG_IS_WALLPAPER) != 0) {
continue;
@@ -89,9 +91,22 @@ public class FreeformTaskTransitionObserver implements Transitions.TransitionObs
if (taskInfo == null || taskInfo.taskId == -1) {
continue;
}
+ // Filter out non-leaf tasks. Freeform/fullscreen don't nest tasks, but split-screen
+ // does, so this prevents adding duplicate captions in that scenario.
+ if (change.getParent() != null
+ && info.getChange(change.getParent()).getTaskInfo() != null) {
+ // This logic relies on 2 assumptions: 1 is that child tasks will be visited before
+ // parents (due to how z-order works). 2 is that no non-tasks are interleaved
+ // between tasks (hierarchically).
+ taskParents.add(change.getContainer());
+ }
+ if (taskParents.contains(change.getContainer())) {
+ continue;
+ }
switch (change.getMode()) {
case WindowManager.TRANSIT_OPEN:
+ case WindowManager.TRANSIT_TO_FRONT:
onOpenTransitionReady(change, startT, finishT);
break;
case WindowManager.TRANSIT_CLOSE: {
@@ -154,20 +169,28 @@ public class FreeformTaskTransitionObserver implements Transitions.TransitionObs
boolean adopted = false;
final ActivityManager.RunningTaskInfo taskInfo = change.getTaskInfo();
- if (type == Transitions.TRANSIT_MAXIMIZE
- && taskInfo.getWindowingMode() == WINDOWING_MODE_FULLSCREEN) {
+ if (taskInfo.getWindowingMode() == WINDOWING_MODE_FULLSCREEN) {
windowDecor = mFreeformTaskListener.giveWindowDecoration(
change.getTaskInfo(), startT, finishT);
- adopted = mFullscreenTaskListener.adoptWindowDecoration(
- change, startT, finishT, windowDecor);
+ if (windowDecor != null) {
+ adopted = mFullscreenTaskListener.adoptWindowDecoration(
+ change, startT, finishT, windowDecor);
+ } else {
+ // will return false if it already has the window decor.
+ adopted = mFullscreenTaskListener.createWindowDecoration(change, startT, finishT);
+ }
}
- if (type == Transitions.TRANSIT_RESTORE_FROM_MAXIMIZE
- && taskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM) {
+ if (taskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM) {
windowDecor = mFullscreenTaskListener.giveWindowDecoration(
change.getTaskInfo(), startT, finishT);
- adopted = mFreeformTaskListener.adoptWindowDecoration(
- change, startT, finishT, windowDecor);
+ if (windowDecor != null) {
+ adopted = mFreeformTaskListener.adoptWindowDecoration(
+ change, startT, finishT, windowDecor);
+ } else {
+ // will return false if it already has the window decor.
+ adopted = mFreeformTaskListener.createWindowDecoration(change, startT, finishT);
+ }
}
if (!adopted) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/fullscreen/FullscreenTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/fullscreen/FullscreenTaskListener.java
index 7d1259a732c9..76e296bb8c61 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/fullscreen/FullscreenTaskListener.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/fullscreen/FullscreenTaskListener.java
@@ -173,16 +173,23 @@ public class FullscreenTaskListener<T extends AutoCloseable>
*
* @param change the change of this task transition that needs to have the task layer as the
* leash
+ * @return {@code true} if a decoration was actually created.
*/
- public void createWindowDecoration(TransitionInfo.Change change,
+ public boolean createWindowDecoration(TransitionInfo.Change change,
SurfaceControl.Transaction startT, SurfaceControl.Transaction finishT) {
final State<T> state = createOrUpdateTaskState(change.getTaskInfo(), change.getLeash());
- if (!mWindowDecorViewModelOptional.isPresent()) return;
+ if (!mWindowDecorViewModelOptional.isPresent()) return false;
+ if (state.mWindowDecoration != null) {
+ // Already has a decoration.
+ return false;
+ }
T newWindowDecor = mWindowDecorViewModelOptional.get().createWindowDecoration(
state.mTaskInfo, state.mLeash, startT, finishT);
if (newWindowDecor != null) {
state.mWindowDecoration = newWindowDecor;
+ return true;
}
+ return false;
}
/**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
index f170e774739f..1a52d8c395ba 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
@@ -324,6 +324,19 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
return mPipTransitionController;
}
+ /**
+ * Returns true if the PiP window is currently being animated.
+ */
+ public boolean isAnimating() {
+ // TODO(b/183746978) move this to PipAnimationController, and inject that in PipController
+ PipAnimationController.PipTransitionAnimator animator =
+ mPipAnimationController.getCurrentAnimator();
+ if (animator != null && animator.isRunning()) {
+ return true;
+ }
+ return false;
+ }
+
public Rect getCurrentOrAnimatingBounds() {
PipAnimationController.PipTransitionAnimator animator =
mPipAnimationController.getCurrentAnimator();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipKeepClearAlgorithm.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipKeepClearAlgorithm.java
index 6dd02e46d657..84071e08d472 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipKeepClearAlgorithm.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipKeepClearAlgorithm.java
@@ -54,13 +54,8 @@ public class PhonePipKeepClearAlgorithm implements PipKeepClearAlgorithm {
? pipBoundsAlgorithm.getEntryDestinationBoundsIgnoringKeepClearAreas()
: pipBoundsState.getBounds();
float snapFraction = pipBoundsAlgorithm.getSnapFraction(startingBounds);
- int verticalGravity;
+ int verticalGravity = Gravity.BOTTOM;
int horizontalGravity;
- if (snapFraction < 1.5f || snapFraction >= 3.5f) {
- verticalGravity = Gravity.NO_GRAVITY;
- } else {
- verticalGravity = Gravity.BOTTOM;
- }
if (snapFraction >= 0.5f && snapFraction < 2.5f) {
horizontalGravity = Gravity.RIGHT;
} else {
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 3d879b685706..bc8191d2af46 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
@@ -149,7 +149,42 @@ public class PipController implements PipTransitionController.PipTransitionCallb
private final Rect mTmpInsetBounds = new Rect();
private final int mEnterAnimationDuration;
- private final Runnable mMovePipInResponseToKeepClearAreasChangeCallback;
+ private final Runnable mMovePipInResponseToKeepClearAreasChangeCallback =
+ this::onKeepClearAreasChangedCallback;
+
+ private void onKeepClearAreasChangedCallback() {
+ if (!mEnablePipKeepClearAlgorithm) {
+ // early bail out if the keep clear areas feature is disabled
+ return;
+ }
+ // if there is another animation ongoing, wait for it to finish and try again
+ if (mPipTaskOrganizer.isAnimating()) {
+ mMainExecutor.removeCallbacks(
+ mMovePipInResponseToKeepClearAreasChangeCallback);
+ mMainExecutor.executeDelayed(
+ mMovePipInResponseToKeepClearAreasChangeCallback,
+ PIP_KEEP_CLEAR_AREAS_DELAY);
+ return;
+ }
+ updatePipPositionForKeepClearAreas();
+ }
+
+ private void updatePipPositionForKeepClearAreas() {
+ if (!mEnablePipKeepClearAlgorithm) {
+ // early bail out if the keep clear areas feature is disabled
+ return;
+ }
+ // only move if already in pip, other transitions account for keep clear areas
+ if (mPipTransitionState.hasEnteredPip()) {
+ Rect destBounds = mPipKeepClearAlgorithm.adjust(mPipBoundsState,
+ mPipBoundsAlgorithm);
+ // only move if the bounds are actually different
+ if (destBounds != mPipBoundsState.getBounds()) {
+ mPipTaskOrganizer.scheduleAnimateResizePip(destBounds,
+ mEnterAnimationDuration, null);
+ }
+ }
+ }
private boolean mIsInFixedRotation;
private PipAnimationListener mPinnedStackAnimationRecentsCallback;
@@ -302,6 +337,9 @@ public class PipController implements PipTransitionController.PipTransitionCallb
public void onImeVisibilityChanged(boolean imeVisible, int imeHeight) {
mPipBoundsState.setImeVisibility(imeVisible, imeHeight);
mTouchHandler.onImeVisibilityChanged(imeVisible, imeHeight);
+ if (imeVisible) {
+ updatePipPositionForKeepClearAreas();
+ }
}
@Override
@@ -414,15 +452,6 @@ public class PipController implements PipTransitionController.PipTransitionCallb
mEnterAnimationDuration = mContext.getResources()
.getInteger(R.integer.config_pipEnterAnimationDuration);
- mMovePipInResponseToKeepClearAreasChangeCallback = () -> {
- // only move if already in pip, other transitions account for keep clear areas
- if (mPipTransitionState.hasEnteredPip()) {
- Rect destBounds = mPipKeepClearAlgorithm.adjust(mPipBoundsState,
- mPipBoundsAlgorithm);
- mPipTaskOrganizer.scheduleAnimateResizePip(destBounds,
- mEnterAnimationDuration, null);
- }
- };
mPipParamsChangedForwarder = pipParamsChangedForwarder;
mDisplayInsetsController = displayInsetsController;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
index 84d9217e6fb3..1f3f31e025a0 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
@@ -34,6 +34,7 @@ import android.content.res.Resources;
import android.graphics.Point;
import android.graphics.PointF;
import android.graphics.Rect;
+import android.os.SystemProperties;
import android.provider.DeviceConfig;
import android.util.Size;
import android.view.DisplayCutout;
@@ -70,6 +71,9 @@ public class PipTouchHandler {
private static final String TAG = "PipTouchHandler";
private static final float DEFAULT_STASH_VELOCITY_THRESHOLD = 18000.f;
+ private static final boolean ENABLE_PIP_KEEP_CLEAR_ALGORITHM =
+ SystemProperties.getBoolean("persist.wm.debug.enable_pip_keep_clear_algorithm", false);
+
// Allow PIP to resize to a slightly bigger state upon touch
private boolean mEnableResize;
private final Context mContext;
@@ -426,6 +430,9 @@ public class PipTouchHandler {
if (mTouchState.isUserInteracting()) {
// Defer the update of the current movement bounds until after the user finishes
// touching the screen
+ } else if (ENABLE_PIP_KEEP_CLEAR_ALGORITHM) {
+ // Ignore moving PiP if keep clear algorithm is enabled, since IME and shelf height
+ // now are accounted for in the keep clear algorithm calculations
} else {
final boolean isExpanded = mMenuState == MENU_STATE_FULL && willResizeMenu();
final Rect toMovementBounds = new Rect();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
index 025e5592e367..991f136c0055 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
@@ -133,6 +133,20 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
@Retention(RetentionPolicy.SOURCE)
@interface ExitReason{}
+ public static final int ENTER_REASON_UNKNOWN = 0;
+ public static final int ENTER_REASON_MULTI_INSTANCE = 1;
+ public static final int ENTER_REASON_DRAG = 2;
+ public static final int ENTER_REASON_LAUNCHER = 3;
+ /** Acts as a mapping to the actual EnterReasons as defined in the logging proto */
+ @IntDef(value = {
+ ENTER_REASON_MULTI_INSTANCE,
+ ENTER_REASON_DRAG,
+ ENTER_REASON_LAUNCHER,
+ ENTER_REASON_UNKNOWN
+ })
+ public @interface SplitEnterReason {
+ }
+
private final ShellCommandHandler mShellCommandHandler;
private final ShellController mShellController;
private final ShellTaskOrganizer mTaskOrganizer;
@@ -154,7 +168,8 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
private StageCoordinator mStageCoordinator;
// Only used for the legacy recents animation from splitscreen to allow the tasks to be animated
// outside the bounds of the roots by being reparented into a higher level fullscreen container
- private SurfaceControl mSplitTasksContainerLayer;
+ private SurfaceControl mGoingToRecentsTasksLayer;
+ private SurfaceControl mStartingSplitTasksLayer;
public SplitScreenController(Context context,
ShellInit shellInit,
@@ -393,7 +408,7 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
*/
public void startShortcut(String packageName, String shortcutId, @SplitPosition int position,
@Nullable Bundle options, UserHandle user, @NonNull InstanceId instanceId) {
- mStageCoordinator.getLogger().enterRequested(instanceId);
+ mStageCoordinator.getLogger().enterRequested(instanceId, ENTER_REASON_LAUNCHER);
startShortcut(packageName, shortcutId, position, options, user);
}
@@ -441,7 +456,7 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
*/
public void startIntent(PendingIntent intent, @Nullable Intent fillInIntent,
@SplitPosition int position, @Nullable Bundle options, @NonNull InstanceId instanceId) {
- mStageCoordinator.getLogger().enterRequested(instanceId);
+ mStageCoordinator.getLogger().enterRequested(instanceId, ENTER_REASON_LAUNCHER);
startIntent(intent, fillInIntent, position, options);
}
@@ -509,19 +524,53 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
}
RemoteAnimationTarget[] onGoingToRecentsLegacy(RemoteAnimationTarget[] apps) {
+ if (ENABLE_SHELL_TRANSITIONS) return null;
+
if (isSplitScreenVisible()) {
// Evict child tasks except the top visible one under split root to ensure it could be
// launched as full screen when switching to it on recents.
final WindowContainerTransaction wct = new WindowContainerTransaction();
mStageCoordinator.prepareEvictInvisibleChildTasks(wct);
mSyncQueue.queue(wct);
+ } else {
+ return null;
}
- return reparentSplitTasksForAnimation(apps, false /* enterSplitScreen */);
+
+ SurfaceControl.Transaction t = mTransactionPool.acquire();
+ if (mGoingToRecentsTasksLayer != null) {
+ t.remove(mGoingToRecentsTasksLayer);
+ }
+ mGoingToRecentsTasksLayer = reparentSplitTasksForAnimation(apps, t,
+ "SplitScreenController#onGoingToRecentsLegacy" /* callsite */);
+ t.apply();
+ mTransactionPool.release(t);
+
+ return new RemoteAnimationTarget[]{mStageCoordinator.getDividerBarLegacyTarget()};
}
RemoteAnimationTarget[] onStartingSplitLegacy(RemoteAnimationTarget[] apps) {
+ if (ENABLE_SHELL_TRANSITIONS) return null;
+
+ int openingApps = 0;
+ for (int i = 0; i < apps.length; ++i) {
+ if (apps[i].mode == MODE_OPENING) openingApps++;
+ }
+ if (openingApps < 2) {
+ // Not having enough apps to enter split screen
+ return null;
+ }
+
+ SurfaceControl.Transaction t = mTransactionPool.acquire();
+ if (mStartingSplitTasksLayer != null) {
+ t.remove(mStartingSplitTasksLayer);
+ }
+ mStartingSplitTasksLayer = reparentSplitTasksForAnimation(apps, t,
+ "SplitScreenController#onStartingSplitLegacy" /* callsite */);
+ t.apply();
+ mTransactionPool.release(t);
+
try {
- return reparentSplitTasksForAnimation(apps, true /* enterSplitScreen */);
+ return new RemoteAnimationTarget[]{mStageCoordinator.getDividerBarLegacyTarget()};
} finally {
for (RemoteAnimationTarget appTarget : apps) {
if (appTarget.leash != null) {
@@ -531,45 +580,23 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
}
}
- private RemoteAnimationTarget[] reparentSplitTasksForAnimation(RemoteAnimationTarget[] apps,
- boolean enterSplitScreen) {
- if (ENABLE_SHELL_TRANSITIONS) return null;
-
- if (enterSplitScreen) {
- int openingApps = 0;
- for (int i = 0; i < apps.length; ++i) {
- if (apps[i].mode == MODE_OPENING) openingApps++;
- }
- if (openingApps < 2) {
- // Not having enough apps to enter split screen
- return null;
- }
- } else if (!isSplitScreenVisible()) {
- return null;
- }
-
- final SurfaceControl.Transaction transaction = mTransactionPool.acquire();
- if (mSplitTasksContainerLayer != null) {
- // Remove the previous layer before recreating
- transaction.remove(mSplitTasksContainerLayer);
- }
+ private SurfaceControl reparentSplitTasksForAnimation(RemoteAnimationTarget[] apps,
+ SurfaceControl.Transaction t, String callsite) {
final SurfaceControl.Builder builder = new SurfaceControl.Builder(new SurfaceSession())
.setContainerLayer()
.setName("RecentsAnimationSplitTasks")
.setHidden(false)
- .setCallsite("SplitScreenController#onGoingtoRecentsLegacy");
+ .setCallsite(callsite);
mRootTDAOrganizer.attachToDisplayArea(DEFAULT_DISPLAY, builder);
- mSplitTasksContainerLayer = builder.build();
+ final SurfaceControl splitTasksLayer = builder.build();
for (int i = 0; i < apps.length; ++i) {
final RemoteAnimationTarget appTarget = apps[i];
- transaction.reparent(appTarget.leash, mSplitTasksContainerLayer);
- transaction.setPosition(appTarget.leash, appTarget.screenSpaceBounds.left,
+ t.reparent(appTarget.leash, splitTasksLayer);
+ t.setPosition(appTarget.leash, appTarget.screenSpaceBounds.left,
appTarget.screenSpaceBounds.top);
}
- transaction.apply();
- mTransactionPool.release(transaction);
- return new RemoteAnimationTarget[]{mStageCoordinator.getDividerBarLegacyTarget()};
+ return splitTasksLayer;
}
/**
* Sets drag info to be logged when splitscreen is entered.
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitscreenEventLogger.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitscreenEventLogger.java
index 626ccb1d2890..033d743d8042 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitscreenEventLogger.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitscreenEventLogger.java
@@ -17,6 +17,8 @@
package com.android.wm.shell.splitscreen;
import static com.android.internal.util.FrameworkStatsLog.SPLITSCREEN_UICHANGED__ENTER_REASON__LAUNCHER;
+import static com.android.internal.util.FrameworkStatsLog.SPLITSCREEN_UICHANGED__ENTER_REASON__MULTI_INSTANCE;
+import static com.android.internal.util.FrameworkStatsLog.SPLITSCREEN_UICHANGED__ENTER_REASON__UNKNOWN_ENTER;
import static com.android.internal.util.FrameworkStatsLog.SPLITSCREEN_UICHANGED__EXIT_REASON__APP_DOES_NOT_SUPPORT_MULTIWINDOW;
import static com.android.internal.util.FrameworkStatsLog.SPLITSCREEN_UICHANGED__EXIT_REASON__APP_FINISHED;
import static com.android.internal.util.FrameworkStatsLog.SPLITSCREEN_UICHANGED__EXIT_REASON__DEVICE_FOLDED;
@@ -28,6 +30,10 @@ import static com.android.internal.util.FrameworkStatsLog.SPLITSCREEN_UICHANGED_
import static com.android.internal.util.FrameworkStatsLog.SPLITSCREEN_UICHANGED__EXIT_REASON__UNKNOWN_EXIT;
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.splitscreen.SplitScreenController.ENTER_REASON_DRAG;
+import static com.android.wm.shell.splitscreen.SplitScreenController.ENTER_REASON_LAUNCHER;
+import static com.android.wm.shell.splitscreen.SplitScreenController.ENTER_REASON_MULTI_INSTANCE;
+import static com.android.wm.shell.splitscreen.SplitScreenController.ENTER_REASON_UNKNOWN;
import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_APP_DOES_NOT_SUPPORT_MULTIWINDOW;
import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_APP_FINISHED;
import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_DEVICE_FOLDED;
@@ -38,6 +44,7 @@ import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON
import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_SCREEN_LOCKED_SHOW_ON_TOP;
import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_UNKNOWN;
+import android.annotation.Nullable;
import android.util.Slog;
import com.android.internal.logging.InstanceId;
@@ -59,7 +66,7 @@ public class SplitscreenEventLogger {
// Drag info
private @SplitPosition int mDragEnterPosition;
- private InstanceId mEnterSessionId;
+ private @Nullable InstanceId mEnterSessionId;
// For deduping async events
private int mLastMainStagePosition = -1;
@@ -67,6 +74,7 @@ public class SplitscreenEventLogger {
private int mLastSideStagePosition = -1;
private int mLastSideStageUid = -1;
private float mLastSplitRatio = -1f;
+ private @SplitScreenController.SplitEnterReason int mEnterReason = ENTER_REASON_UNKNOWN;
public SplitscreenEventLogger() {
mIdSequence = new InstanceIdSequence(Integer.MAX_VALUE);
@@ -84,15 +92,26 @@ public class SplitscreenEventLogger {
*/
public void enterRequestedByDrag(@SplitPosition int position, InstanceId enterSessionId) {
mDragEnterPosition = position;
- enterRequested(enterSessionId);
+ enterRequested(enterSessionId, ENTER_REASON_DRAG);
}
/**
* May be called before logEnter() to indicate that the session was started from launcher.
* This specifically is for all the scenarios where split started without a drag interaction
*/
- public void enterRequested(InstanceId enterSessionId) {
+ public void enterRequested(@Nullable InstanceId enterSessionId,
+ @SplitScreenController.SplitEnterReason int enterReason) {
mEnterSessionId = enterSessionId;
+ mEnterReason = enterReason;
+ }
+
+ /**
+ * @return if an enterSessionId has been set via either
+ * {@link #enterRequested(InstanceId, int)} or
+ * {@link #enterRequestedByDrag(int, InstanceId)}
+ */
+ public boolean hasValidEnterSessionId() {
+ return mEnterSessionId != null;
}
/**
@@ -103,9 +122,7 @@ public class SplitscreenEventLogger {
@SplitPosition int sideStagePosition, int sideStageUid,
boolean isLandscape) {
mLoggerSessionId = mIdSequence.newInstanceId();
- int enterReason = mDragEnterPosition != SPLIT_POSITION_UNDEFINED
- ? getDragEnterReasonFromSplitPosition(mDragEnterPosition, isLandscape)
- : SPLITSCREEN_UICHANGED__ENTER_REASON__LAUNCHER;
+ int enterReason = getLoggerEnterReason(isLandscape);
updateMainStageState(getMainStagePositionFromSplitPosition(mainStagePosition, isLandscape),
mainStageUid);
updateSideStageState(getSideStagePositionFromSplitPosition(sideStagePosition, isLandscape),
@@ -124,6 +141,20 @@ public class SplitscreenEventLogger {
mLoggerSessionId.getId());
}
+ private int getLoggerEnterReason(boolean isLandscape) {
+ switch (mEnterReason) {
+ case ENTER_REASON_MULTI_INSTANCE:
+ return SPLITSCREEN_UICHANGED__ENTER_REASON__MULTI_INSTANCE;
+ case ENTER_REASON_LAUNCHER:
+ return SPLITSCREEN_UICHANGED__ENTER_REASON__LAUNCHER;
+ case ENTER_REASON_DRAG:
+ return getDragEnterReasonFromSplitPosition(mDragEnterPosition, isLandscape);
+ case ENTER_REASON_UNKNOWN:
+ default:
+ return SPLITSCREEN_UICHANGED__ENTER_REASON__UNKNOWN_ENTER;
+ }
+ }
+
/**
* Returns the framework logging constant given a splitscreen exit reason.
*/
@@ -189,6 +220,7 @@ public class SplitscreenEventLogger {
mLastMainStageUid = -1;
mLastSideStagePosition = -1;
mLastSideStageUid = -1;
+ mEnterReason = ENTER_REASON_UNKNOWN;
}
/**
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 db35b48eb898..c8dcf4acd746 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
@@ -18,8 +18,6 @@ package com.android.wm.shell.splitscreen;
import static android.app.ActivityOptions.KEY_LAUNCH_ROOT_TASK_TOKEN;
import static android.app.ActivityTaskManager.INVALID_TASK_ID;
-import static android.app.ComponentOptions.KEY_PENDING_INTENT_BACKGROUND_ACTIVITY_ALLOWED;
-import static android.app.ComponentOptions.KEY_PENDING_INTENT_BACKGROUND_ACTIVITY_ALLOWED_BY_PERMISSION;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
@@ -46,6 +44,8 @@ import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSIT
import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_MAIN;
import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_SIDE;
import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_UNDEFINED;
+import static com.android.wm.shell.splitscreen.SplitScreenController.ENTER_REASON_LAUNCHER;
+import static com.android.wm.shell.splitscreen.SplitScreenController.ENTER_REASON_MULTI_INSTANCE;
import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_APP_DOES_NOT_SUPPORT_MULTIWINDOW;
import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_APP_FINISHED;
import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_CHILD_TASK_ENTER_PIP;
@@ -671,7 +671,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
private void setEnterInstanceId(InstanceId instanceId) {
if (instanceId != null) {
- mLogger.enterRequested(instanceId);
+ mLogger.enterRequested(instanceId, ENTER_REASON_LAUNCHER);
}
}
@@ -1109,9 +1109,6 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
private void addActivityOptions(Bundle opts, StageTaskListener stage) {
opts.putParcelable(KEY_LAUNCH_ROOT_TASK_TOKEN, stage.mRootTaskInfo.token);
- // Put BAL flags to avoid activity start aborted.
- opts.putBoolean(KEY_PENDING_INTENT_BACKGROUND_ACTIVITY_ALLOWED, true);
- opts.putBoolean(KEY_PENDING_INTENT_BACKGROUND_ACTIVITY_ALLOWED_BY_PERMISSION, true);
}
void updateActivityOptions(Bundle opts, @SplitPosition int position) {
@@ -1477,6 +1474,9 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
updateRecentTasksSplitPair();
if (!mLogger.hasStartedSession()) {
+ if (!mLogger.hasValidEnterSessionId()) {
+ mLogger.enterRequested(null /*enterSessionId*/, ENTER_REASON_MULTI_INSTANCE);
+ }
mLogger.logEnter(mSplitLayout.getDividerPositionAsFraction(),
getMainStagePosition(), mMainStage.getTopChildTaskUid(),
getSideStagePosition(), mSideStage.getTopChildTaskUid(),
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeControllerTest.java
index 577942505b13..c628f3994d8d 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeControllerTest.java
@@ -32,13 +32,14 @@ import android.app.WindowConfiguration;
import android.os.Handler;
import android.os.IBinder;
import android.testing.AndroidTestingRunner;
+import android.window.DisplayAreaInfo;
import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction;
import android.window.WindowContainerTransaction.Change;
import androidx.test.filters.SmallTest;
-import com.android.wm.shell.RootDisplayAreaOrganizer;
+import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.ShellTestCase;
import com.android.wm.shell.common.ShellExecutor;
@@ -59,7 +60,7 @@ public class DesktopModeControllerTest extends ShellTestCase {
@Mock
private ShellTaskOrganizer mShellTaskOrganizer;
@Mock
- private RootDisplayAreaOrganizer mRootDisplayAreaOrganizer;
+ private RootTaskDisplayAreaOrganizer mRootTaskDisplayAreaOrganizer;
@Mock
private ShellExecutor mTestExecutor;
@Mock
@@ -75,7 +76,7 @@ public class DesktopModeControllerTest extends ShellTestCase {
mShellInit = Mockito.spy(new ShellInit(mTestExecutor));
mController = new DesktopModeController(mContext, mShellInit, mShellTaskOrganizer,
- mRootDisplayAreaOrganizer, mMockHandler, mMockTransitions);
+ mRootTaskDisplayAreaOrganizer, mMockHandler, mMockTransitions);
mShellInit.init();
}
@@ -94,19 +95,19 @@ public class DesktopModeControllerTest extends ShellTestCase {
when(mShellTaskOrganizer.prepareClearFreeformForStandardTasks(
mContext.getDisplayId())).thenReturn(taskWct);
- // Create a fake WCT to simulate setting display windowing mode to freeform
- WindowContainerTransaction displayWct = new WindowContainerTransaction();
+ // Create a fake DisplayAreaInfo to check if windowing mode change is set correctly
MockToken displayMockToken = new MockToken();
- displayWct.setWindowingMode(displayMockToken.token(), WINDOWING_MODE_FREEFORM);
- when(mRootDisplayAreaOrganizer.prepareWindowingModeChange(mContext.getDisplayId(),
- WINDOWING_MODE_FREEFORM)).thenReturn(displayWct);
+ DisplayAreaInfo displayAreaInfo = new DisplayAreaInfo(displayMockToken.mToken,
+ mContext.getDisplayId(), 0);
+ when(mRootTaskDisplayAreaOrganizer.getDisplayAreaInfo(mContext.getDisplayId()))
+ .thenReturn(displayAreaInfo);
// The test
mController.updateDesktopModeActive(true);
ArgumentCaptor<WindowContainerTransaction> arg = ArgumentCaptor.forClass(
WindowContainerTransaction.class);
- verify(mRootDisplayAreaOrganizer).applyTransaction(arg.capture());
+ verify(mRootTaskDisplayAreaOrganizer).applyTransaction(arg.capture());
// WCT should have 2 changes - clear task wm mode and set display wm mode
WindowContainerTransaction wct = arg.getValue();
@@ -118,7 +119,7 @@ public class DesktopModeControllerTest extends ShellTestCase {
assertThat(taskWmModeChange.getWindowingMode()).isEqualTo(WINDOWING_MODE_UNDEFINED);
// Verify executed WCT has a change for setting display windowing mode to freeform
- Change displayWmModeChange = wct.getChanges().get(displayMockToken.binder());
+ Change displayWmModeChange = wct.getChanges().get(displayAreaInfo.token.asBinder());
assertThat(displayWmModeChange).isNotNull();
assertThat(displayWmModeChange.getWindowingMode()).isEqualTo(WINDOWING_MODE_FREEFORM);
}
@@ -139,19 +140,19 @@ public class DesktopModeControllerTest extends ShellTestCase {
when(mShellTaskOrganizer.prepareClearBoundsForStandardTasks(
mContext.getDisplayId())).thenReturn(taskBoundsWct);
- // Create a fake WCT to simulate setting display windowing mode to fullscreen
- WindowContainerTransaction displayWct = new WindowContainerTransaction();
+ // Create a fake DisplayAreaInfo to check if windowing mode change is set correctly
MockToken displayMockToken = new MockToken();
- displayWct.setWindowingMode(displayMockToken.token(), WINDOWING_MODE_FULLSCREEN);
- when(mRootDisplayAreaOrganizer.prepareWindowingModeChange(mContext.getDisplayId(),
- WINDOWING_MODE_FULLSCREEN)).thenReturn(displayWct);
+ DisplayAreaInfo displayAreaInfo = new DisplayAreaInfo(displayMockToken.mToken,
+ mContext.getDisplayId(), 0);
+ when(mRootTaskDisplayAreaOrganizer.getDisplayAreaInfo(mContext.getDisplayId()))
+ .thenReturn(displayAreaInfo);
// The test
mController.updateDesktopModeActive(false);
ArgumentCaptor<WindowContainerTransaction> arg = ArgumentCaptor.forClass(
WindowContainerTransaction.class);
- verify(mRootDisplayAreaOrganizer).applyTransaction(arg.capture());
+ verify(mRootTaskDisplayAreaOrganizer).applyTransaction(arg.capture());
// WCT should have 3 changes - clear task wm mode and bounds and set display wm mode
WindowContainerTransaction wct = arg.getValue();
@@ -171,7 +172,7 @@ public class DesktopModeControllerTest extends ShellTestCase {
.isTrue();
// Verify executed WCT has a change for setting display windowing mode to fullscreen
- Change displayWmModeChange = wct.getChanges().get(displayMockToken.binder());
+ Change displayWmModeChange = wct.getChanges().get(displayAreaInfo.token.asBinder());
assertThat(displayWmModeChange).isNotNull();
assertThat(displayWmModeChange.getWindowingMode()).isEqualTo(WINDOWING_MODE_FULLSCREEN);
}