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;
|
package android.window;
|
||||||
|
|
||||||
import android.content.Intent;
|
import android.window.TaskFragmentTransaction;
|
||||||
import android.content.res.Configuration;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.os.IBinder;
|
|
||||||
import android.window.TaskFragmentInfo;
|
|
||||||
|
|
||||||
/** @hide */
|
/** @hide */
|
||||||
oneway interface ITaskFragmentOrganizer {
|
oneway interface ITaskFragmentOrganizer {
|
||||||
void onTaskFragmentAppeared(in TaskFragmentInfo taskFragmentInfo);
|
void onTransactionReady(in TaskFragmentTransaction transaction);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,13 @@
|
|||||||
|
|
||||||
package android.window;
|
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.CallSuper;
|
||||||
import android.annotation.NonNull;
|
import android.annotation.NonNull;
|
||||||
import android.annotation.Nullable;
|
import android.annotation.Nullable;
|
||||||
@@ -27,6 +34,7 @@ import android.os.IBinder;
|
|||||||
import android.os.RemoteException;
|
import android.os.RemoteException;
|
||||||
import android.view.RemoteAnimationDefinition;
|
import android.view.RemoteAnimationDefinition;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -204,6 +212,67 @@ public class TaskFragmentOrganizer extends WindowOrganizer {
|
|||||||
public void onActivityReparentToTask(int taskId, @NonNull Intent activityIntent,
|
public void onActivityReparentToTask(int taskId, @NonNull Intent activityIntent,
|
||||||
@NonNull IBinder activityToken) {}
|
@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
|
@Override
|
||||||
public void applyTransaction(@NonNull WindowContainerTransaction t) {
|
public void applyTransaction(@NonNull WindowContainerTransaction t) {
|
||||||
t.setTaskFragmentOrganizer(mInterface);
|
t.setTaskFragmentOrganizer(mInterface);
|
||||||
@@ -221,51 +290,8 @@ public class TaskFragmentOrganizer extends WindowOrganizer {
|
|||||||
|
|
||||||
private final ITaskFragmentOrganizer mInterface = new ITaskFragmentOrganizer.Stub() {
|
private final ITaskFragmentOrganizer mInterface = new ITaskFragmentOrganizer.Stub() {
|
||||||
@Override
|
@Override
|
||||||
public void onTaskFragmentAppeared(@NonNull TaskFragmentInfo taskFragmentInfo) {
|
public void onTransactionReady(@NonNull TaskFragmentTransaction transaction) {
|
||||||
mExecutor.execute(
|
mExecutor.execute(() -> TaskFragmentOrganizer.this.onTransactionReady(transaction));
|
||||||
() -> 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));
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
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;
|
package com.android.server.wm;
|
||||||
|
|
||||||
import static android.window.TaskFragmentOrganizer.putErrorInfoInBundle;
|
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.internal.protolog.ProtoLogGroup.WM_DEBUG_WINDOW_ORGANIZER;
|
||||||
import static com.android.server.wm.TaskFragment.EMBEDDING_ALLOWED;
|
import static com.android.server.wm.TaskFragment.EMBEDDING_ALLOWED;
|
||||||
@@ -38,6 +44,7 @@ import android.view.RemoteAnimationDefinition;
|
|||||||
import android.window.ITaskFragmentOrganizer;
|
import android.window.ITaskFragmentOrganizer;
|
||||||
import android.window.ITaskFragmentOrganizerController;
|
import android.window.ITaskFragmentOrganizerController;
|
||||||
import android.window.TaskFragmentInfo;
|
import android.window.TaskFragmentInfo;
|
||||||
|
import android.window.TaskFragmentTransaction;
|
||||||
|
|
||||||
import com.android.internal.protolog.common.ProtoLog;
|
import com.android.internal.protolog.common.ProtoLog;
|
||||||
|
|
||||||
@@ -68,6 +75,11 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
|
|||||||
private final ArrayList<PendingTaskFragmentEvent> mPendingTaskFragmentEvents =
|
private final ArrayList<PendingTaskFragmentEvent> mPendingTaskFragmentEvents =
|
||||||
new ArrayList<>();
|
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) {
|
TaskFragmentOrganizerController(ActivityTaskManagerService atm) {
|
||||||
mAtmService = atm;
|
mAtmService = atm;
|
||||||
mGlobalLock = atm.mGlobalLock;
|
mGlobalLock = atm.mGlobalLock;
|
||||||
@@ -145,107 +157,138 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
|
|||||||
mOrganizer.asBinder().unlinkToDeath(this, 0 /*flags*/);
|
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());
|
ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "TaskFragment appeared name=%s", tf.getName());
|
||||||
final TaskFragmentInfo info = tf.getTaskFragmentInfo();
|
final TaskFragmentInfo info = tf.getTaskFragmentInfo();
|
||||||
try {
|
|
||||||
mOrganizer.onTaskFragmentAppeared(info);
|
|
||||||
mLastSentTaskFragmentInfos.put(tf, info);
|
|
||||||
tf.mTaskFragmentAppearedSent = true;
|
tf.mTaskFragmentAppearedSent = true;
|
||||||
} catch (RemoteException e) {
|
mLastSentTaskFragmentInfos.put(tf, info);
|
||||||
Slog.d(TAG, "Exception sending onTaskFragmentAppeared callback", e);
|
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());
|
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;
|
tf.mTaskFragmentAppearedSent = false;
|
||||||
mLastSentTaskFragmentInfos.remove(tf);
|
mLastSentTaskFragmentInfos.remove(tf);
|
||||||
mLastSentTaskFragmentParentConfigs.remove(tf);
|
mLastSentTaskFragmentParentConfigs.remove(tf);
|
||||||
|
return new TaskFragmentTransaction.Change(TYPE_TASK_FRAGMENT_VANISHED)
|
||||||
|
.setTaskFragmentToken(tf.getFragmentToken())
|
||||||
|
.setTaskFragmentInfo(tf.getTaskFragmentInfo());
|
||||||
}
|
}
|
||||||
|
|
||||||
void onTaskFragmentInfoChanged(TaskFragment tf) {
|
@Nullable
|
||||||
// Parent config may have changed. The controller will check if there is any important
|
TaskFragmentTransaction.Change prepareTaskFragmentInfoChanged(
|
||||||
// config change for the organizer.
|
@NonNull TaskFragment tf) {
|
||||||
onTaskFragmentParentInfoChanged(tf);
|
|
||||||
|
|
||||||
// Check if the info is different from the last reported info.
|
// Check if the info is different from the last reported info.
|
||||||
final TaskFragmentInfo info = tf.getTaskFragmentInfo();
|
final TaskFragmentInfo info = tf.getTaskFragmentInfo();
|
||||||
final TaskFragmentInfo lastInfo = mLastSentTaskFragmentInfos.get(tf);
|
final TaskFragmentInfo lastInfo = mLastSentTaskFragmentInfos.get(tf);
|
||||||
if (info.equalsForTaskFragmentOrganizer(lastInfo) && configurationsAreEqualForOrganizer(
|
if (info.equalsForTaskFragmentOrganizer(lastInfo) && configurationsAreEqualForOrganizer(
|
||||||
info.getConfiguration(), lastInfo.getConfiguration())) {
|
info.getConfiguration(), lastInfo.getConfiguration())) {
|
||||||
return;
|
// Parent config may have changed. The controller will check if there is any
|
||||||
}
|
// important config change for the organizer.
|
||||||
ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "TaskFragment info changed name=%s",
|
return prepareTaskFragmentParentInfoChanged(tf);
|
||||||
tf.getName());
|
|
||||||
try {
|
|
||||||
mOrganizer.onTaskFragmentInfoChanged(info);
|
|
||||||
mLastSentTaskFragmentInfos.put(tf, info);
|
|
||||||
} catch (RemoteException e) {
|
|
||||||
Slog.d(TAG, "Exception sending onTaskFragmentInfoChanged callback", e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void onTaskFragmentParentInfoChanged(TaskFragment tf) {
|
ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "TaskFragment info changed name=%s",
|
||||||
// Check if the parent info is different from the last reported parent info.
|
tf.getName());
|
||||||
if (tf.getParent() == null || tf.getParent().asTask() == null) {
|
mLastSentTaskFragmentInfos.put(tf, info);
|
||||||
mLastSentTaskFragmentParentConfigs.remove(tf);
|
final TaskFragmentTransaction.Change change =
|
||||||
return;
|
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());
|
||||||
}
|
}
|
||||||
final Task parent = tf.getParent().asTask();
|
return change;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
TaskFragmentTransaction.Change prepareTaskFragmentParentInfoChanged(
|
||||||
|
@NonNull TaskFragment tf) {
|
||||||
|
if (!shouldSendTaskFragmentParentInfoChanged(tf)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
final Task parent = tf.getTask();
|
||||||
final Configuration parentConfig = parent.getConfiguration();
|
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,
|
ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER,
|
||||||
"TaskFragment parent info changed name=%s parentTaskId=%d",
|
"TaskFragment parent info changed name=%s parentTaskId=%d",
|
||||||
tf.getName(), parent.mTaskId);
|
tf.getName(), parent.mTaskId);
|
||||||
try {
|
|
||||||
mOrganizer.onTaskFragmentParentInfoChanged(tf.getFragmentToken(), parentConfig);
|
|
||||||
mLastSentTaskFragmentParentConfigs.put(tf, new Configuration(parentConfig));
|
mLastSentTaskFragmentParentConfigs.put(tf, new Configuration(parentConfig));
|
||||||
} catch (RemoteException e) {
|
return new TaskFragmentTransaction.Change(TYPE_TASK_FRAGMENT_PARENT_INFO_CHANGED)
|
||||||
Slog.d(TAG, "Exception sending onTaskFragmentParentInfoChanged callback", e);
|
.setTaskFragmentToken(tf.getFragmentToken())
|
||||||
}
|
.setTaskId(parent.mTaskId)
|
||||||
|
.setTaskConfiguration(parent.getConfiguration());
|
||||||
}
|
}
|
||||||
|
|
||||||
void onTaskFragmentError(IBinder errorCallbackToken, @Nullable TaskFragment taskFragment,
|
/** Whether the system should report TaskFragment parent info changed to the organizer. */
|
||||||
int opType, Throwable exception) {
|
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,
|
ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER,
|
||||||
"Sending TaskFragment error exception=%s", exception.toString());
|
"Sending TaskFragment error exception=%s", exception.toString());
|
||||||
final TaskFragmentInfo info =
|
final TaskFragmentInfo info =
|
||||||
taskFragment != null ? taskFragment.getTaskFragmentInfo() : null;
|
taskFragment != null ? taskFragment.getTaskFragmentInfo() : null;
|
||||||
final Bundle errorBundle = putErrorInfoInBundle(exception, info, opType);
|
final Bundle errorBundle = putErrorInfoInBundle(exception, info, opType);
|
||||||
try {
|
return new TaskFragmentTransaction.Change(TYPE_TASK_FRAGMENT_ERROR)
|
||||||
mOrganizer.onTaskFragmentError(errorCallbackToken, errorBundle);
|
.setErrorCallbackToken(errorCallbackToken)
|
||||||
} catch (RemoteException e) {
|
.setErrorBundle(errorBundle);
|
||||||
Slog.d(TAG, "Exception sending onTaskFragmentError callback", e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void onActivityReparentToTask(ActivityRecord activity) {
|
@Nullable
|
||||||
|
TaskFragmentTransaction.Change prepareActivityReparentToTask(
|
||||||
|
@NonNull ActivityRecord activity) {
|
||||||
if (activity.finishing) {
|
if (activity.finishing) {
|
||||||
Slog.d(TAG, "Reparent activity=" + activity.token + " is finishing");
|
Slog.d(TAG, "Reparent activity=" + activity.token + " is finishing");
|
||||||
return;
|
return null;
|
||||||
}
|
}
|
||||||
final Task task = activity.getTask();
|
final Task task = activity.getTask();
|
||||||
if (task == null || task.effectiveUid != mOrganizerUid) {
|
if (task == null || task.effectiveUid != mOrganizerUid) {
|
||||||
Slog.d(TAG, "Reparent activity=" + activity.token
|
Slog.d(TAG, "Reparent activity=" + activity.token
|
||||||
+ " is not in a task belong to the organizer app.");
|
+ " is not in a task belong to the organizer app.");
|
||||||
return;
|
return null;
|
||||||
}
|
}
|
||||||
if (task.isAllowedToEmbedActivity(activity, mOrganizerUid) != EMBEDDING_ALLOWED) {
|
if (task.isAllowedToEmbedActivity(activity, mOrganizerUid) != EMBEDDING_ALLOWED) {
|
||||||
Slog.d(TAG, "Reparent activity=" + activity.token
|
Slog.d(TAG, "Reparent activity=" + activity.token
|
||||||
+ " is not allowed to be embedded.");
|
+ " is not allowed to be embedded.");
|
||||||
return;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
final IBinder activityToken;
|
final IBinder activityToken;
|
||||||
@@ -268,11 +311,10 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
|
|||||||
}
|
}
|
||||||
ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Activity=%s reparent to taskId=%d",
|
ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Activity=%s reparent to taskId=%d",
|
||||||
activity.token, task.mTaskId);
|
activity.token, task.mTaskId);
|
||||||
try {
|
return new TaskFragmentTransaction.Change(TYPE_ACTIVITY_REPARENT_TO_TASK)
|
||||||
mOrganizer.onActivityReparentToTask(task.mTaskId, activity.intent, activityToken);
|
.setTaskId(task.mTaskId)
|
||||||
} catch (RemoteException e) {
|
.setActivityIntent(activity.intent)
|
||||||
Slog.d(TAG, "Exception sending onActivityReparentToTask callback", e);
|
.setActivityToken(activityToken);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -375,7 +417,7 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
|
|||||||
*/
|
*/
|
||||||
@Nullable
|
@Nullable
|
||||||
public RemoteAnimationDefinition getRemoteAnimationDefinition(
|
public RemoteAnimationDefinition getRemoteAnimationDefinition(
|
||||||
ITaskFragmentOrganizer organizer, int taskId) {
|
@NonNull ITaskFragmentOrganizer organizer, int taskId) {
|
||||||
synchronized (mGlobalLock) {
|
synchronized (mGlobalLock) {
|
||||||
final TaskFragmentOrganizerState organizerState =
|
final TaskFragmentOrganizerState organizerState =
|
||||||
mTaskFragmentOrganizerState.get(organizer.asBinder());
|
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);
|
final TaskFragmentOrganizerState state = validateAndGetState(organizer);
|
||||||
return state.mOrganizerUid;
|
return state.mOrganizerUid;
|
||||||
}
|
}
|
||||||
|
|
||||||
void onTaskFragmentAppeared(ITaskFragmentOrganizer organizer, TaskFragment taskFragment) {
|
void onTaskFragmentAppeared(@NonNull ITaskFragmentOrganizer organizer,
|
||||||
|
@NonNull TaskFragment taskFragment) {
|
||||||
final TaskFragmentOrganizerState state = validateAndGetState(organizer);
|
final TaskFragmentOrganizerState state = validateAndGetState(organizer);
|
||||||
if (!state.addTaskFragment(taskFragment)) {
|
if (!state.addTaskFragment(taskFragment)) {
|
||||||
return;
|
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,
|
handleTaskFragmentInfoChanged(organizer, taskFragment,
|
||||||
PendingTaskFragmentEvent.EVENT_INFO_CHANGED);
|
PendingTaskFragmentEvent.EVENT_INFO_CHANGED);
|
||||||
}
|
}
|
||||||
|
|
||||||
void onTaskFragmentParentInfoChanged(ITaskFragmentOrganizer organizer,
|
void onTaskFragmentParentInfoChanged(@NonNull ITaskFragmentOrganizer organizer,
|
||||||
TaskFragment taskFragment) {
|
@NonNull TaskFragment taskFragment) {
|
||||||
handleTaskFragmentInfoChanged(organizer, taskFragment,
|
handleTaskFragmentInfoChanged(organizer, taskFragment,
|
||||||
PendingTaskFragmentEvent.EVENT_PARENT_INFO_CHANGED);
|
PendingTaskFragmentEvent.EVENT_PARENT_INFO_CHANGED);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleTaskFragmentInfoChanged(ITaskFragmentOrganizer organizer,
|
private void handleTaskFragmentInfoChanged(@NonNull ITaskFragmentOrganizer organizer,
|
||||||
TaskFragment taskFragment, int eventType) {
|
@NonNull TaskFragment taskFragment, int eventType) {
|
||||||
validateAndGetState(organizer);
|
validateAndGetState(organizer);
|
||||||
if (!taskFragment.mTaskFragmentAppearedSent) {
|
if (!taskFragment.mTaskFragmentAppearedSent) {
|
||||||
// Skip if TaskFragment still not appeared.
|
// Skip if TaskFragment still not appeared.
|
||||||
@@ -444,7 +488,8 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
|
|||||||
mPendingTaskFragmentEvents.add(pendingEvent);
|
mPendingTaskFragmentEvents.add(pendingEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
void onTaskFragmentVanished(ITaskFragmentOrganizer organizer, TaskFragment taskFragment) {
|
void onTaskFragmentVanished(@NonNull ITaskFragmentOrganizer organizer,
|
||||||
|
@NonNull TaskFragment taskFragment) {
|
||||||
final TaskFragmentOrganizerState state = validateAndGetState(organizer);
|
final TaskFragmentOrganizerState state = validateAndGetState(organizer);
|
||||||
for (int i = mPendingTaskFragmentEvents.size() - 1; i >= 0; i--) {
|
for (int i = mPendingTaskFragmentEvents.size() - 1; i >= 0; i--) {
|
||||||
PendingTaskFragmentEvent entry = mPendingTaskFragmentEvents.get(i);
|
PendingTaskFragmentEvent entry = mPendingTaskFragmentEvents.get(i);
|
||||||
@@ -467,8 +512,9 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
|
|||||||
state.removeTaskFragment(taskFragment);
|
state.removeTaskFragment(taskFragment);
|
||||||
}
|
}
|
||||||
|
|
||||||
void onTaskFragmentError(ITaskFragmentOrganizer organizer, IBinder errorCallbackToken,
|
void onTaskFragmentError(@NonNull ITaskFragmentOrganizer organizer,
|
||||||
TaskFragment taskFragment, int opType, Throwable exception) {
|
@Nullable IBinder errorCallbackToken, @Nullable TaskFragment taskFragment,
|
||||||
|
int opType, @NonNull Throwable exception) {
|
||||||
validateAndGetState(organizer);
|
validateAndGetState(organizer);
|
||||||
Slog.w(TAG, "onTaskFragmentError ", exception);
|
Slog.w(TAG, "onTaskFragmentError ", exception);
|
||||||
final PendingTaskFragmentEvent pendingEvent = new PendingTaskFragmentEvent.Builder(
|
final PendingTaskFragmentEvent pendingEvent = new PendingTaskFragmentEvent.Builder(
|
||||||
@@ -483,7 +529,7 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
|
|||||||
mAtmService.mWindowManager.mWindowPlacerLocked.requestTraversal();
|
mAtmService.mWindowManager.mWindowPlacerLocked.requestTraversal();
|
||||||
}
|
}
|
||||||
|
|
||||||
void onActivityReparentToTask(ActivityRecord activity) {
|
void onActivityReparentToTask(@NonNull ActivityRecord activity) {
|
||||||
final ITaskFragmentOrganizer organizer;
|
final ITaskFragmentOrganizer organizer;
|
||||||
if (activity.mLastTaskFragmentOrganizerBeforePip != null) {
|
if (activity.mLastTaskFragmentOrganizerBeforePip != null) {
|
||||||
// If the activity is previously embedded in an organized TaskFragment.
|
// If the activity is previously embedded in an organized TaskFragment.
|
||||||
@@ -515,11 +561,11 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
|
|||||||
mPendingTaskFragmentEvents.add(pendingEvent);
|
mPendingTaskFragmentEvents.add(pendingEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean isOrganizerRegistered(ITaskFragmentOrganizer organizer) {
|
boolean isOrganizerRegistered(@NonNull ITaskFragmentOrganizer organizer) {
|
||||||
return mTaskFragmentOrganizerState.containsKey(organizer.asBinder());
|
return mTaskFragmentOrganizerState.containsKey(organizer.asBinder());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void removeOrganizer(ITaskFragmentOrganizer organizer) {
|
private void removeOrganizer(@NonNull ITaskFragmentOrganizer organizer) {
|
||||||
final TaskFragmentOrganizerState state = validateAndGetState(organizer);
|
final TaskFragmentOrganizerState state = validateAndGetState(organizer);
|
||||||
// remove all of the children of the organized TaskFragment
|
// remove all of the children of the organized TaskFragment
|
||||||
state.dispose();
|
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
|
* we wouldn't register {@link DeathRecipient} for the organizer, and might not remove the
|
||||||
* {@link TaskFragment} after the organizer process died.
|
* {@link TaskFragment} after the organizer process died.
|
||||||
*/
|
*/
|
||||||
private TaskFragmentOrganizerState validateAndGetState(ITaskFragmentOrganizer organizer) {
|
@NonNull
|
||||||
|
private TaskFragmentOrganizerState validateAndGetState(
|
||||||
|
@NonNull ITaskFragmentOrganizer organizer) {
|
||||||
final TaskFragmentOrganizerState state =
|
final TaskFragmentOrganizerState state =
|
||||||
mTaskFragmentOrganizerState.get(organizer.asBinder());
|
mTaskFragmentOrganizerState.get(organizer.asBinder());
|
||||||
if (state == null) {
|
if (state == null) {
|
||||||
@@ -672,7 +720,7 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private PendingTaskFragmentEvent getLastPendingLifecycleEvent(TaskFragment tf) {
|
private PendingTaskFragmentEvent getLastPendingLifecycleEvent(@NonNull TaskFragment tf) {
|
||||||
for (int i = mPendingTaskFragmentEvents.size() - 1; i >= 0; i--) {
|
for (int i = mPendingTaskFragmentEvents.size() - 1; i >= 0; i--) {
|
||||||
PendingTaskFragmentEvent entry = mPendingTaskFragmentEvents.get(i);
|
PendingTaskFragmentEvent entry = mPendingTaskFragmentEvents.get(i);
|
||||||
if (tf == entry.mTaskFragment && entry.isLifecycleEvent()) {
|
if (tf == entry.mTaskFragment && entry.isLifecycleEvent()) {
|
||||||
@@ -683,7 +731,7 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private PendingTaskFragmentEvent getPendingTaskFragmentEvent(TaskFragment taskFragment,
|
private PendingTaskFragmentEvent getPendingTaskFragmentEvent(@NonNull TaskFragment taskFragment,
|
||||||
int type) {
|
int type) {
|
||||||
for (int i = mPendingTaskFragmentEvents.size() - 1; i >= 0; i--) {
|
for (int i = mPendingTaskFragmentEvents.size() - 1; i >= 0; i--) {
|
||||||
PendingTaskFragmentEvent entry = mPendingTaskFragmentEvents.get(i);
|
PendingTaskFragmentEvent entry = mPendingTaskFragmentEvents.get(i);
|
||||||
@@ -731,16 +779,36 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
|
|||||||
candidateEvents.add(event);
|
candidateEvents.add(event);
|
||||||
}
|
}
|
||||||
final int numEvents = candidateEvents.size();
|
final int numEvents = candidateEvents.size();
|
||||||
for (int i = 0; i < numEvents; i++) {
|
if (numEvents == 0) {
|
||||||
dispatchEvent(candidateEvents.get(i));
|
return;
|
||||||
}
|
|
||||||
if (numEvents > 0) {
|
|
||||||
mPendingTaskFragmentEvents.removeAll(candidateEvents);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isTaskVisible(Task task, ArrayList<Task> knownVisibleTasks,
|
mTmpOrganizerToTransactionMap.clear();
|
||||||
ArrayList<Task> knownInvisibleTasks) {
|
mTmpOrganizerList.clear();
|
||||||
|
for (int i = 0; i < numEvents; 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));
|
||||||
|
}
|
||||||
|
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(@NonNull Task task,
|
||||||
|
@NonNull ArrayList<Task> knownVisibleTasks,
|
||||||
|
@NonNull ArrayList<Task> knownInvisibleTasks) {
|
||||||
if (knownVisibleTasks.contains(task)) {
|
if (knownVisibleTasks.contains(task)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -756,44 +824,57 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void dispatchPendingInfoChangedEvent(TaskFragment taskFragment) {
|
void dispatchPendingInfoChangedEvent(@NonNull TaskFragment taskFragment) {
|
||||||
PendingTaskFragmentEvent event = getPendingTaskFragmentEvent(taskFragment,
|
final PendingTaskFragmentEvent event = getPendingTaskFragmentEvent(taskFragment,
|
||||||
PendingTaskFragmentEvent.EVENT_INFO_CHANGED);
|
PendingTaskFragmentEvent.EVENT_INFO_CHANGED);
|
||||||
if (event == null) {
|
if (event == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
dispatchEvent(event);
|
final TaskFragmentTransaction transaction = new TaskFragmentTransaction();
|
||||||
|
transaction.addChange(prepareChange(event));
|
||||||
|
dispatchTransactionInfo(event.mTaskFragmentOrg, transaction);
|
||||||
mPendingTaskFragmentEvents.remove(event);
|
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 ITaskFragmentOrganizer taskFragmentOrg = event.mTaskFragmentOrg;
|
||||||
final TaskFragment taskFragment = event.mTaskFragment;
|
final TaskFragment taskFragment = event.mTaskFragment;
|
||||||
final TaskFragmentOrganizerState state =
|
final TaskFragmentOrganizerState state =
|
||||||
mTaskFragmentOrganizerState.get(taskFragmentOrg.asBinder());
|
mTaskFragmentOrganizerState.get(taskFragmentOrg.asBinder());
|
||||||
if (state == null) {
|
if (state == null) {
|
||||||
return;
|
return null;
|
||||||
}
|
}
|
||||||
switch (event.mEventType) {
|
switch (event.mEventType) {
|
||||||
case PendingTaskFragmentEvent.EVENT_APPEARED:
|
case PendingTaskFragmentEvent.EVENT_APPEARED:
|
||||||
state.onTaskFragmentAppeared(taskFragment);
|
return state.prepareTaskFragmentAppeared(taskFragment);
|
||||||
break;
|
|
||||||
case PendingTaskFragmentEvent.EVENT_VANISHED:
|
case PendingTaskFragmentEvent.EVENT_VANISHED:
|
||||||
state.onTaskFragmentVanished(taskFragment);
|
return state.prepareTaskFragmentVanished(taskFragment);
|
||||||
break;
|
|
||||||
case PendingTaskFragmentEvent.EVENT_INFO_CHANGED:
|
case PendingTaskFragmentEvent.EVENT_INFO_CHANGED:
|
||||||
state.onTaskFragmentInfoChanged(taskFragment);
|
return state.prepareTaskFragmentInfoChanged(taskFragment);
|
||||||
break;
|
|
||||||
case PendingTaskFragmentEvent.EVENT_PARENT_INFO_CHANGED:
|
case PendingTaskFragmentEvent.EVENT_PARENT_INFO_CHANGED:
|
||||||
state.onTaskFragmentParentInfoChanged(taskFragment);
|
return state.prepareTaskFragmentParentInfoChanged(taskFragment);
|
||||||
break;
|
|
||||||
case PendingTaskFragmentEvent.EVENT_ERROR:
|
case PendingTaskFragmentEvent.EVENT_ERROR:
|
||||||
state.onTaskFragmentError(event.mErrorCallbackToken, taskFragment, event.mOpType,
|
return state.prepareTaskFragmentError(event.mErrorCallbackToken, taskFragment,
|
||||||
event.mException);
|
event.mOpType, event.mException);
|
||||||
break;
|
|
||||||
case PendingTaskFragmentEvent.EVENT_ACTIVITY_REPARENT_TO_TASK:
|
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 Task parent = mock(Task.class);
|
||||||
final Configuration parentConfig = new Configuration();
|
final Configuration parentConfig = new Configuration();
|
||||||
parentConfig.smallestScreenWidthDp = 10;
|
parentConfig.smallestScreenWidthDp = 10;
|
||||||
doReturn(parent).when(mTaskFragment).getParent();
|
doReturn(parent).when(mTaskFragment).getTask();
|
||||||
doReturn(parentConfig).when(parent).getConfiguration();
|
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;
|
mTaskFragment.mTaskFragmentAppearedSent = true;
|
||||||
mController.onTaskFragmentParentInfoChanged(
|
mController.onTaskFragmentParentInfoChanged(
|
||||||
|
|||||||
Reference in New Issue
Block a user