Merge "Convert TaskFragmentOrganizer callbacks to a transaction callback" into tm-qpr-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
d600010bc5
@@ -16,54 +16,9 @@
|
||||
|
||||
package android.window;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.content.res.Configuration;
|
||||
import android.os.Bundle;
|
||||
import android.os.IBinder;
|
||||
import android.window.TaskFragmentInfo;
|
||||
import android.window.TaskFragmentTransaction;
|
||||
|
||||
/** @hide */
|
||||
oneway interface ITaskFragmentOrganizer {
|
||||
void onTaskFragmentAppeared(in TaskFragmentInfo taskFragmentInfo);
|
||||
void onTaskFragmentInfoChanged(in TaskFragmentInfo taskFragmentInfo);
|
||||
void onTaskFragmentVanished(in TaskFragmentInfo taskFragmentInfo);
|
||||
|
||||
/**
|
||||
* Called when the parent leaf Task of organized TaskFragments is changed.
|
||||
* When the leaf Task is changed, the organizer may want to update the TaskFragments in one
|
||||
* transaction.
|
||||
*
|
||||
* For case like screen size change, it will trigger onTaskFragmentParentInfoChanged with new
|
||||
* Task bounds, but may not trigger onTaskFragmentInfoChanged because there can be an override
|
||||
* bounds.
|
||||
*/
|
||||
void onTaskFragmentParentInfoChanged(in IBinder fragmentToken, in Configuration parentConfig);
|
||||
|
||||
/**
|
||||
* Called when the {@link WindowContainerTransaction} created with
|
||||
* {@link WindowContainerTransaction#setErrorCallbackToken(IBinder)} failed on the server side.
|
||||
*
|
||||
* @param errorCallbackToken Token set through {@link
|
||||
* WindowContainerTransaction#setErrorCallbackToken(IBinder)}
|
||||
* @param errorBundle Bundle containing the exception, operation type and TaskFragmentInfo
|
||||
* if any. Should be created with
|
||||
* {@link TaskFragmentOrganizer#putErrorInfoInBundle}.
|
||||
*/
|
||||
void onTaskFragmentError(in IBinder errorCallbackToken, in Bundle errorBundle);
|
||||
|
||||
/**
|
||||
* Called when an Activity is reparented to the Task with organized TaskFragment. For example,
|
||||
* when an Activity enters and then exits Picture-in-picture, it will be reparented back to its
|
||||
* orginial Task. In this case, we need to notify the organizer so that it can check if the
|
||||
* Activity matches any split rule.
|
||||
*
|
||||
* @param taskId The Task that the activity is reparented to.
|
||||
* @param activityIntent The intent that the activity is original launched with.
|
||||
* @param activityToken If the activity belongs to the same process as the organizer, this
|
||||
* will be the actual activity token; if the activity belongs to a
|
||||
* different process, the server will generate a temporary token that
|
||||
* the organizer can use to reparent the activity through
|
||||
* {@link WindowContainerTransaction} if needed.
|
||||
*/
|
||||
void onActivityReparentToTask(int taskId, in Intent activityIntent, in IBinder activityToken);
|
||||
void onTransactionReady(in TaskFragmentTransaction transaction);
|
||||
}
|
||||
|
||||
@@ -16,6 +16,13 @@
|
||||
|
||||
package android.window;
|
||||
|
||||
import static android.window.TaskFragmentTransaction.TYPE_ACTIVITY_REPARENT_TO_TASK;
|
||||
import static android.window.TaskFragmentTransaction.TYPE_TASK_FRAGMENT_APPEARED;
|
||||
import static android.window.TaskFragmentTransaction.TYPE_TASK_FRAGMENT_ERROR;
|
||||
import static android.window.TaskFragmentTransaction.TYPE_TASK_FRAGMENT_INFO_CHANGED;
|
||||
import static android.window.TaskFragmentTransaction.TYPE_TASK_FRAGMENT_PARENT_INFO_CHANGED;
|
||||
import static android.window.TaskFragmentTransaction.TYPE_TASK_FRAGMENT_VANISHED;
|
||||
|
||||
import android.annotation.CallSuper;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
@@ -27,6 +34,7 @@ import android.os.IBinder;
|
||||
import android.os.RemoteException;
|
||||
import android.view.RemoteAnimationDefinition;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
/**
|
||||
@@ -204,6 +212,67 @@ public class TaskFragmentOrganizer extends WindowOrganizer {
|
||||
public void onActivityReparentToTask(int taskId, @NonNull Intent activityIntent,
|
||||
@NonNull IBinder activityToken) {}
|
||||
|
||||
/**
|
||||
* Called when the transaction is ready so that the organizer can update the TaskFragments based
|
||||
* on the changes in transaction.
|
||||
* @hide
|
||||
*/
|
||||
public void onTransactionReady(@NonNull TaskFragmentTransaction transaction) {
|
||||
final List<TaskFragmentTransaction.Change> changes = transaction.getChanges();
|
||||
for (TaskFragmentTransaction.Change change : changes) {
|
||||
// TODO(b/240519866): apply all changes in one WCT.
|
||||
switch (change.getType()) {
|
||||
case TYPE_TASK_FRAGMENT_APPEARED:
|
||||
onTaskFragmentAppeared(change.getTaskFragmentInfo());
|
||||
if (change.getTaskConfiguration() != null) {
|
||||
// TODO(b/240519866): convert to pass TaskConfiguration for all TFs in the
|
||||
// same Task
|
||||
onTaskFragmentParentInfoChanged(
|
||||
change.getTaskFragmentToken(),
|
||||
change.getTaskConfiguration());
|
||||
}
|
||||
break;
|
||||
case TYPE_TASK_FRAGMENT_INFO_CHANGED:
|
||||
if (change.getTaskConfiguration() != null) {
|
||||
// TODO(b/240519866): convert to pass TaskConfiguration for all TFs in the
|
||||
// same Task
|
||||
onTaskFragmentParentInfoChanged(
|
||||
change.getTaskFragmentToken(),
|
||||
change.getTaskConfiguration());
|
||||
}
|
||||
onTaskFragmentInfoChanged(change.getTaskFragmentInfo());
|
||||
break;
|
||||
case TYPE_TASK_FRAGMENT_VANISHED:
|
||||
onTaskFragmentVanished(change.getTaskFragmentInfo());
|
||||
break;
|
||||
case TYPE_TASK_FRAGMENT_PARENT_INFO_CHANGED:
|
||||
onTaskFragmentParentInfoChanged(
|
||||
change.getTaskFragmentToken(),
|
||||
change.getTaskConfiguration());
|
||||
break;
|
||||
case TYPE_TASK_FRAGMENT_ERROR:
|
||||
final Bundle errorBundle = change.getErrorBundle();
|
||||
onTaskFragmentError(
|
||||
change.getErrorCallbackToken(),
|
||||
errorBundle.getParcelable(
|
||||
KEY_ERROR_CALLBACK_TASK_FRAGMENT_INFO, TaskFragmentInfo.class),
|
||||
errorBundle.getInt(KEY_ERROR_CALLBACK_OP_TYPE),
|
||||
errorBundle.getSerializable(KEY_ERROR_CALLBACK_EXCEPTION,
|
||||
java.lang.Throwable.class));
|
||||
break;
|
||||
case TYPE_ACTIVITY_REPARENT_TO_TASK:
|
||||
onActivityReparentToTask(
|
||||
change.getTaskId(),
|
||||
change.getActivityIntent(),
|
||||
change.getActivityToken());
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException(
|
||||
"Unknown TaskFragmentEvent=" + change.getType());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyTransaction(@NonNull WindowContainerTransaction t) {
|
||||
t.setTaskFragmentOrganizer(mInterface);
|
||||
@@ -221,51 +290,8 @@ public class TaskFragmentOrganizer extends WindowOrganizer {
|
||||
|
||||
private final ITaskFragmentOrganizer mInterface = new ITaskFragmentOrganizer.Stub() {
|
||||
@Override
|
||||
public void onTaskFragmentAppeared(@NonNull TaskFragmentInfo taskFragmentInfo) {
|
||||
mExecutor.execute(
|
||||
() -> TaskFragmentOrganizer.this.onTaskFragmentAppeared(taskFragmentInfo));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTaskFragmentInfoChanged(@NonNull TaskFragmentInfo taskFragmentInfo) {
|
||||
mExecutor.execute(
|
||||
() -> TaskFragmentOrganizer.this.onTaskFragmentInfoChanged(taskFragmentInfo));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTaskFragmentVanished(@NonNull TaskFragmentInfo taskFragmentInfo) {
|
||||
mExecutor.execute(
|
||||
() -> TaskFragmentOrganizer.this.onTaskFragmentVanished(taskFragmentInfo));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTaskFragmentParentInfoChanged(
|
||||
@NonNull IBinder fragmentToken, @NonNull Configuration parentConfig) {
|
||||
mExecutor.execute(
|
||||
() -> TaskFragmentOrganizer.this.onTaskFragmentParentInfoChanged(
|
||||
fragmentToken, parentConfig));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTaskFragmentError(
|
||||
@NonNull IBinder errorCallbackToken, @NonNull Bundle errorBundle) {
|
||||
mExecutor.execute(() -> {
|
||||
final TaskFragmentInfo info = errorBundle.getParcelable(
|
||||
KEY_ERROR_CALLBACK_TASK_FRAGMENT_INFO, TaskFragmentInfo.class);
|
||||
TaskFragmentOrganizer.this.onTaskFragmentError(
|
||||
errorCallbackToken, info,
|
||||
errorBundle.getInt(KEY_ERROR_CALLBACK_OP_TYPE),
|
||||
(Throwable) errorBundle.getSerializable(KEY_ERROR_CALLBACK_EXCEPTION,
|
||||
java.lang.Throwable.class));
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityReparentToTask(int taskId, @NonNull Intent activityIntent,
|
||||
@NonNull IBinder activityToken) {
|
||||
mExecutor.execute(
|
||||
() -> TaskFragmentOrganizer.this.onActivityReparentToTask(
|
||||
taskId, activityIntent, activityToken));
|
||||
public void onTransactionReady(@NonNull TaskFragmentTransaction transaction) {
|
||||
mExecutor.execute(() -> TaskFragmentOrganizer.this.onTransactionReady(transaction));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
20
core/java/android/window/TaskFragmentTransaction.aidl
Normal file
20
core/java/android/window/TaskFragmentTransaction.aidl
Normal file
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
parcelable TaskFragmentTransaction;
|
||||
parcelable TaskFragmentTransaction.Change;
|
||||
335
core/java/android/window/TaskFragmentTransaction.java
Normal file
335
core/java/android/window/TaskFragmentTransaction.java
Normal file
@@ -0,0 +1,335 @@
|
||||
/*
|
||||
* 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 static java.util.Objects.requireNonNull;
|
||||
|
||||
import android.annotation.IntDef;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.content.Intent;
|
||||
import android.content.res.Configuration;
|
||||
import android.os.Bundle;
|
||||
import android.os.IBinder;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Used to communicate information about what are changing on embedded TaskFragments belonging to
|
||||
* the same TaskFragmentOrganizer. A transaction can contain multiple changes.
|
||||
* @see TaskFragmentTransaction.Change
|
||||
* @hide
|
||||
*/
|
||||
public final class TaskFragmentTransaction implements Parcelable {
|
||||
|
||||
private final ArrayList<Change> mChanges = new ArrayList<>();
|
||||
|
||||
public TaskFragmentTransaction() {}
|
||||
|
||||
private TaskFragmentTransaction(Parcel in) {
|
||||
in.readTypedList(mChanges, Change.CREATOR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(@NonNull Parcel dest, int flags) {
|
||||
dest.writeTypedList(mChanges);
|
||||
}
|
||||
|
||||
/** Adds a {@link Change} to this transaction. */
|
||||
public void addChange(@Nullable Change change) {
|
||||
if (change != null) {
|
||||
mChanges.add(change);
|
||||
}
|
||||
}
|
||||
|
||||
/** Whether this transaction contains any {@link Change}. */
|
||||
public boolean isEmpty() {
|
||||
return mChanges.isEmpty();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public List<Change> getChanges() {
|
||||
return mChanges;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("TaskFragmentTransaction{changes=[");
|
||||
for (int i = 0; i < mChanges.size(); ++i) {
|
||||
if (i > 0) {
|
||||
sb.append(',');
|
||||
}
|
||||
sb.append(mChanges.get(i));
|
||||
}
|
||||
sb.append("]}");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static final Creator<TaskFragmentTransaction> CREATOR = new Creator<>() {
|
||||
@Override
|
||||
public TaskFragmentTransaction createFromParcel(Parcel in) {
|
||||
return new TaskFragmentTransaction(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TaskFragmentTransaction[] newArray(int size) {
|
||||
return new TaskFragmentTransaction[size];
|
||||
}
|
||||
};
|
||||
|
||||
/** Change type: the TaskFragment is attached to the hierarchy. */
|
||||
public static final int TYPE_TASK_FRAGMENT_APPEARED = 1;
|
||||
|
||||
/** Change type: the status of the TaskFragment is changed. */
|
||||
public static final int TYPE_TASK_FRAGMENT_INFO_CHANGED = 2;
|
||||
|
||||
/** Change type: the TaskFragment is removed form the hierarchy. */
|
||||
public static final int TYPE_TASK_FRAGMENT_VANISHED = 3;
|
||||
|
||||
/** Change type: the status of the parent leaf Task is changed. */
|
||||
public static final int TYPE_TASK_FRAGMENT_PARENT_INFO_CHANGED = 4;
|
||||
|
||||
/** Change type: the TaskFragment related operation failed on the server side. */
|
||||
public static final int TYPE_TASK_FRAGMENT_ERROR = 5;
|
||||
|
||||
/**
|
||||
* Change type: an Activity is reparented to the Task. For example, when an Activity enters and
|
||||
* then exits Picture-in-picture, it will be reparented back to its original Task. In this case,
|
||||
* we need to notify the organizer so that it can check if the Activity matches any split rule.
|
||||
*/
|
||||
public static final int TYPE_ACTIVITY_REPARENT_TO_TASK = 6;
|
||||
|
||||
@IntDef(prefix = { "TYPE_" }, value = {
|
||||
TYPE_TASK_FRAGMENT_APPEARED,
|
||||
TYPE_TASK_FRAGMENT_INFO_CHANGED,
|
||||
TYPE_TASK_FRAGMENT_VANISHED,
|
||||
TYPE_TASK_FRAGMENT_PARENT_INFO_CHANGED,
|
||||
TYPE_TASK_FRAGMENT_ERROR,
|
||||
TYPE_ACTIVITY_REPARENT_TO_TASK
|
||||
})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@interface ChangeType {}
|
||||
|
||||
/** Represents the change an embedded TaskFragment undergoes. */
|
||||
public static final class Change implements Parcelable {
|
||||
|
||||
/** @see ChangeType */
|
||||
@ChangeType
|
||||
private final int mType;
|
||||
|
||||
/** @see #setTaskFragmentToken(IBinder) */
|
||||
@Nullable
|
||||
private IBinder mTaskFragmentToken;
|
||||
|
||||
/** @see #setTaskFragmentInfo(TaskFragmentInfo) */
|
||||
@Nullable
|
||||
private TaskFragmentInfo mTaskFragmentInfo;
|
||||
|
||||
/** @see #setTaskId(int) */
|
||||
private int mTaskId;
|
||||
|
||||
/** @see #setTaskConfiguration(Configuration) */
|
||||
@Nullable
|
||||
private Configuration mTaskConfiguration;
|
||||
|
||||
/** @see #setErrorCallbackToken(IBinder) */
|
||||
@Nullable
|
||||
private IBinder mErrorCallbackToken;
|
||||
|
||||
/** @see #setErrorBundle(Bundle) */
|
||||
@Nullable
|
||||
private Bundle mErrorBundle;
|
||||
|
||||
/** @see #setActivityIntent(Intent) */
|
||||
@Nullable
|
||||
private Intent mActivityIntent;
|
||||
|
||||
/** @see #setActivityToken(IBinder) */
|
||||
@Nullable
|
||||
private IBinder mActivityToken;
|
||||
|
||||
public Change(@ChangeType int type) {
|
||||
mType = type;
|
||||
}
|
||||
|
||||
private Change(Parcel in) {
|
||||
mType = in.readInt();
|
||||
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();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(@NonNull Parcel dest, int flags) {
|
||||
dest.writeInt(mType);
|
||||
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);
|
||||
}
|
||||
|
||||
/** The change is related to the TaskFragment created with this unique token. */
|
||||
public Change setTaskFragmentToken(@NonNull IBinder taskFragmentToken) {
|
||||
mTaskFragmentToken = requireNonNull(taskFragmentToken);
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Info of the embedded TaskFragment. */
|
||||
public Change setTaskFragmentInfo(@NonNull TaskFragmentInfo info) {
|
||||
mTaskFragmentInfo = requireNonNull(info);
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Task id the parent Task. */
|
||||
public Change setTaskId(int taskId) {
|
||||
mTaskId = taskId;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Configuration of the parent Task. */
|
||||
public Change setTaskConfiguration(@NonNull Configuration configuration) {
|
||||
mTaskConfiguration = requireNonNull(configuration);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* If the {@link #TYPE_TASK_FRAGMENT_ERROR} is from a {@link WindowContainerTransaction}
|
||||
* from the {@link TaskFragmentOrganizer}, it may come with an error callback token to
|
||||
* report back.
|
||||
*/
|
||||
public Change setErrorCallbackToken(@Nullable IBinder errorCallbackToken) {
|
||||
mErrorCallbackToken = errorCallbackToken;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Bundle with necessary info about the failure operation of
|
||||
* {@link #TYPE_TASK_FRAGMENT_ERROR}.
|
||||
*/
|
||||
public Change setErrorBundle(@NonNull Bundle errorBundle) {
|
||||
mErrorBundle = requireNonNull(errorBundle);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Intent of the activity that is reparented to the Task for
|
||||
* {@link #TYPE_ACTIVITY_REPARENT_TO_TASK}.
|
||||
*/
|
||||
public Change setActivityIntent(@NonNull Intent intent) {
|
||||
mActivityIntent = requireNonNull(intent);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Token of the reparent activity for {@link #TYPE_ACTIVITY_REPARENT_TO_TASK}.
|
||||
* If the activity belongs to the same process as the organizer, this will be the actual
|
||||
* activity token; if the activity belongs to a different process, the server will generate
|
||||
* a temporary token that the organizer can use to reparent the activity through
|
||||
* {@link WindowContainerTransaction} if needed.
|
||||
*/
|
||||
public Change setActivityToken(@NonNull IBinder activityToken) {
|
||||
mActivityToken = requireNonNull(activityToken);
|
||||
return this;
|
||||
}
|
||||
|
||||
@ChangeType
|
||||
public int getType() {
|
||||
return mType;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public IBinder getTaskFragmentToken() {
|
||||
return mTaskFragmentToken;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public TaskFragmentInfo getTaskFragmentInfo() {
|
||||
return mTaskFragmentInfo;
|
||||
}
|
||||
|
||||
public int getTaskId() {
|
||||
return mTaskId;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Configuration getTaskConfiguration() {
|
||||
return mTaskConfiguration;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public IBinder getErrorCallbackToken() {
|
||||
return mErrorCallbackToken;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Bundle getErrorBundle() {
|
||||
return mErrorBundle;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Intent getActivityIntent() {
|
||||
return mActivityIntent;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public IBinder getActivityToken() {
|
||||
return mActivityToken;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Change{ type=" + mType + " }";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static final Creator<Change> CREATOR = new Creator<>() {
|
||||
@Override
|
||||
public Change createFromParcel(Parcel in) {
|
||||
return new Change(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Change[] newArray(int size) {
|
||||
return new Change[size];
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -17,6 +17,12 @@
|
||||
package com.android.server.wm;
|
||||
|
||||
import static android.window.TaskFragmentOrganizer.putErrorInfoInBundle;
|
||||
import static android.window.TaskFragmentTransaction.TYPE_ACTIVITY_REPARENT_TO_TASK;
|
||||
import static android.window.TaskFragmentTransaction.TYPE_TASK_FRAGMENT_APPEARED;
|
||||
import static android.window.TaskFragmentTransaction.TYPE_TASK_FRAGMENT_ERROR;
|
||||
import static android.window.TaskFragmentTransaction.TYPE_TASK_FRAGMENT_INFO_CHANGED;
|
||||
import static android.window.TaskFragmentTransaction.TYPE_TASK_FRAGMENT_PARENT_INFO_CHANGED;
|
||||
import static android.window.TaskFragmentTransaction.TYPE_TASK_FRAGMENT_VANISHED;
|
||||
|
||||
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_WINDOW_ORGANIZER;
|
||||
import static com.android.server.wm.TaskFragment.EMBEDDING_ALLOWED;
|
||||
@@ -38,6 +44,7 @@ import android.view.RemoteAnimationDefinition;
|
||||
import android.window.ITaskFragmentOrganizer;
|
||||
import android.window.ITaskFragmentOrganizerController;
|
||||
import android.window.TaskFragmentInfo;
|
||||
import android.window.TaskFragmentTransaction;
|
||||
|
||||
import com.android.internal.protolog.common.ProtoLog;
|
||||
|
||||
@@ -68,6 +75,11 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
|
||||
private final ArrayList<PendingTaskFragmentEvent> mPendingTaskFragmentEvents =
|
||||
new ArrayList<>();
|
||||
|
||||
/** Map from {@link ITaskFragmentOrganizer} to {@link TaskFragmentTransaction}. */
|
||||
private final ArrayMap<IBinder, TaskFragmentTransaction> mTmpOrganizerToTransactionMap =
|
||||
new ArrayMap<>();
|
||||
private final ArrayList<ITaskFragmentOrganizer> mTmpOrganizerList = new ArrayList<>();
|
||||
|
||||
TaskFragmentOrganizerController(ActivityTaskManagerService atm) {
|
||||
mAtmService = atm;
|
||||
mGlobalLock = atm.mGlobalLock;
|
||||
@@ -145,107 +157,138 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
|
||||
mOrganizer.asBinder().unlinkToDeath(this, 0 /*flags*/);
|
||||
}
|
||||
|
||||
void onTaskFragmentAppeared(TaskFragment tf) {
|
||||
@NonNull
|
||||
TaskFragmentTransaction.Change prepareTaskFragmentAppeared(@NonNull TaskFragment tf) {
|
||||
ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "TaskFragment appeared name=%s", tf.getName());
|
||||
final TaskFragmentInfo info = tf.getTaskFragmentInfo();
|
||||
try {
|
||||
mOrganizer.onTaskFragmentAppeared(info);
|
||||
mLastSentTaskFragmentInfos.put(tf, info);
|
||||
tf.mTaskFragmentAppearedSent = true;
|
||||
} catch (RemoteException e) {
|
||||
Slog.d(TAG, "Exception sending onTaskFragmentAppeared callback", e);
|
||||
tf.mTaskFragmentAppearedSent = true;
|
||||
mLastSentTaskFragmentInfos.put(tf, info);
|
||||
final TaskFragmentTransaction.Change change =
|
||||
new TaskFragmentTransaction.Change(TYPE_TASK_FRAGMENT_APPEARED)
|
||||
.setTaskFragmentToken(tf.getFragmentToken())
|
||||
.setTaskFragmentInfo(info);
|
||||
if (shouldSendTaskFragmentParentInfoChanged(tf)) {
|
||||
// TODO(b/240519866): convert to pass TaskConfiguration for all TFs in the same Task
|
||||
final Task task = tf.getTask();
|
||||
mLastSentTaskFragmentParentConfigs
|
||||
.put(tf, new Configuration(task.getConfiguration()));
|
||||
change.setTaskId(task.mTaskId)
|
||||
.setTaskConfiguration(task.getConfiguration());
|
||||
}
|
||||
onTaskFragmentParentInfoChanged(tf);
|
||||
return change;
|
||||
}
|
||||
|
||||
void onTaskFragmentVanished(TaskFragment tf) {
|
||||
@NonNull
|
||||
TaskFragmentTransaction.Change prepareTaskFragmentVanished(@NonNull TaskFragment tf) {
|
||||
ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "TaskFragment vanished name=%s", tf.getName());
|
||||
try {
|
||||
mOrganizer.onTaskFragmentVanished(tf.getTaskFragmentInfo());
|
||||
} catch (RemoteException e) {
|
||||
Slog.d(TAG, "Exception sending onTaskFragmentVanished callback", e);
|
||||
}
|
||||
tf.mTaskFragmentAppearedSent = false;
|
||||
mLastSentTaskFragmentInfos.remove(tf);
|
||||
mLastSentTaskFragmentParentConfigs.remove(tf);
|
||||
return new TaskFragmentTransaction.Change(TYPE_TASK_FRAGMENT_VANISHED)
|
||||
.setTaskFragmentToken(tf.getFragmentToken())
|
||||
.setTaskFragmentInfo(tf.getTaskFragmentInfo());
|
||||
}
|
||||
|
||||
void onTaskFragmentInfoChanged(TaskFragment tf) {
|
||||
// Parent config may have changed. The controller will check if there is any important
|
||||
// config change for the organizer.
|
||||
onTaskFragmentParentInfoChanged(tf);
|
||||
|
||||
@Nullable
|
||||
TaskFragmentTransaction.Change prepareTaskFragmentInfoChanged(
|
||||
@NonNull TaskFragment tf) {
|
||||
// Check if the info is different from the last reported info.
|
||||
final TaskFragmentInfo info = tf.getTaskFragmentInfo();
|
||||
final TaskFragmentInfo lastInfo = mLastSentTaskFragmentInfos.get(tf);
|
||||
if (info.equalsForTaskFragmentOrganizer(lastInfo) && configurationsAreEqualForOrganizer(
|
||||
info.getConfiguration(), lastInfo.getConfiguration())) {
|
||||
return;
|
||||
// Parent config may have changed. The controller will check if there is any
|
||||
// important config change for the organizer.
|
||||
return prepareTaskFragmentParentInfoChanged(tf);
|
||||
}
|
||||
|
||||
ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "TaskFragment info changed name=%s",
|
||||
tf.getName());
|
||||
try {
|
||||
mOrganizer.onTaskFragmentInfoChanged(info);
|
||||
mLastSentTaskFragmentInfos.put(tf, info);
|
||||
} catch (RemoteException e) {
|
||||
Slog.d(TAG, "Exception sending onTaskFragmentInfoChanged callback", e);
|
||||
mLastSentTaskFragmentInfos.put(tf, info);
|
||||
final TaskFragmentTransaction.Change change =
|
||||
new TaskFragmentTransaction.Change(TYPE_TASK_FRAGMENT_INFO_CHANGED)
|
||||
.setTaskFragmentToken(tf.getFragmentToken())
|
||||
.setTaskFragmentInfo(info);
|
||||
if (shouldSendTaskFragmentParentInfoChanged(tf)) {
|
||||
// TODO(b/240519866): convert to pass TaskConfiguration for all TFs in the same Task
|
||||
// at once.
|
||||
// Parent config may have changed. The controller will check if there is any
|
||||
// important config change for the organizer.
|
||||
final Task task = tf.getTask();
|
||||
mLastSentTaskFragmentParentConfigs
|
||||
.put(tf, new Configuration(task.getConfiguration()));
|
||||
change.setTaskId(task.mTaskId)
|
||||
.setTaskConfiguration(task.getConfiguration());
|
||||
}
|
||||
return change;
|
||||
}
|
||||
|
||||
void onTaskFragmentParentInfoChanged(TaskFragment tf) {
|
||||
// Check if the parent info is different from the last reported parent info.
|
||||
if (tf.getParent() == null || tf.getParent().asTask() == null) {
|
||||
mLastSentTaskFragmentParentConfigs.remove(tf);
|
||||
return;
|
||||
@Nullable
|
||||
TaskFragmentTransaction.Change prepareTaskFragmentParentInfoChanged(
|
||||
@NonNull TaskFragment tf) {
|
||||
if (!shouldSendTaskFragmentParentInfoChanged(tf)) {
|
||||
return null;
|
||||
}
|
||||
final Task parent = tf.getParent().asTask();
|
||||
|
||||
final Task parent = tf.getTask();
|
||||
final Configuration parentConfig = parent.getConfiguration();
|
||||
final Configuration lastParentConfig = mLastSentTaskFragmentParentConfigs.get(tf);
|
||||
if (configurationsAreEqualForOrganizer(parentConfig, lastParentConfig)
|
||||
&& parentConfig.windowConfiguration.getWindowingMode()
|
||||
== lastParentConfig.windowConfiguration.getWindowingMode()) {
|
||||
return;
|
||||
}
|
||||
ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER,
|
||||
"TaskFragment parent info changed name=%s parentTaskId=%d",
|
||||
tf.getName(), parent.mTaskId);
|
||||
try {
|
||||
mOrganizer.onTaskFragmentParentInfoChanged(tf.getFragmentToken(), parentConfig);
|
||||
mLastSentTaskFragmentParentConfigs.put(tf, new Configuration(parentConfig));
|
||||
} catch (RemoteException e) {
|
||||
Slog.d(TAG, "Exception sending onTaskFragmentParentInfoChanged callback", e);
|
||||
}
|
||||
mLastSentTaskFragmentParentConfigs.put(tf, new Configuration(parentConfig));
|
||||
return new TaskFragmentTransaction.Change(TYPE_TASK_FRAGMENT_PARENT_INFO_CHANGED)
|
||||
.setTaskFragmentToken(tf.getFragmentToken())
|
||||
.setTaskId(parent.mTaskId)
|
||||
.setTaskConfiguration(parent.getConfiguration());
|
||||
}
|
||||
|
||||
void onTaskFragmentError(IBinder errorCallbackToken, @Nullable TaskFragment taskFragment,
|
||||
int opType, Throwable exception) {
|
||||
/** Whether the system should report TaskFragment parent info changed to the organizer. */
|
||||
private boolean shouldSendTaskFragmentParentInfoChanged(@NonNull TaskFragment tf) {
|
||||
final Task parent = tf.getTask();
|
||||
if (parent == null) {
|
||||
// The TaskFragment is not attached.
|
||||
mLastSentTaskFragmentParentConfigs.remove(tf);
|
||||
return false;
|
||||
}
|
||||
// Check if the parent info is different from the last reported parent info.
|
||||
final Configuration parentConfig = parent.getConfiguration();
|
||||
final Configuration lastParentConfig = mLastSentTaskFragmentParentConfigs.get(tf);
|
||||
return !configurationsAreEqualForOrganizer(parentConfig, lastParentConfig)
|
||||
|| parentConfig.windowConfiguration.getWindowingMode()
|
||||
!= lastParentConfig.windowConfiguration.getWindowingMode();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
TaskFragmentTransaction.Change prepareTaskFragmentError(
|
||||
@Nullable IBinder errorCallbackToken, @Nullable TaskFragment taskFragment,
|
||||
int opType, @NonNull Throwable exception) {
|
||||
ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER,
|
||||
"Sending TaskFragment error exception=%s", exception.toString());
|
||||
final TaskFragmentInfo info =
|
||||
taskFragment != null ? taskFragment.getTaskFragmentInfo() : null;
|
||||
final Bundle errorBundle = putErrorInfoInBundle(exception, info, opType);
|
||||
try {
|
||||
mOrganizer.onTaskFragmentError(errorCallbackToken, errorBundle);
|
||||
} catch (RemoteException e) {
|
||||
Slog.d(TAG, "Exception sending onTaskFragmentError callback", e);
|
||||
}
|
||||
return new TaskFragmentTransaction.Change(TYPE_TASK_FRAGMENT_ERROR)
|
||||
.setErrorCallbackToken(errorCallbackToken)
|
||||
.setErrorBundle(errorBundle);
|
||||
}
|
||||
|
||||
void onActivityReparentToTask(ActivityRecord activity) {
|
||||
@Nullable
|
||||
TaskFragmentTransaction.Change prepareActivityReparentToTask(
|
||||
@NonNull ActivityRecord activity) {
|
||||
if (activity.finishing) {
|
||||
Slog.d(TAG, "Reparent activity=" + activity.token + " is finishing");
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
final Task task = activity.getTask();
|
||||
if (task == null || task.effectiveUid != mOrganizerUid) {
|
||||
Slog.d(TAG, "Reparent activity=" + activity.token
|
||||
+ " is not in a task belong to the organizer app.");
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
if (task.isAllowedToEmbedActivity(activity, mOrganizerUid) != EMBEDDING_ALLOWED) {
|
||||
Slog.d(TAG, "Reparent activity=" + activity.token
|
||||
+ " is not allowed to be embedded.");
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
|
||||
final IBinder activityToken;
|
||||
@@ -268,11 +311,10 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
|
||||
}
|
||||
ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Activity=%s reparent to taskId=%d",
|
||||
activity.token, task.mTaskId);
|
||||
try {
|
||||
mOrganizer.onActivityReparentToTask(task.mTaskId, activity.intent, activityToken);
|
||||
} catch (RemoteException e) {
|
||||
Slog.d(TAG, "Exception sending onActivityReparentToTask callback", e);
|
||||
}
|
||||
return new TaskFragmentTransaction.Change(TYPE_ACTIVITY_REPARENT_TO_TASK)
|
||||
.setTaskId(task.mTaskId)
|
||||
.setActivityIntent(activity.intent)
|
||||
.setActivityToken(activityToken);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -375,7 +417,7 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
|
||||
*/
|
||||
@Nullable
|
||||
public RemoteAnimationDefinition getRemoteAnimationDefinition(
|
||||
ITaskFragmentOrganizer organizer, int taskId) {
|
||||
@NonNull ITaskFragmentOrganizer organizer, int taskId) {
|
||||
synchronized (mGlobalLock) {
|
||||
final TaskFragmentOrganizerState organizerState =
|
||||
mTaskFragmentOrganizerState.get(organizer.asBinder());
|
||||
@@ -385,12 +427,13 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
|
||||
}
|
||||
}
|
||||
|
||||
int getTaskFragmentOrganizerUid(ITaskFragmentOrganizer organizer) {
|
||||
int getTaskFragmentOrganizerUid(@NonNull ITaskFragmentOrganizer organizer) {
|
||||
final TaskFragmentOrganizerState state = validateAndGetState(organizer);
|
||||
return state.mOrganizerUid;
|
||||
}
|
||||
|
||||
void onTaskFragmentAppeared(ITaskFragmentOrganizer organizer, TaskFragment taskFragment) {
|
||||
void onTaskFragmentAppeared(@NonNull ITaskFragmentOrganizer organizer,
|
||||
@NonNull TaskFragment taskFragment) {
|
||||
final TaskFragmentOrganizerState state = validateAndGetState(organizer);
|
||||
if (!state.addTaskFragment(taskFragment)) {
|
||||
return;
|
||||
@@ -406,19 +449,20 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
|
||||
}
|
||||
}
|
||||
|
||||
void onTaskFragmentInfoChanged(ITaskFragmentOrganizer organizer, TaskFragment taskFragment) {
|
||||
void onTaskFragmentInfoChanged(@NonNull ITaskFragmentOrganizer organizer,
|
||||
@NonNull TaskFragment taskFragment) {
|
||||
handleTaskFragmentInfoChanged(organizer, taskFragment,
|
||||
PendingTaskFragmentEvent.EVENT_INFO_CHANGED);
|
||||
}
|
||||
|
||||
void onTaskFragmentParentInfoChanged(ITaskFragmentOrganizer organizer,
|
||||
TaskFragment taskFragment) {
|
||||
void onTaskFragmentParentInfoChanged(@NonNull ITaskFragmentOrganizer organizer,
|
||||
@NonNull TaskFragment taskFragment) {
|
||||
handleTaskFragmentInfoChanged(organizer, taskFragment,
|
||||
PendingTaskFragmentEvent.EVENT_PARENT_INFO_CHANGED);
|
||||
}
|
||||
|
||||
private void handleTaskFragmentInfoChanged(ITaskFragmentOrganizer organizer,
|
||||
TaskFragment taskFragment, int eventType) {
|
||||
private void handleTaskFragmentInfoChanged(@NonNull ITaskFragmentOrganizer organizer,
|
||||
@NonNull TaskFragment taskFragment, int eventType) {
|
||||
validateAndGetState(organizer);
|
||||
if (!taskFragment.mTaskFragmentAppearedSent) {
|
||||
// Skip if TaskFragment still not appeared.
|
||||
@@ -444,7 +488,8 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
|
||||
mPendingTaskFragmentEvents.add(pendingEvent);
|
||||
}
|
||||
|
||||
void onTaskFragmentVanished(ITaskFragmentOrganizer organizer, TaskFragment taskFragment) {
|
||||
void onTaskFragmentVanished(@NonNull ITaskFragmentOrganizer organizer,
|
||||
@NonNull TaskFragment taskFragment) {
|
||||
final TaskFragmentOrganizerState state = validateAndGetState(organizer);
|
||||
for (int i = mPendingTaskFragmentEvents.size() - 1; i >= 0; i--) {
|
||||
PendingTaskFragmentEvent entry = mPendingTaskFragmentEvents.get(i);
|
||||
@@ -467,8 +512,9 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
|
||||
state.removeTaskFragment(taskFragment);
|
||||
}
|
||||
|
||||
void onTaskFragmentError(ITaskFragmentOrganizer organizer, IBinder errorCallbackToken,
|
||||
TaskFragment taskFragment, int opType, Throwable exception) {
|
||||
void onTaskFragmentError(@NonNull ITaskFragmentOrganizer organizer,
|
||||
@Nullable IBinder errorCallbackToken, @Nullable TaskFragment taskFragment,
|
||||
int opType, @NonNull Throwable exception) {
|
||||
validateAndGetState(organizer);
|
||||
Slog.w(TAG, "onTaskFragmentError ", exception);
|
||||
final PendingTaskFragmentEvent pendingEvent = new PendingTaskFragmentEvent.Builder(
|
||||
@@ -483,7 +529,7 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
|
||||
mAtmService.mWindowManager.mWindowPlacerLocked.requestTraversal();
|
||||
}
|
||||
|
||||
void onActivityReparentToTask(ActivityRecord activity) {
|
||||
void onActivityReparentToTask(@NonNull ActivityRecord activity) {
|
||||
final ITaskFragmentOrganizer organizer;
|
||||
if (activity.mLastTaskFragmentOrganizerBeforePip != null) {
|
||||
// If the activity is previously embedded in an organized TaskFragment.
|
||||
@@ -515,11 +561,11 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
|
||||
mPendingTaskFragmentEvents.add(pendingEvent);
|
||||
}
|
||||
|
||||
boolean isOrganizerRegistered(ITaskFragmentOrganizer organizer) {
|
||||
boolean isOrganizerRegistered(@NonNull ITaskFragmentOrganizer organizer) {
|
||||
return mTaskFragmentOrganizerState.containsKey(organizer.asBinder());
|
||||
}
|
||||
|
||||
private void removeOrganizer(ITaskFragmentOrganizer organizer) {
|
||||
private void removeOrganizer(@NonNull ITaskFragmentOrganizer organizer) {
|
||||
final TaskFragmentOrganizerState state = validateAndGetState(organizer);
|
||||
// remove all of the children of the organized TaskFragment
|
||||
state.dispose();
|
||||
@@ -539,7 +585,9 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
|
||||
* we wouldn't register {@link DeathRecipient} for the organizer, and might not remove the
|
||||
* {@link TaskFragment} after the organizer process died.
|
||||
*/
|
||||
private TaskFragmentOrganizerState validateAndGetState(ITaskFragmentOrganizer organizer) {
|
||||
@NonNull
|
||||
private TaskFragmentOrganizerState validateAndGetState(
|
||||
@NonNull ITaskFragmentOrganizer organizer) {
|
||||
final TaskFragmentOrganizerState state =
|
||||
mTaskFragmentOrganizerState.get(organizer.asBinder());
|
||||
if (state == null) {
|
||||
@@ -672,7 +720,7 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private PendingTaskFragmentEvent getLastPendingLifecycleEvent(TaskFragment tf) {
|
||||
private PendingTaskFragmentEvent getLastPendingLifecycleEvent(@NonNull TaskFragment tf) {
|
||||
for (int i = mPendingTaskFragmentEvents.size() - 1; i >= 0; i--) {
|
||||
PendingTaskFragmentEvent entry = mPendingTaskFragmentEvents.get(i);
|
||||
if (tf == entry.mTaskFragment && entry.isLifecycleEvent()) {
|
||||
@@ -683,7 +731,7 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private PendingTaskFragmentEvent getPendingTaskFragmentEvent(TaskFragment taskFragment,
|
||||
private PendingTaskFragmentEvent getPendingTaskFragmentEvent(@NonNull TaskFragment taskFragment,
|
||||
int type) {
|
||||
for (int i = mPendingTaskFragmentEvents.size() - 1; i >= 0; i--) {
|
||||
PendingTaskFragmentEvent entry = mPendingTaskFragmentEvents.get(i);
|
||||
@@ -731,16 +779,36 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
|
||||
candidateEvents.add(event);
|
||||
}
|
||||
final int numEvents = candidateEvents.size();
|
||||
if (numEvents == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
mTmpOrganizerToTransactionMap.clear();
|
||||
mTmpOrganizerList.clear();
|
||||
for (int i = 0; i < numEvents; i++) {
|
||||
dispatchEvent(candidateEvents.get(i));
|
||||
final PendingTaskFragmentEvent event = candidateEvents.get(i);
|
||||
if (!mTmpOrganizerToTransactionMap.containsKey(event.mTaskFragmentOrg.asBinder())) {
|
||||
mTmpOrganizerToTransactionMap.put(event.mTaskFragmentOrg.asBinder(),
|
||||
new TaskFragmentTransaction());
|
||||
mTmpOrganizerList.add(event.mTaskFragmentOrg);
|
||||
}
|
||||
mTmpOrganizerToTransactionMap.get(event.mTaskFragmentOrg.asBinder())
|
||||
.addChange(prepareChange(event));
|
||||
}
|
||||
if (numEvents > 0) {
|
||||
mPendingTaskFragmentEvents.removeAll(candidateEvents);
|
||||
final int numOrganizers = mTmpOrganizerList.size();
|
||||
for (int i = 0; i < numOrganizers; i++) {
|
||||
final ITaskFragmentOrganizer organizer = mTmpOrganizerList.get(i);
|
||||
dispatchTransactionInfo(organizer,
|
||||
mTmpOrganizerToTransactionMap.get(organizer.asBinder()));
|
||||
}
|
||||
mPendingTaskFragmentEvents.removeAll(candidateEvents);
|
||||
mTmpOrganizerToTransactionMap.clear();
|
||||
mTmpOrganizerList.clear();
|
||||
}
|
||||
|
||||
private static boolean isTaskVisible(Task task, ArrayList<Task> knownVisibleTasks,
|
||||
ArrayList<Task> knownInvisibleTasks) {
|
||||
private static boolean isTaskVisible(@NonNull Task task,
|
||||
@NonNull ArrayList<Task> knownVisibleTasks,
|
||||
@NonNull ArrayList<Task> knownInvisibleTasks) {
|
||||
if (knownVisibleTasks.contains(task)) {
|
||||
return true;
|
||||
}
|
||||
@@ -756,44 +824,57 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
|
||||
}
|
||||
}
|
||||
|
||||
void dispatchPendingInfoChangedEvent(TaskFragment taskFragment) {
|
||||
PendingTaskFragmentEvent event = getPendingTaskFragmentEvent(taskFragment,
|
||||
void dispatchPendingInfoChangedEvent(@NonNull TaskFragment taskFragment) {
|
||||
final PendingTaskFragmentEvent event = getPendingTaskFragmentEvent(taskFragment,
|
||||
PendingTaskFragmentEvent.EVENT_INFO_CHANGED);
|
||||
if (event == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
dispatchEvent(event);
|
||||
final TaskFragmentTransaction transaction = new TaskFragmentTransaction();
|
||||
transaction.addChange(prepareChange(event));
|
||||
dispatchTransactionInfo(event.mTaskFragmentOrg, transaction);
|
||||
mPendingTaskFragmentEvents.remove(event);
|
||||
}
|
||||
|
||||
private void dispatchEvent(PendingTaskFragmentEvent event) {
|
||||
private void dispatchTransactionInfo(@NonNull ITaskFragmentOrganizer organizer,
|
||||
@NonNull TaskFragmentTransaction transaction) {
|
||||
if (transaction.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
organizer.onTransactionReady(transaction);
|
||||
} catch (RemoteException e) {
|
||||
Slog.d(TAG, "Exception sending TaskFragmentTransaction", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private TaskFragmentTransaction.Change prepareChange(
|
||||
@NonNull PendingTaskFragmentEvent event) {
|
||||
final ITaskFragmentOrganizer taskFragmentOrg = event.mTaskFragmentOrg;
|
||||
final TaskFragment taskFragment = event.mTaskFragment;
|
||||
final TaskFragmentOrganizerState state =
|
||||
mTaskFragmentOrganizerState.get(taskFragmentOrg.asBinder());
|
||||
if (state == null) {
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
switch (event.mEventType) {
|
||||
case PendingTaskFragmentEvent.EVENT_APPEARED:
|
||||
state.onTaskFragmentAppeared(taskFragment);
|
||||
break;
|
||||
return state.prepareTaskFragmentAppeared(taskFragment);
|
||||
case PendingTaskFragmentEvent.EVENT_VANISHED:
|
||||
state.onTaskFragmentVanished(taskFragment);
|
||||
break;
|
||||
return state.prepareTaskFragmentVanished(taskFragment);
|
||||
case PendingTaskFragmentEvent.EVENT_INFO_CHANGED:
|
||||
state.onTaskFragmentInfoChanged(taskFragment);
|
||||
break;
|
||||
return state.prepareTaskFragmentInfoChanged(taskFragment);
|
||||
case PendingTaskFragmentEvent.EVENT_PARENT_INFO_CHANGED:
|
||||
state.onTaskFragmentParentInfoChanged(taskFragment);
|
||||
break;
|
||||
return state.prepareTaskFragmentParentInfoChanged(taskFragment);
|
||||
case PendingTaskFragmentEvent.EVENT_ERROR:
|
||||
state.onTaskFragmentError(event.mErrorCallbackToken, taskFragment, event.mOpType,
|
||||
event.mException);
|
||||
break;
|
||||
return state.prepareTaskFragmentError(event.mErrorCallbackToken, taskFragment,
|
||||
event.mOpType, event.mException);
|
||||
case PendingTaskFragmentEvent.EVENT_ACTIVITY_REPARENT_TO_TASK:
|
||||
state.onActivityReparentToTask(event.mActivity);
|
||||
return state.prepareActivityReparentToTask(event.mActivity);
|
||||
default:
|
||||
throw new IllegalArgumentException("Unknown TaskFragmentEvent=" + event.mEventType);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -199,9 +199,11 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
|
||||
final Task parent = mock(Task.class);
|
||||
final Configuration parentConfig = new Configuration();
|
||||
parentConfig.smallestScreenWidthDp = 10;
|
||||
doReturn(parent).when(mTaskFragment).getParent();
|
||||
doReturn(parent).when(mTaskFragment).getTask();
|
||||
doReturn(parentConfig).when(parent).getConfiguration();
|
||||
doReturn(parent).when(parent).asTask();
|
||||
// Task needs to be visible
|
||||
parent.lastActiveTime = 100;
|
||||
doReturn(true).when(parent).shouldBeVisible(any());
|
||||
|
||||
mTaskFragment.mTaskFragmentAppearedSent = true;
|
||||
mController.onTaskFragmentParentInfoChanged(
|
||||
|
||||
Reference in New Issue
Block a user