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
This commit is contained in:
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<TaskFragmentContainer> 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.
|
||||
* <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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -261,7 +261,7 @@ public class SplitControllerTest {
|
||||
|
||||
assertNotNull(tf);
|
||||
assertNotNull(taskContainer);
|
||||
assertEquals(TASK_BOUNDS, taskContainer.getTaskBounds());
|
||||
assertEquals(TASK_BOUNDS, taskContainer.getConfiguration().windowConfiguration.getBounds());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user