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(); } }