Merge "Add TaskFragmentParentInfo" into tm-qpr-dev

This commit is contained in:
Charles Chen
2022-09-21 11:43:45 +00:00
committed by Android (Google) Code Review
9 changed files with 231 additions and 32 deletions

View File

@@ -188,6 +188,10 @@ public final class TaskFragmentInfo implements Parcelable {
/**
* Returns {@code true} if the parameters that are important for task fragment organizers are
* equal between this {@link TaskFragmentInfo} and {@param that}.
* Note that this method is usually called with
* {@link com.android.server.wm.WindowOrganizerController#configurationsAreEqualForOrganizer(
* Configuration, Configuration)} to determine if this {@link TaskFragmentInfo} should
* be dispatched to the client.
*/
public boolean equalsForTaskFragmentOrganizer(@Nullable TaskFragmentInfo that) {
if (that == null) {

View File

@@ -0,0 +1,23 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.window;
/**
* The information about the parent Task of a particular TaskFragment
* @hide
*/
parcelable TaskFragmentParentInfo;

View File

@@ -0,0 +1,130 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.window;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.WindowConfiguration;
import android.content.res.Configuration;
import android.os.Parcel;
import android.os.Parcelable;
/**
* The information about the parent Task of a particular TaskFragment
* @hide
*/
public class TaskFragmentParentInfo implements Parcelable {
@NonNull
private final Configuration mConfiguration = new Configuration();
private final int mDisplayId;
private final boolean mVisibleRequested;
public TaskFragmentParentInfo(@NonNull Configuration configuration, int displayId,
boolean visibleRequested) {
mConfiguration.setTo(configuration);
mDisplayId = displayId;
mVisibleRequested = visibleRequested;
}
public TaskFragmentParentInfo(@NonNull TaskFragmentParentInfo info) {
mConfiguration.setTo(info.getConfiguration());
mDisplayId = info.mDisplayId;
mVisibleRequested = info.mVisibleRequested;
}
/** The {@link Configuration} of the parent Task */
@NonNull
public Configuration getConfiguration() {
return mConfiguration;
}
/**
* The display ID of the parent Task. {@link android.view.Display#INVALID_DISPLAY} means the
* Task is detached from previously associated display.
*/
public int getDisplayId() {
return mDisplayId;
}
/** Whether the parent Task is requested to be visible or not */
public boolean isVisibleRequested() {
return mVisibleRequested;
}
/**
* Returns {@code true} if the parameters which are important for task fragment
* organizers are equal between this {@link TaskFragmentParentInfo} and {@code that}.
* Note that this method is usually called with
* {@link com.android.server.wm.WindowOrganizerController#configurationsAreEqualForOrganizer(
* Configuration, Configuration)} to determine if this {@link TaskFragmentParentInfo} should
* be dispatched to the client.
*/
public boolean equalsForTaskFragmentOrganizer(@Nullable TaskFragmentParentInfo that) {
if (that == null) {
return false;
}
return getWindowingMode() == that.getWindowingMode() && mDisplayId == that.mDisplayId
&& mVisibleRequested == that.mVisibleRequested;
}
@WindowConfiguration.WindowingMode
private int getWindowingMode() {
return mConfiguration.windowConfiguration.getWindowingMode();
}
@Override
public String toString() {
return TaskFragmentParentInfo.class.getSimpleName() + ":{"
+ "config=" + mConfiguration
+ ", displayId=" + mDisplayId
+ ", visibleRequested=" + mVisibleRequested
+ "}";
}
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
mConfiguration.writeToParcel(dest, flags);
dest.writeInt(mDisplayId);
dest.writeBoolean(mVisibleRequested);
}
private TaskFragmentParentInfo(Parcel in) {
mConfiguration.readFromParcel(in);
mDisplayId = in.readInt();
mVisibleRequested = in.readBoolean();
}
public static final Creator<TaskFragmentParentInfo> CREATOR =
new Creator<TaskFragmentParentInfo>() {
@Override
public TaskFragmentParentInfo createFromParcel(Parcel in) {
return new TaskFragmentParentInfo(in);
}
@Override
public TaskFragmentParentInfo[] newArray(int size) {
return new TaskFragmentParentInfo[size];
}
};
@Override
public int describeContents() {
return 0;
}
}

View File

@@ -171,10 +171,6 @@ public final class TaskFragmentTransaction implements Parcelable {
/** @see #setTaskId(int) */
private int mTaskId;
/** @see #setTaskConfiguration(Configuration) */
@Nullable
private Configuration mTaskConfiguration;
/** @see #setErrorCallbackToken(IBinder) */
@Nullable
private IBinder mErrorCallbackToken;
@@ -191,6 +187,9 @@ public final class TaskFragmentTransaction implements Parcelable {
@Nullable
private IBinder mActivityToken;
@Nullable
private TaskFragmentParentInfo mTaskFragmentParentInfo;
public Change(@ChangeType int type) {
mType = type;
}
@@ -200,11 +199,11 @@ public final class TaskFragmentTransaction implements Parcelable {
mTaskFragmentToken = in.readStrongBinder();
mTaskFragmentInfo = in.readTypedObject(TaskFragmentInfo.CREATOR);
mTaskId = in.readInt();
mTaskConfiguration = in.readTypedObject(Configuration.CREATOR);
mErrorCallbackToken = in.readStrongBinder();
mErrorBundle = in.readBundle(TaskFragmentTransaction.class.getClassLoader());
mActivityIntent = in.readTypedObject(Intent.CREATOR);
mActivityToken = in.readStrongBinder();
mTaskFragmentParentInfo = in.readTypedObject(TaskFragmentParentInfo.CREATOR);
}
@Override
@@ -213,11 +212,11 @@ public final class TaskFragmentTransaction implements Parcelable {
dest.writeStrongBinder(mTaskFragmentToken);
dest.writeTypedObject(mTaskFragmentInfo, flags);
dest.writeInt(mTaskId);
dest.writeTypedObject(mTaskConfiguration, flags);
dest.writeStrongBinder(mErrorCallbackToken);
dest.writeBundle(mErrorBundle);
dest.writeTypedObject(mActivityIntent, flags);
dest.writeStrongBinder(mActivityToken);
dest.writeTypedObject(mTaskFragmentParentInfo, flags);
}
/** The change is related to the TaskFragment created with this unique token. */
@@ -241,10 +240,10 @@ public final class TaskFragmentTransaction implements Parcelable {
return this;
}
// TODO(b/241043377): Keep this API to prevent @TestApi changes. Remove in the next release.
/** Configuration of the parent Task. */
@NonNull
public Change setTaskConfiguration(@NonNull Configuration configuration) {
mTaskConfiguration = requireNonNull(configuration);
return this;
}
@@ -292,6 +291,19 @@ public final class TaskFragmentTransaction implements Parcelable {
return this;
}
// TODO(b/241043377): Hide this API to prevent @TestApi changes. Remove in the next release.
/**
* Sets info of the parent Task of the embedded TaskFragment.
* @see TaskFragmentParentInfo
*
* @hide pending unhide
*/
@NonNull
public Change setTaskFragmentParentInfo(@NonNull TaskFragmentParentInfo info) {
mTaskFragmentParentInfo = requireNonNull(info);
return this;
}
@ChangeType
public int getType() {
return mType;
@@ -311,9 +323,10 @@ public final class TaskFragmentTransaction implements Parcelable {
return mTaskId;
}
// TODO(b/241043377): Keep this API to prevent @TestApi changes. Remove in the next release.
@Nullable
public Configuration getTaskConfiguration() {
return mTaskConfiguration;
return mTaskFragmentParentInfo.getConfiguration();
}
@Nullable
@@ -337,6 +350,13 @@ public final class TaskFragmentTransaction implements Parcelable {
return mActivityToken;
}
// TODO(b/241043377): Hide this API to prevent @TestApi changes. Remove in the next release.
/** @hide pending unhide */
@Nullable
public TaskFragmentParentInfo getTaskFragmentParentInfo() {
return mTaskFragmentParentInfo;
}
@Override
public String toString() {
return "Change{ type=" + mType + " }";

View File

@@ -63,6 +63,7 @@ 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;
@@ -191,7 +192,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,12 +348,14 @@ 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) {
int taskId, @NonNull TaskFragmentParentInfo parentInfo) {
// TODO(b/241043111): handles displayId and visibility here.
final Configuration parentConfig = parentInfo.getConfiguration();
onTaskConfigurationChanged(taskId, parentConfig);
if (isInPictureInPicture(parentConfig)) {
// No need to update presentation in PIP until the Task exit PIP.

View File

@@ -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;
@@ -75,6 +76,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;
@@ -1038,15 +1040,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());
}

View File

@@ -185,6 +185,7 @@ import android.view.WindowManager.TransitionOldType;
import android.window.ITaskOrganizer;
import android.window.PictureInPictureSurfaceTransaction;
import android.window.StartingWindowInfo;
import android.window.TaskFragmentParentInfo;
import android.window.TaskSnapshot;
import android.window.WindowContainerToken;
@@ -3518,6 +3519,14 @@ class Task extends TaskFragment {
return info;
}
/**
* Returns the {@link TaskFragmentParentInfo} which will send to the client
* {@link android.window.TaskFragmentOrganizer}
*/
TaskFragmentParentInfo getTaskFragmentParentInfo() {
return new TaskFragmentParentInfo(getConfiguration(), getDisplayId(), isVisibleRequested());
}
boolean isTaskId(int taskId) {
return mTaskId == taskId;
}

View File

@@ -49,6 +49,7 @@ import android.view.WindowManager;
import android.window.ITaskFragmentOrganizer;
import android.window.ITaskFragmentOrganizerController;
import android.window.TaskFragmentInfo;
import android.window.TaskFragmentParentInfo;
import android.window.TaskFragmentTransaction;
import android.window.WindowContainerTransaction;
@@ -118,10 +119,10 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
private final Map<TaskFragment, Integer> mTaskFragmentTaskIds = new WeakHashMap<>();
/**
* Map from {@link Task#mTaskId} to the last Task {@link Configuration} sent to the
* Map from {@link Task#mTaskId} to the last {@link TaskFragmentParentInfo} sent to the
* organizer.
*/
private final SparseArray<Configuration> mLastSentTaskFragmentParentConfigs =
private final SparseArray<TaskFragmentParentInfo> mLastSentTaskFragmentParentInfos =
new SparseArray<>();
/**
@@ -225,7 +226,7 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
taskId = mTaskFragmentTaskIds.remove(tf);
if (!mTaskFragmentTaskIds.containsValue(taskId)) {
// No more TaskFragment in the Task.
mLastSentTaskFragmentParentConfigs.remove(taskId);
mLastSentTaskFragmentParentInfos.remove(taskId);
}
} else {
// This can happen if the appeared wasn't sent before remove.
@@ -260,25 +261,27 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
}
@Nullable
TaskFragmentTransaction.Change prepareTaskFragmentParentInfoChanged(
@NonNull Task task) {
TaskFragmentTransaction.Change prepareTaskFragmentParentInfoChanged(@NonNull Task task) {
final int taskId = task.mTaskId;
// Check if the parent info is different from the last reported parent info.
final Configuration taskConfig = task.getConfiguration();
final Configuration lastParentConfig = mLastSentTaskFragmentParentConfigs.get(taskId);
if (configurationsAreEqualForOrganizer(taskConfig, lastParentConfig)
&& taskConfig.windowConfiguration.getWindowingMode()
== lastParentConfig.windowConfiguration.getWindowingMode()) {
final TaskFragmentParentInfo parentInfo = task.getTaskFragmentParentInfo();
final TaskFragmentParentInfo lastParentInfo = mLastSentTaskFragmentParentInfos
.get(taskId);
final Configuration lastParentConfig = lastParentInfo != null
? lastParentInfo.getConfiguration() : null;
if (parentInfo.equalsForTaskFragmentOrganizer(lastParentInfo)
&& configurationsAreEqualForOrganizer(parentInfo.getConfiguration(),
lastParentConfig)) {
return null;
}
ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER,
"TaskFragment parent info changed name=%s parentTaskId=%d",
task.getName(), taskId);
mLastSentTaskFragmentParentConfigs.put(taskId, new Configuration(taskConfig));
mLastSentTaskFragmentParentInfos.put(taskId, new TaskFragmentParentInfo(parentInfo));
return new TaskFragmentTransaction.Change(TYPE_TASK_FRAGMENT_PARENT_INFO_CHANGED)
.setTaskId(taskId)
.setTaskConfiguration(taskConfig);
.setTaskFragmentParentInfo(parentInfo);
}
@NonNull

View File

@@ -18,6 +18,7 @@ package com.android.server.wm;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
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_THROWABLE;
import static android.window.TaskFragmentOrganizer.getTransitionType;
@@ -76,6 +77,7 @@ import android.window.TaskFragmentCreationParams;
import android.window.TaskFragmentInfo;
import android.window.TaskFragmentOrganizer;
import android.window.TaskFragmentOrganizerToken;
import android.window.TaskFragmentParentInfo;
import android.window.TaskFragmentTransaction;
import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction;
@@ -271,7 +273,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
@Test
public void testOnTaskFragmentParentInfoChanged() {
setupMockParent(mTaskFragment, mTask);
mTask.getConfiguration().smallestScreenWidthDp = 10;
mTask.getTaskFragmentParentInfo().getConfiguration().smallestScreenWidthDp = 10;
mController.onTaskFragmentAppeared(
mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment);
@@ -295,7 +297,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
// Trigger callback if the size is changed.
clearInvocations(mOrganizer);
mTask.getConfiguration().smallestScreenWidthDp = 100;
mTask.getTaskFragmentParentInfo().getConfiguration().smallestScreenWidthDp = 100;
mController.onTaskFragmentInfoChanged(
mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment);
mController.dispatchPendingEvents();
@@ -304,7 +306,8 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
// Trigger callback if the windowing mode is changed.
clearInvocations(mOrganizer);
mTask.getConfiguration().windowConfiguration.setWindowingMode(WINDOWING_MODE_PINNED);
mTask.getTaskFragmentParentInfo().getConfiguration().windowConfiguration
.setWindowingMode(WINDOWING_MODE_PINNED);
mController.onTaskFragmentInfoChanged(
mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment);
mController.dispatchPendingEvents();
@@ -1268,7 +1271,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
final TaskFragmentTransaction.Change change = changes.get(0);
assertEquals(TYPE_TASK_FRAGMENT_PARENT_INFO_CHANGED, change.getType());
assertEquals(task.mTaskId, change.getTaskId());
assertEquals(task.getConfiguration(), change.getTaskConfiguration());
assertEquals(task.getTaskFragmentParentInfo(), change.getTaskFragmentParentInfo());
}
/** Asserts that there will be a transaction for TaskFragment error. */
@@ -1316,8 +1319,8 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
/** Setups the mock Task as the parent of the given TaskFragment. */
private static void setupMockParent(TaskFragment taskFragment, Task mockParent) {
doReturn(mockParent).when(taskFragment).getTask();
final Configuration taskConfig = new Configuration();
doReturn(taskConfig).when(mockParent).getConfiguration();
doReturn(new TaskFragmentParentInfo(new Configuration(), DEFAULT_DISPLAY, true))
.when(mockParent).getTaskFragmentParentInfo();
// Task needs to be visible
mockParent.lastActiveTime = 100;