From e9d7d941eebbbdc7bdbf5ef1cd9a6969d07659bd Mon Sep 17 00:00:00 2001 From: Charles Chen Date: Thu, 29 Sep 2022 17:19:21 +0800 Subject: [PATCH] Consolidate mTaskBounds logic to mConfiguration After the horizontal layout feature, the split layout is not just determined by task bounds, but the whole task Configuration should be take account. This CL removes the mTaskBounds logic and consolidate to use TaskContainer#mConfiguration instead. This CL also introduces ActivityClient#getTaskConfiguration to obtain task config at TaskContainer initialization. Bug: 240219484 Test: atest WMJetpackUnitTests Change-Id: I5725ac92d841c53675c78b9e50e0d3fee3973f37 --- core/java/android/app/ActivityClient.java | 9 ++- .../app/IActivityClientController.aidl | 6 +- .../extensions/embedding/SplitController.java | 15 ---- .../extensions/embedding/SplitPresenter.java | 18 +---- .../extensions/embedding/TaskContainer.java | 75 ++++++++++++------- .../layout/WindowLayoutComponentImpl.java | 16 ++-- .../embedding/SplitControllerTest.java | 2 +- .../embedding/TaskContainerTest.java | 23 ------ .../server/wm/ActivityClientController.java | 11 +-- 9 files changed, 74 insertions(+), 101 deletions(-) diff --git a/core/java/android/app/ActivityClient.java b/core/java/android/app/ActivityClient.java index 4cf48abc2ed30..324b8e7a784f5 100644 --- a/core/java/android/app/ActivityClient.java +++ b/core/java/android/app/ActivityClient.java @@ -227,12 +227,13 @@ public class ActivityClient { } /** - * Returns the windowing mode of the task that hosts the activity, or {@code -1} if task is not - * found. + * Returns the {@link Configuration} of the task which hosts the Activity, or {@code null} if + * the task {@link Configuration} cannot be obtained. */ - public int getTaskWindowingMode(IBinder activityToken) { + @Nullable + public Configuration getTaskConfiguration(IBinder activityToken) { try { - return getActivityClientController().getTaskWindowingMode(activityToken); + return getActivityClientController().getTaskConfiguration(activityToken); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } diff --git a/core/java/android/app/IActivityClientController.aidl b/core/java/android/app/IActivityClientController.aidl index 62481ba8f2511..8b655b9bf315e 100644 --- a/core/java/android/app/IActivityClientController.aidl +++ b/core/java/android/app/IActivityClientController.aidl @@ -78,7 +78,11 @@ interface IActivityClientController { boolean willActivityBeVisible(in IBinder token); int getDisplayId(in IBinder activityToken); int getTaskForActivity(in IBinder token, in boolean onlyRoot); - int getTaskWindowingMode(in IBinder activityToken); + /** + * Returns the {@link Configuration} of the task which hosts the Activity, or {@code null} if + * the task {@link Configuration} cannot be obtained. + */ + Configuration getTaskConfiguration(in IBinder activityToken); IBinder getActivityTokenBelow(IBinder token); ComponentName getCallingActivity(in IBinder token); String getCallingPackage(in IBinder token); 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 c06548ad81a12..4df2d7d82f6ad 100644 --- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java +++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java @@ -41,7 +41,6 @@ import static androidx.window.extensions.embedding.SplitContainer.shouldFinishAs import static androidx.window.extensions.embedding.SplitContainer.shouldFinishAssociatedContainerWhenStacked; import static androidx.window.extensions.embedding.SplitPresenter.RESULT_EXPAND_FAILED_NO_TF_INFO; import static androidx.window.extensions.embedding.SplitPresenter.getActivityIntentMinDimensionsPair; -import static androidx.window.extensions.embedding.SplitPresenter.getNonEmbeddedActivityBounds; import static androidx.window.extensions.embedding.SplitPresenter.shouldShowSplit; import android.app.Activity; @@ -464,7 +463,6 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen // 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; @@ -614,12 +612,6 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen } } - @GuardedBy("mLock") - private void onTaskContainerInfoChanged(@NonNull TaskContainer taskContainer, - @NonNull Configuration config) { - taskContainer.setTaskBounds(config.windowConfiguration.getBounds()); - } - /** Returns whether the given {@link TaskContainer} may show in split. */ // Suppress GuardedBy warning because lint asks to mark this method as // @GuardedBy(mPresenter.mController.mLock), which is mLock itself @@ -1235,13 +1227,6 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen final TaskContainer taskContainer = mTaskContainers.get(taskId); final TaskFragmentContainer container = new TaskFragmentContainer(pendingAppearedActivity, pendingAppearedIntent, taskContainer, this); - if (!taskContainer.isTaskBoundsInitialized()) { - // Get the initial bounds before the TaskFragment has appeared. - final Rect taskBounds = getNonEmbeddedActivityBounds(activityInTask); - if (!taskContainer.setTaskBounds(taskBounds)) { - Log.w(TAG, "Can't find bounds from activity=" + activityInTask); - } - } return container; } diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java index f494b32cff143..5395fb2ef5ed1 100644 --- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java +++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java @@ -932,11 +932,7 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer { if (taskContainer != null) { return taskContainer.getTaskProperties(); } - // Use a copy of configuration because activity's configuration may be updated later, - // or we may get unexpected TaskContainer's configuration if Activity's configuration is - // updated. An example is Activity is going to be in split. - return new TaskProperties(activity.getDisplayId(), - new Configuration(activity.getResources().getConfiguration())); + return TaskProperties.getTaskPropertiesFromActivity(activity); } @NonNull @@ -950,16 +946,4 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer { // TODO(b/190433398): Supply correct insets. return new WindowMetrics(taskBounds, WindowInsets.CONSUMED); } - - /** Obtains the bounds from a non-embedded Activity. */ - @NonNull - static Rect getNonEmbeddedActivityBounds(@NonNull Activity activity) { - final WindowConfiguration windowConfiguration = - activity.getResources().getConfiguration().windowConfiguration; - if (!activity.isInMultiWindowMode()) { - // In fullscreen mode the max bounds should correspond to the task bounds. - return windowConfiguration.getMaxBounds(); - } - return windowConfiguration.getBounds(); - } } 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 231da0542e956..dba5a7a1cf3c6 100644 --- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java +++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java @@ -20,14 +20,17 @@ import static android.app.ActivityTaskManager.INVALID_TASK_ID; 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.app.WindowConfiguration.inMultiWindowMode; import android.app.Activity; +import android.app.ActivityClient; 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.util.Log; import android.window.TaskFragmentInfo; import android.window.TaskFragmentParentInfo; import android.window.WindowContainerTransaction; @@ -41,14 +44,11 @@ import java.util.Set; /** Represents TaskFragments and split pairs below a Task. */ class TaskContainer { + private static final String TAG = TaskContainer.class.getSimpleName(); /** 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(); - /** Active TaskFragments in this Task. */ @NonNull final List mContainers = new ArrayList<>(); @@ -86,10 +86,10 @@ class TaskContainer { 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(); + final TaskProperties taskProperties = TaskProperties + .getTaskPropertiesFromActivity(activityInTask); + mConfiguration = taskProperties.getConfiguration(); + mDisplayId = taskProperties.getDisplayId(); // Note that it is always called when there's a new Activity is started, which implies // the host task is visible. mIsVisible = true; @@ -107,25 +107,6 @@ class TaskContainer { return mIsVisible; } - @NonNull - Rect getTaskBounds() { - return mTaskBounds; - } - - /** Returns {@code true} if the bounds is changed. */ - boolean setTaskBounds(@NonNull Rect taskBounds) { - if (!taskBounds.isEmpty() && !mTaskBounds.equals(taskBounds)) { - mTaskBounds.set(taskBounds); - return true; - } - return false; - } - - /** Whether the Task bounds has been initialized. */ - boolean isTaskBoundsInitialized() { - return !mTaskBounds.isEmpty(); - } - @NonNull Configuration getConfiguration() { // Make a copy in case the config is updated unexpectedly. @@ -261,5 +242,45 @@ class TaskContainer { Configuration getConfiguration() { return mConfiguration; } + + /** + * Obtains the {@link TaskProperties} for the task that the provided {@link Activity} is + * associated with. + *

+ * Note that for most case, caller should use + * {@link SplitPresenter#getTaskProperties(Activity)} instead. This method is used before + * the {@code activity} goes into split. + *

+ * If the {@link Activity} is in fullscreen, override + * {@link WindowConfiguration#getBounds()} with {@link WindowConfiguration#getMaxBounds()} + * in case the {@link Activity} is letterboxed. Otherwise, get the Task + * {@link Configuration} from the server side or use {@link Activity}'s + * {@link Configuration} as a fallback if the Task {@link Configuration} cannot be obtained. + */ + @NonNull + static TaskProperties getTaskPropertiesFromActivity(@NonNull Activity activity) { + final int displayId = activity.getDisplayId(); + // Use a copy of configuration because activity's configuration may be updated later, + // or we may get unexpected TaskContainer's configuration if Activity's configuration is + // updated. An example is Activity is going to be in split. + final Configuration activityConfig = new Configuration( + activity.getResources().getConfiguration()); + final WindowConfiguration windowConfiguration = activityConfig.windowConfiguration; + final int windowingMode = windowConfiguration.getWindowingMode(); + if (!inMultiWindowMode(windowingMode)) { + // Use the max bounds in fullscreen in case the Activity is letterboxed. + windowConfiguration.setBounds(windowConfiguration.getMaxBounds()); + return new TaskProperties(displayId, activityConfig); + } + final Configuration taskConfig = ActivityClient.getInstance() + .getTaskConfiguration(activity.getActivityToken()); + if (taskConfig == null) { + Log.w(TAG, "Could not obtain task configuration for activity:" + activity); + // Still report activity config if task config cannot be obtained from the server + // side. + return new TaskProperties(displayId, activityConfig); + } + return new TaskProperties(displayId, taskConfig); + } } } 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 2192b5ca219c9..b70b320eee3c7 100644 --- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/layout/WindowLayoutComponentImpl.java +++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/layout/WindowLayoutComponentImpl.java @@ -35,7 +35,6 @@ import android.graphics.Rect; import android.os.Bundle; import android.os.IBinder; import android.util.ArrayMap; -import android.window.WindowContext; import android.window.WindowProvider; import androidx.annotation.NonNull; @@ -310,20 +309,21 @@ public class WindowLayoutComponentImpl implements WindowLayoutComponent { } final int windowingMode; if (context instanceof Activity) { - windowingMode = ActivityClient.getInstance().getTaskWindowingMode( + final Configuration taskConfig = ActivityClient.getInstance().getTaskConfiguration( context.getActivityToken()); + if (taskConfig == null) { + // If we cannot determine the task configuration for any reason, it is likely that + // we won't be able to determine its position correctly as well. DisplayFeatures' + // bounds in this case can't be computed correctly, so we should skip. + return false; + } + windowingMode = taskConfig.windowConfiguration.getWindowingMode(); } else { // TODO(b/242674941): use task windowing mode for window context that associates with // activity. windowingMode = context.getResources().getConfiguration().windowConfiguration .getWindowingMode(); } - if (windowingMode == -1) { - // If we cannot determine the task windowing mode for any reason, it is likely that we - // won't be able to determine its position correctly as well. DisplayFeatures' bounds - // in this case can't be computed correctly, so we should skip. - return false; - } // It is recommended not to report any display features in multi-window mode, since it // won't be possible to synchronize the display feature positions with window movement. return !WindowConfiguration.inMultiWindowMode(windowingMode); 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 87d027899eb4d..8c1b87a650e04 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 @@ -261,7 +261,7 @@ public class SplitControllerTest { assertNotNull(tf); assertNotNull(taskContainer); - assertEquals(TASK_BOUNDS, taskContainer.getTaskBounds()); + assertEquals(TASK_BOUNDS, taskContainer.getConfiguration().windowConfiguration.getBounds()); } @Test 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 af9c6ba5c1628..95328ce700e30 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 @@ -23,7 +23,6 @@ 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.createTestTaskContainer; import static org.junit.Assert.assertEquals; @@ -67,28 +66,6 @@ public class TaskContainerTest { MockitoAnnotations.initMocks(this); } - @Test - public void testIsTaskBoundsInitialized() { - final TaskContainer taskContainer = createTestTaskContainer(); - - assertFalse(taskContainer.isTaskBoundsInitialized()); - - taskContainer.setTaskBounds(TASK_BOUNDS); - - assertTrue(taskContainer.isTaskBoundsInitialized()); - } - - @Test - public void testSetTaskBounds() { - final TaskContainer taskContainer = createTestTaskContainer(); - - assertFalse(taskContainer.setTaskBounds(new Rect())); - - assertTrue(taskContainer.setTaskBounds(TASK_BOUNDS)); - - assertFalse(taskContainer.setTaskBounds(TASK_BOUNDS)); - } - @Test public void testGetWindowingModeForSplitTaskFragment() { final TaskContainer taskContainer = createTestTaskContainer(); diff --git a/services/core/java/com/android/server/wm/ActivityClientController.java b/services/core/java/com/android/server/wm/ActivityClientController.java index 741141d9e463d..da6e7e8436eb1 100644 --- a/services/core/java/com/android/server/wm/ActivityClientController.java +++ b/services/core/java/com/android/server/wm/ActivityClientController.java @@ -580,17 +580,18 @@ class ActivityClientController extends IActivityClientController.Stub { } /** - * Returns the windowing mode of the task that hosts the activity, or {@code -1} if task is not - * found. + * Returns the {@link Configuration} of the task which hosts the Activity, or {@code null} if + * the task {@link Configuration} cannot be obtained. */ @Override - public int getTaskWindowingMode(IBinder activityToken) { + @Nullable + public Configuration getTaskConfiguration(IBinder activityToken) { synchronized (mGlobalLock) { final ActivityRecord ar = ActivityRecord.isInAnyTask(activityToken); if (ar == null) { - return -1; + return null; } - return ar.getTask().getWindowingMode(); + return ar.getTask().getConfiguration(); } }