Loading core/java/android/app/ActivityClient.java +5 −4 Original line number Diff line number Diff line Loading @@ -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(); } Loading core/java/android/app/IActivityClientController.aidl +5 −1 Original line number Diff line number Diff line Loading @@ -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); Loading libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java +0 −15 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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 Loading Loading @@ -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; } Loading libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java +1 −17 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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(); } } libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java +48 −27 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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<TaskFragmentContainer> mContainers = new ArrayList<>(); Loading Loading @@ -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; Loading @@ -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. Loading Loading @@ -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. * <p> * Note that for most case, caller should use * {@link SplitPresenter#getTaskProperties(Activity)} instead. This method is used before * the {@code activity} goes into split. * </p><p> * 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); } } } Loading
core/java/android/app/ActivityClient.java +5 −4 Original line number Diff line number Diff line Loading @@ -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(); } Loading
core/java/android/app/IActivityClientController.aidl +5 −1 Original line number Diff line number Diff line Loading @@ -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); Loading
libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java +0 −15 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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 Loading Loading @@ -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; } Loading
libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java +1 −17 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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(); } }
libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java +48 −27 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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<TaskFragmentContainer> mContainers = new ArrayList<>(); Loading Loading @@ -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; Loading @@ -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. Loading Loading @@ -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. * <p> * Note that for most case, caller should use * {@link SplitPresenter#getTaskProperties(Activity)} instead. This method is used before * the {@code activity} goes into split. * </p><p> * 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); } } }