Merge "Pass Task configuration changed for all TaskFragments at once" into tm-qpr-dev
This commit is contained in:
@@ -32,8 +32,10 @@ import android.content.res.Configuration;
|
|||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
import android.os.RemoteException;
|
import android.os.RemoteException;
|
||||||
|
import android.util.SparseArray;
|
||||||
import android.view.RemoteAnimationDefinition;
|
import android.view.RemoteAnimationDefinition;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
|
|
||||||
@@ -72,6 +74,12 @@ public class TaskFragmentOrganizer extends WindowOrganizer {
|
|||||||
*/
|
*/
|
||||||
private final Executor mExecutor;
|
private final Executor mExecutor;
|
||||||
|
|
||||||
|
// TODO(b/240519866): doing so to keep CTS compatibility. Remove in the next release.
|
||||||
|
/** Map from Task id to client tokens of TaskFragments in the Task. */
|
||||||
|
private final SparseArray<List<IBinder>> mTaskIdToFragmentTokens = new SparseArray<>();
|
||||||
|
/** Map from Task id to Task configuration. */
|
||||||
|
private final SparseArray<Configuration> mTaskIdToConfigurations = new SparseArray<>();
|
||||||
|
|
||||||
public TaskFragmentOrganizer(@NonNull Executor executor) {
|
public TaskFragmentOrganizer(@NonNull Executor executor) {
|
||||||
mExecutor = executor;
|
mExecutor = executor;
|
||||||
}
|
}
|
||||||
@@ -160,6 +168,27 @@ public class TaskFragmentOrganizer extends WindowOrganizer {
|
|||||||
public void onTaskFragmentParentInfoChanged(
|
public void onTaskFragmentParentInfoChanged(
|
||||||
@NonNull IBinder fragmentToken, @NonNull Configuration parentConfig) {}
|
@NonNull IBinder fragmentToken, @NonNull Configuration parentConfig) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
public void onTaskFragmentParentInfoChanged(int taskId, @NonNull Configuration parentConfig) {
|
||||||
|
// TODO(b/240519866): doing so to keep CTS compatibility. Remove in the next release.
|
||||||
|
final List<IBinder> tokens = mTaskIdToFragmentTokens.get(taskId);
|
||||||
|
if (tokens == null || tokens.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (int i = tokens.size() - 1; i >= 0; i--) {
|
||||||
|
onTaskFragmentParentInfoChanged(tokens.get(i), parentConfig);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when the {@link WindowContainerTransaction} created with
|
* Called when the {@link WindowContainerTransaction} created with
|
||||||
* {@link WindowContainerTransaction#setErrorCallbackToken(IBinder)} failed on the server side.
|
* {@link WindowContainerTransaction#setErrorCallbackToken(IBinder)} failed on the server side.
|
||||||
@@ -221,34 +250,43 @@ public class TaskFragmentOrganizer extends WindowOrganizer {
|
|||||||
final List<TaskFragmentTransaction.Change> changes = transaction.getChanges();
|
final List<TaskFragmentTransaction.Change> changes = transaction.getChanges();
|
||||||
for (TaskFragmentTransaction.Change change : changes) {
|
for (TaskFragmentTransaction.Change change : changes) {
|
||||||
// TODO(b/240519866): apply all changes in one WCT.
|
// TODO(b/240519866): apply all changes in one WCT.
|
||||||
|
final int taskId = change.getTaskId();
|
||||||
switch (change.getType()) {
|
switch (change.getType()) {
|
||||||
case TYPE_TASK_FRAGMENT_APPEARED:
|
case TYPE_TASK_FRAGMENT_APPEARED:
|
||||||
onTaskFragmentAppeared(change.getTaskFragmentInfo());
|
// TODO(b/240519866): doing so to keep CTS compatibility. Remove in the next
|
||||||
if (change.getTaskConfiguration() != null) {
|
// release.
|
||||||
// TODO(b/240519866): convert to pass TaskConfiguration for all TFs in the
|
if (!mTaskIdToFragmentTokens.contains(taskId)) {
|
||||||
// same Task
|
mTaskIdToFragmentTokens.put(taskId, new ArrayList<>());
|
||||||
onTaskFragmentParentInfoChanged(
|
|
||||||
change.getTaskFragmentToken(),
|
|
||||||
change.getTaskConfiguration());
|
|
||||||
}
|
}
|
||||||
|
mTaskIdToFragmentTokens.get(taskId).add(change.getTaskFragmentToken());
|
||||||
|
onTaskFragmentParentInfoChanged(change.getTaskFragmentToken(),
|
||||||
|
mTaskIdToConfigurations.get(taskId));
|
||||||
|
|
||||||
|
onTaskFragmentAppeared(change.getTaskFragmentInfo());
|
||||||
break;
|
break;
|
||||||
case TYPE_TASK_FRAGMENT_INFO_CHANGED:
|
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());
|
onTaskFragmentInfoChanged(change.getTaskFragmentInfo());
|
||||||
break;
|
break;
|
||||||
case TYPE_TASK_FRAGMENT_VANISHED:
|
case TYPE_TASK_FRAGMENT_VANISHED:
|
||||||
|
// TODO(b/240519866): doing so to keep CTS compatibility. Remove in the next
|
||||||
|
// release.
|
||||||
|
if (mTaskIdToFragmentTokens.contains(taskId)) {
|
||||||
|
final List<IBinder> tokens = mTaskIdToFragmentTokens.get(taskId);
|
||||||
|
tokens.remove(change.getTaskFragmentToken());
|
||||||
|
if (tokens.isEmpty()) {
|
||||||
|
mTaskIdToFragmentTokens.remove(taskId);
|
||||||
|
mTaskIdToConfigurations.remove(taskId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
onTaskFragmentVanished(change.getTaskFragmentInfo());
|
onTaskFragmentVanished(change.getTaskFragmentInfo());
|
||||||
break;
|
break;
|
||||||
case TYPE_TASK_FRAGMENT_PARENT_INFO_CHANGED:
|
case TYPE_TASK_FRAGMENT_PARENT_INFO_CHANGED:
|
||||||
onTaskFragmentParentInfoChanged(
|
// TODO(b/240519866): doing so to keep CTS compatibility. Remove in the next
|
||||||
change.getTaskFragmentToken(),
|
// release.
|
||||||
change.getTaskConfiguration());
|
mTaskIdToConfigurations.put(taskId, change.getTaskConfiguration());
|
||||||
|
|
||||||
|
onTaskFragmentParentInfoChanged(taskId, change.getTaskConfiguration());
|
||||||
break;
|
break;
|
||||||
case TYPE_TASK_FRAGMENT_ERROR:
|
case TYPE_TASK_FRAGMENT_ERROR:
|
||||||
final Bundle errorBundle = change.getErrorBundle();
|
final Bundle errorBundle = change.getErrorBundle();
|
||||||
|
|||||||
@@ -51,12 +51,6 @@ class JetpackTaskFragmentOrganizer extends TaskFragmentOrganizer {
|
|||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
final Map<IBinder, TaskFragmentInfo> mFragmentInfos = new ArrayMap<>();
|
final Map<IBinder, TaskFragmentInfo> mFragmentInfos = new ArrayMap<>();
|
||||||
|
|
||||||
/**
|
|
||||||
* Mapping from the client assigned unique token to the TaskFragment parent
|
|
||||||
* {@link Configuration}.
|
|
||||||
*/
|
|
||||||
final Map<IBinder, Configuration> mFragmentParentConfigs = new ArrayMap<>();
|
|
||||||
|
|
||||||
private final TaskFragmentCallback mCallback;
|
private final TaskFragmentCallback mCallback;
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
TaskFragmentAnimationController mAnimationController;
|
TaskFragmentAnimationController mAnimationController;
|
||||||
@@ -68,8 +62,7 @@ class JetpackTaskFragmentOrganizer extends TaskFragmentOrganizer {
|
|||||||
void onTaskFragmentAppeared(@NonNull TaskFragmentInfo taskFragmentInfo);
|
void onTaskFragmentAppeared(@NonNull TaskFragmentInfo taskFragmentInfo);
|
||||||
void onTaskFragmentInfoChanged(@NonNull TaskFragmentInfo taskFragmentInfo);
|
void onTaskFragmentInfoChanged(@NonNull TaskFragmentInfo taskFragmentInfo);
|
||||||
void onTaskFragmentVanished(@NonNull TaskFragmentInfo taskFragmentInfo);
|
void onTaskFragmentVanished(@NonNull TaskFragmentInfo taskFragmentInfo);
|
||||||
void onTaskFragmentParentInfoChanged(@NonNull IBinder fragmentToken,
|
void onTaskFragmentParentInfoChanged(int taskId, @NonNull Configuration parentConfig);
|
||||||
@NonNull Configuration parentConfig);
|
|
||||||
void onActivityReparentToTask(int taskId, @NonNull Intent activityIntent,
|
void onActivityReparentToTask(int taskId, @NonNull Intent activityIntent,
|
||||||
@NonNull IBinder activityToken);
|
@NonNull IBinder activityToken);
|
||||||
void onTaskFragmentError(@Nullable TaskFragmentInfo taskFragmentInfo, int opType);
|
void onTaskFragmentError(@Nullable TaskFragmentInfo taskFragmentInfo, int opType);
|
||||||
@@ -300,7 +293,6 @@ class JetpackTaskFragmentOrganizer extends TaskFragmentOrganizer {
|
|||||||
@Override
|
@Override
|
||||||
public void onTaskFragmentVanished(@NonNull TaskFragmentInfo taskFragmentInfo) {
|
public void onTaskFragmentVanished(@NonNull TaskFragmentInfo taskFragmentInfo) {
|
||||||
mFragmentInfos.remove(taskFragmentInfo.getFragmentToken());
|
mFragmentInfos.remove(taskFragmentInfo.getFragmentToken());
|
||||||
mFragmentParentConfigs.remove(taskFragmentInfo.getFragmentToken());
|
|
||||||
|
|
||||||
if (mCallback != null) {
|
if (mCallback != null) {
|
||||||
mCallback.onTaskFragmentVanished(taskFragmentInfo);
|
mCallback.onTaskFragmentVanished(taskFragmentInfo);
|
||||||
@@ -308,12 +300,9 @@ class JetpackTaskFragmentOrganizer extends TaskFragmentOrganizer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onTaskFragmentParentInfoChanged(
|
public void onTaskFragmentParentInfoChanged(int taskId, @NonNull Configuration parentConfig) {
|
||||||
@NonNull IBinder fragmentToken, @NonNull Configuration parentConfig) {
|
|
||||||
mFragmentParentConfigs.put(fragmentToken, parentConfig);
|
|
||||||
|
|
||||||
if (mCallback != null) {
|
if (mCallback != null) {
|
||||||
mCallback.onTaskFragmentParentInfoChanged(fragmentToken, parentConfig);
|
mCallback.onTaskFragmentParentInfoChanged(taskId, parentConfig);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -155,6 +155,9 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
|
|||||||
container.setInfo(taskFragmentInfo);
|
container.setInfo(taskFragmentInfo);
|
||||||
if (container.isFinished()) {
|
if (container.isFinished()) {
|
||||||
mPresenter.cleanupContainer(container, false /* shouldFinishDependent */);
|
mPresenter.cleanupContainer(container, false /* shouldFinishDependent */);
|
||||||
|
} else {
|
||||||
|
// Update with the latest Task configuration.
|
||||||
|
mPresenter.updateContainer(container);
|
||||||
}
|
}
|
||||||
updateCallbackIfNecessary();
|
updateCallbackIfNecessary();
|
||||||
}
|
}
|
||||||
@@ -233,19 +236,30 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onTaskFragmentParentInfoChanged(@NonNull IBinder fragmentToken,
|
public void onTaskFragmentParentInfoChanged(int taskId, @NonNull Configuration parentConfig) {
|
||||||
@NonNull Configuration parentConfig) {
|
|
||||||
synchronized (mLock) {
|
synchronized (mLock) {
|
||||||
final TaskFragmentContainer container = getContainer(fragmentToken);
|
onTaskConfigurationChanged(taskId, parentConfig);
|
||||||
if (container != null) {
|
|
||||||
onTaskConfigurationChanged(container.getTaskId(), parentConfig);
|
|
||||||
if (isInPictureInPicture(parentConfig)) {
|
if (isInPictureInPicture(parentConfig)) {
|
||||||
// No need to update presentation in PIP until the Task exit PIP.
|
// No need to update presentation in PIP until the Task exit PIP.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
mPresenter.updateContainer(container);
|
final TaskContainer taskContainer = getTaskContainer(taskId);
|
||||||
updateCallbackIfNecessary();
|
if (taskContainer == null || taskContainer.isEmpty()) {
|
||||||
|
Log.e(TAG, "onTaskFragmentParentInfoChanged on empty Task id=" + taskId);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
// Update all TaskFragments in the Task. Make a copy of the list since some may be
|
||||||
|
// removed on updating.
|
||||||
|
final List<TaskFragmentContainer> containers =
|
||||||
|
new ArrayList<>(taskContainer.mContainers);
|
||||||
|
for (int i = containers.size() - 1; i >= 0; i--) {
|
||||||
|
final TaskFragmentContainer container = containers.get(i);
|
||||||
|
// Wait until onTaskFragmentAppeared to update new container.
|
||||||
|
if (!container.isFinished() && !container.isWaitingActivityAppear()) {
|
||||||
|
mPresenter.updateContainer(container);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
updateCallbackIfNecessary();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -887,11 +887,12 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks {
|
|||||||
|
|
||||||
logIfTransactionTooLarge(r.intent, r.getSavedState());
|
logIfTransactionTooLarge(r.intent, r.getSavedState());
|
||||||
|
|
||||||
if (r.isEmbedded()) {
|
final TaskFragment organizedTaskFragment = r.getOrganizedTaskFragment();
|
||||||
|
if (organizedTaskFragment != null) {
|
||||||
// Sending TaskFragmentInfo to client to ensure the info is updated before
|
// Sending TaskFragmentInfo to client to ensure the info is updated before
|
||||||
// the activity creation.
|
// the activity creation.
|
||||||
mService.mTaskFragmentOrganizerController.dispatchPendingInfoChangedEvent(
|
mService.mTaskFragmentOrganizerController.dispatchPendingInfoChangedEvent(
|
||||||
r.getOrganizedTaskFragment());
|
organizedTaskFragment);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create activity launch transaction.
|
// Create activity launch transaction.
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package com.android.server.wm;
|
package com.android.server.wm;
|
||||||
|
|
||||||
|
import static android.app.ActivityTaskManager.INVALID_TASK_ID;
|
||||||
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_ACTIVITY_REPARENT_TO_TASK;
|
||||||
import static android.window.TaskFragmentTransaction.TYPE_TASK_FRAGMENT_APPEARED;
|
import static android.window.TaskFragmentTransaction.TYPE_TASK_FRAGMENT_APPEARED;
|
||||||
@@ -28,6 +29,8 @@ import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_WINDOW_ORGANI
|
|||||||
import static com.android.server.wm.TaskFragment.EMBEDDING_ALLOWED;
|
import static com.android.server.wm.TaskFragment.EMBEDDING_ALLOWED;
|
||||||
import static com.android.server.wm.WindowOrganizerController.configurationsAreEqualForOrganizer;
|
import static com.android.server.wm.WindowOrganizerController.configurationsAreEqualForOrganizer;
|
||||||
|
|
||||||
|
import static java.util.Objects.requireNonNull;
|
||||||
|
|
||||||
import android.annotation.IntDef;
|
import android.annotation.IntDef;
|
||||||
import android.annotation.NonNull;
|
import android.annotation.NonNull;
|
||||||
import android.annotation.Nullable;
|
import android.annotation.Nullable;
|
||||||
@@ -38,6 +41,7 @@ import android.os.Bundle;
|
|||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
import android.os.RemoteException;
|
import android.os.RemoteException;
|
||||||
import android.util.ArrayMap;
|
import android.util.ArrayMap;
|
||||||
|
import android.util.ArraySet;
|
||||||
import android.util.Slog;
|
import android.util.Slog;
|
||||||
import android.util.SparseArray;
|
import android.util.SparseArray;
|
||||||
import android.view.RemoteAnimationDefinition;
|
import android.view.RemoteAnimationDefinition;
|
||||||
@@ -51,6 +55,7 @@ import com.android.internal.protolog.common.ProtoLog;
|
|||||||
import java.lang.annotation.Retention;
|
import java.lang.annotation.Retention;
|
||||||
import java.lang.annotation.RetentionPolicy;
|
import java.lang.annotation.RetentionPolicy;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.WeakHashMap;
|
import java.util.WeakHashMap;
|
||||||
|
|
||||||
@@ -70,15 +75,12 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
|
|||||||
private final ArrayMap<IBinder, TaskFragmentOrganizerState> mTaskFragmentOrganizerState =
|
private final ArrayMap<IBinder, TaskFragmentOrganizerState> mTaskFragmentOrganizerState =
|
||||||
new ArrayMap<>();
|
new ArrayMap<>();
|
||||||
/**
|
/**
|
||||||
* A List which manages the TaskFragment pending event {@link PendingTaskFragmentEvent}
|
* Map from {@link ITaskFragmentOrganizer} to a list of related {@link PendingTaskFragmentEvent}
|
||||||
*/
|
*/
|
||||||
private final ArrayList<PendingTaskFragmentEvent> mPendingTaskFragmentEvents =
|
private final ArrayMap<IBinder, List<PendingTaskFragmentEvent>> mPendingTaskFragmentEvents =
|
||||||
new ArrayList<>();
|
|
||||||
|
|
||||||
/** Map from {@link ITaskFragmentOrganizer} to {@link TaskFragmentTransaction}. */
|
|
||||||
private final ArrayMap<IBinder, TaskFragmentTransaction> mTmpOrganizerToTransactionMap =
|
|
||||||
new ArrayMap<>();
|
new ArrayMap<>();
|
||||||
private final ArrayList<ITaskFragmentOrganizer> mTmpOrganizerList = new ArrayList<>();
|
|
||||||
|
private final ArraySet<Task> mTmpTaskSet = new ArraySet<>();
|
||||||
|
|
||||||
TaskFragmentOrganizerController(ActivityTaskManagerService atm) {
|
TaskFragmentOrganizerController(ActivityTaskManagerService atm) {
|
||||||
mAtmService = atm;
|
mAtmService = atm;
|
||||||
@@ -94,10 +96,30 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
|
|||||||
private final ITaskFragmentOrganizer mOrganizer;
|
private final ITaskFragmentOrganizer mOrganizer;
|
||||||
private final int mOrganizerPid;
|
private final int mOrganizerPid;
|
||||||
private final int mOrganizerUid;
|
private final int mOrganizerUid;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Map from {@link TaskFragment} to the last {@link TaskFragmentInfo} sent to the
|
||||||
|
* organizer.
|
||||||
|
*/
|
||||||
private final Map<TaskFragment, TaskFragmentInfo> mLastSentTaskFragmentInfos =
|
private final Map<TaskFragment, TaskFragmentInfo> mLastSentTaskFragmentInfos =
|
||||||
new WeakHashMap<>();
|
new WeakHashMap<>();
|
||||||
private final Map<TaskFragment, Configuration> mLastSentTaskFragmentParentConfigs =
|
|
||||||
new WeakHashMap<>();
|
/**
|
||||||
|
* Map from {@link TaskFragment} to its leaf {@link Task#mTaskId}. Embedded
|
||||||
|
* {@link TaskFragment} will not be reparented until it is removed.
|
||||||
|
*/
|
||||||
|
private final Map<TaskFragment, Integer> mTaskFragmentTaskIds = new WeakHashMap<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Map from {@link Task#mTaskId} to the last Task {@link Configuration} sent to the
|
||||||
|
* organizer.
|
||||||
|
*/
|
||||||
|
private final SparseArray<Configuration> mLastSentTaskFragmentParentConfigs =
|
||||||
|
new SparseArray<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Map from temporary activity token to the corresponding {@link ActivityRecord}.
|
||||||
|
*/
|
||||||
private final Map<IBinder, ActivityRecord> mTemporaryActivityTokens =
|
private final Map<IBinder, ActivityRecord> mTemporaryActivityTokens =
|
||||||
new WeakHashMap<>();
|
new WeakHashMap<>();
|
||||||
|
|
||||||
@@ -161,21 +183,15 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
|
|||||||
TaskFragmentTransaction.Change prepareTaskFragmentAppeared(@NonNull TaskFragment tf) {
|
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();
|
||||||
|
final int taskId = tf.getTask().mTaskId;
|
||||||
tf.mTaskFragmentAppearedSent = true;
|
tf.mTaskFragmentAppearedSent = true;
|
||||||
mLastSentTaskFragmentInfos.put(tf, info);
|
mLastSentTaskFragmentInfos.put(tf, info);
|
||||||
final TaskFragmentTransaction.Change change =
|
mTaskFragmentTaskIds.put(tf, taskId);
|
||||||
new TaskFragmentTransaction.Change(TYPE_TASK_FRAGMENT_APPEARED)
|
return new TaskFragmentTransaction.Change(
|
||||||
|
TYPE_TASK_FRAGMENT_APPEARED)
|
||||||
.setTaskFragmentToken(tf.getFragmentToken())
|
.setTaskFragmentToken(tf.getFragmentToken())
|
||||||
.setTaskFragmentInfo(info);
|
.setTaskFragmentInfo(info)
|
||||||
if (shouldSendTaskFragmentParentInfoChanged(tf)) {
|
.setTaskId(taskId);
|
||||||
// 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());
|
|
||||||
}
|
|
||||||
return change;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@@ -183,10 +199,24 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
|
|||||||
ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "TaskFragment vanished name=%s", tf.getName());
|
ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "TaskFragment vanished name=%s", tf.getName());
|
||||||
tf.mTaskFragmentAppearedSent = false;
|
tf.mTaskFragmentAppearedSent = false;
|
||||||
mLastSentTaskFragmentInfos.remove(tf);
|
mLastSentTaskFragmentInfos.remove(tf);
|
||||||
mLastSentTaskFragmentParentConfigs.remove(tf);
|
|
||||||
|
// Cleanup TaskFragmentParentConfig if this is the last TaskFragment in the Task.
|
||||||
|
final int taskId;
|
||||||
|
if (mTaskFragmentTaskIds.containsKey(tf)) {
|
||||||
|
taskId = mTaskFragmentTaskIds.remove(tf);
|
||||||
|
if (!mTaskFragmentTaskIds.containsValue(taskId)) {
|
||||||
|
// No more TaskFragment in the Task.
|
||||||
|
mLastSentTaskFragmentParentConfigs.remove(taskId);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// This can happen if the appeared wasn't sent before remove.
|
||||||
|
taskId = INVALID_TASK_ID;
|
||||||
|
}
|
||||||
|
|
||||||
return new TaskFragmentTransaction.Change(TYPE_TASK_FRAGMENT_VANISHED)
|
return new TaskFragmentTransaction.Change(TYPE_TASK_FRAGMENT_VANISHED)
|
||||||
.setTaskFragmentToken(tf.getFragmentToken())
|
.setTaskFragmentToken(tf.getFragmentToken())
|
||||||
.setTaskFragmentInfo(tf.getTaskFragmentInfo());
|
.setTaskFragmentInfo(tf.getTaskFragmentInfo())
|
||||||
|
.setTaskId(taskId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@@ -197,65 +227,39 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
|
|||||||
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())) {
|
||||||
// Parent config may have changed. The controller will check if there is any
|
return null;
|
||||||
// important config change for the organizer.
|
|
||||||
return prepareTaskFragmentParentInfoChanged(tf);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "TaskFragment info changed name=%s",
|
ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "TaskFragment info changed name=%s",
|
||||||
tf.getName());
|
tf.getName());
|
||||||
mLastSentTaskFragmentInfos.put(tf, info);
|
mLastSentTaskFragmentInfos.put(tf, info);
|
||||||
final TaskFragmentTransaction.Change change =
|
return new TaskFragmentTransaction.Change(
|
||||||
new TaskFragmentTransaction.Change(TYPE_TASK_FRAGMENT_INFO_CHANGED)
|
TYPE_TASK_FRAGMENT_INFO_CHANGED)
|
||||||
.setTaskFragmentToken(tf.getFragmentToken())
|
.setTaskFragmentToken(tf.getFragmentToken())
|
||||||
.setTaskFragmentInfo(info);
|
.setTaskFragmentInfo(info)
|
||||||
if (shouldSendTaskFragmentParentInfoChanged(tf)) {
|
.setTaskId(tf.getTask().mTaskId);
|
||||||
// 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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
TaskFragmentTransaction.Change prepareTaskFragmentParentInfoChanged(
|
TaskFragmentTransaction.Change prepareTaskFragmentParentInfoChanged(
|
||||||
@NonNull TaskFragment tf) {
|
@NonNull Task task) {
|
||||||
if (!shouldSendTaskFragmentParentInfoChanged(tf)) {
|
final int taskId = task.mTaskId;
|
||||||
|
// Check if the parent info is different from the last reported parent info.
|
||||||
|
final Configuration taskConfig = task.getConfiguration();
|
||||||
|
final Configuration lastParentConfig = mLastSentTaskFragmentParentConfigs.get(taskId);
|
||||||
|
if (configurationsAreEqualForOrganizer(taskConfig, lastParentConfig)
|
||||||
|
&& taskConfig.windowConfiguration.getWindowingMode()
|
||||||
|
== lastParentConfig.windowConfiguration.getWindowingMode()) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
final Task parent = tf.getTask();
|
|
||||||
final Configuration parentConfig = parent.getConfiguration();
|
|
||||||
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);
|
task.getName(), taskId);
|
||||||
mLastSentTaskFragmentParentConfigs.put(tf, new Configuration(parentConfig));
|
mLastSentTaskFragmentParentConfigs.put(taskId, new Configuration(taskConfig));
|
||||||
return new TaskFragmentTransaction.Change(TYPE_TASK_FRAGMENT_PARENT_INFO_CHANGED)
|
return new TaskFragmentTransaction.Change(TYPE_TASK_FRAGMENT_PARENT_INFO_CHANGED)
|
||||||
.setTaskFragmentToken(tf.getFragmentToken())
|
.setTaskId(taskId)
|
||||||
.setTaskId(parent.mTaskId)
|
.setTaskConfiguration(taskConfig);
|
||||||
.setTaskConfiguration(parent.getConfiguration());
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 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
|
@NonNull
|
||||||
@@ -345,6 +349,7 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
|
|||||||
}
|
}
|
||||||
mTaskFragmentOrganizerState.put(organizer.asBinder(),
|
mTaskFragmentOrganizerState.put(organizer.asBinder(),
|
||||||
new TaskFragmentOrganizerState(organizer, pid, uid));
|
new TaskFragmentOrganizerState(organizer, pid, uid));
|
||||||
|
mPendingTaskFragmentEvents.put(organizer.asBinder(), new ArrayList<>());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -434,6 +439,11 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
|
|||||||
|
|
||||||
void onTaskFragmentAppeared(@NonNull ITaskFragmentOrganizer organizer,
|
void onTaskFragmentAppeared(@NonNull ITaskFragmentOrganizer organizer,
|
||||||
@NonNull TaskFragment taskFragment) {
|
@NonNull TaskFragment taskFragment) {
|
||||||
|
if (taskFragment.getTask() == null) {
|
||||||
|
Slog.w(TAG, "onTaskFragmentAppeared failed because it is not attached tf="
|
||||||
|
+ taskFragment);
|
||||||
|
return;
|
||||||
|
}
|
||||||
final TaskFragmentOrganizerState state = validateAndGetState(organizer);
|
final TaskFragmentOrganizerState state = validateAndGetState(organizer);
|
||||||
if (!state.addTaskFragment(taskFragment)) {
|
if (!state.addTaskFragment(taskFragment)) {
|
||||||
return;
|
return;
|
||||||
@@ -441,28 +451,15 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
|
|||||||
PendingTaskFragmentEvent pendingEvent = getPendingTaskFragmentEvent(taskFragment,
|
PendingTaskFragmentEvent pendingEvent = getPendingTaskFragmentEvent(taskFragment,
|
||||||
PendingTaskFragmentEvent.EVENT_APPEARED);
|
PendingTaskFragmentEvent.EVENT_APPEARED);
|
||||||
if (pendingEvent == null) {
|
if (pendingEvent == null) {
|
||||||
pendingEvent = new PendingTaskFragmentEvent.Builder(
|
addPendingEvent(new PendingTaskFragmentEvent.Builder(
|
||||||
PendingTaskFragmentEvent.EVENT_APPEARED, organizer)
|
PendingTaskFragmentEvent.EVENT_APPEARED, organizer)
|
||||||
.setTaskFragment(taskFragment)
|
.setTaskFragment(taskFragment)
|
||||||
.build();
|
.build());
|
||||||
mPendingTaskFragmentEvents.add(pendingEvent);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void onTaskFragmentInfoChanged(@NonNull ITaskFragmentOrganizer organizer,
|
void onTaskFragmentInfoChanged(@NonNull ITaskFragmentOrganizer organizer,
|
||||||
@NonNull TaskFragment taskFragment) {
|
@NonNull TaskFragment taskFragment) {
|
||||||
handleTaskFragmentInfoChanged(organizer, taskFragment,
|
|
||||||
PendingTaskFragmentEvent.EVENT_INFO_CHANGED);
|
|
||||||
}
|
|
||||||
|
|
||||||
void onTaskFragmentParentInfoChanged(@NonNull ITaskFragmentOrganizer organizer,
|
|
||||||
@NonNull TaskFragment taskFragment) {
|
|
||||||
handleTaskFragmentInfoChanged(organizer, taskFragment,
|
|
||||||
PendingTaskFragmentEvent.EVENT_PARENT_INFO_CHANGED);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void handleTaskFragmentInfoChanged(@NonNull ITaskFragmentOrganizer organizer,
|
|
||||||
@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.
|
||||||
@@ -470,7 +467,8 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
|
|||||||
}
|
}
|
||||||
PendingTaskFragmentEvent pendingEvent = getLastPendingLifecycleEvent(taskFragment);
|
PendingTaskFragmentEvent pendingEvent = getLastPendingLifecycleEvent(taskFragment);
|
||||||
if (pendingEvent == null) {
|
if (pendingEvent == null) {
|
||||||
pendingEvent = new PendingTaskFragmentEvent.Builder(eventType, organizer)
|
pendingEvent = new PendingTaskFragmentEvent.Builder(
|
||||||
|
PendingTaskFragmentEvent.EVENT_INFO_CHANGED, organizer)
|
||||||
.setTaskFragment(taskFragment)
|
.setTaskFragment(taskFragment)
|
||||||
.build();
|
.build();
|
||||||
} else {
|
} else {
|
||||||
@@ -479,36 +477,31 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Remove and add for re-ordering.
|
// Remove and add for re-ordering.
|
||||||
mPendingTaskFragmentEvents.remove(pendingEvent);
|
removePendingEvent(pendingEvent);
|
||||||
// Reset the defer time when TaskFragment is changed, so that it can check again if
|
// Reset the defer time when TaskFragment is changed, so that it can check again if
|
||||||
// the event should be sent to the organizer, for example the TaskFragment may become
|
// the event should be sent to the organizer, for example the TaskFragment may become
|
||||||
// empty.
|
// empty.
|
||||||
pendingEvent.mDeferTime = 0;
|
pendingEvent.mDeferTime = 0;
|
||||||
}
|
}
|
||||||
mPendingTaskFragmentEvents.add(pendingEvent);
|
addPendingEvent(pendingEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
void onTaskFragmentVanished(@NonNull ITaskFragmentOrganizer organizer,
|
void onTaskFragmentVanished(@NonNull ITaskFragmentOrganizer organizer,
|
||||||
@NonNull TaskFragment taskFragment) {
|
@NonNull TaskFragment taskFragment) {
|
||||||
final TaskFragmentOrganizerState state = validateAndGetState(organizer);
|
final TaskFragmentOrganizerState state = validateAndGetState(organizer);
|
||||||
for (int i = mPendingTaskFragmentEvents.size() - 1; i >= 0; i--) {
|
final List<PendingTaskFragmentEvent> pendingEvents = mPendingTaskFragmentEvents
|
||||||
PendingTaskFragmentEvent entry = mPendingTaskFragmentEvents.get(i);
|
.get(organizer.asBinder());
|
||||||
if (taskFragment == entry.mTaskFragment) {
|
// Remove any pending events since this TaskFragment is being removed.
|
||||||
mPendingTaskFragmentEvents.remove(i);
|
for (int i = pendingEvents.size() - 1; i >= 0; i--) {
|
||||||
if (entry.mEventType == PendingTaskFragmentEvent.EVENT_APPEARED) {
|
final PendingTaskFragmentEvent event = pendingEvents.get(i);
|
||||||
// If taskFragment appeared callback is pending, ignore the vanished request.
|
if (taskFragment == event.mTaskFragment) {
|
||||||
return;
|
pendingEvents.remove(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
addPendingEvent(new PendingTaskFragmentEvent.Builder(
|
||||||
if (!taskFragment.mTaskFragmentAppearedSent) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
final PendingTaskFragmentEvent pendingEvent = new PendingTaskFragmentEvent.Builder(
|
|
||||||
PendingTaskFragmentEvent.EVENT_VANISHED, organizer)
|
PendingTaskFragmentEvent.EVENT_VANISHED, organizer)
|
||||||
.setTaskFragment(taskFragment)
|
.setTaskFragment(taskFragment)
|
||||||
.build();
|
.build());
|
||||||
mPendingTaskFragmentEvents.add(pendingEvent);
|
|
||||||
state.removeTaskFragment(taskFragment);
|
state.removeTaskFragment(taskFragment);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -517,14 +510,13 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
|
|||||||
int opType, @NonNull Throwable exception) {
|
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(
|
addPendingEvent(new PendingTaskFragmentEvent.Builder(
|
||||||
PendingTaskFragmentEvent.EVENT_ERROR, organizer)
|
PendingTaskFragmentEvent.EVENT_ERROR, organizer)
|
||||||
.setErrorCallbackToken(errorCallbackToken)
|
.setErrorCallbackToken(errorCallbackToken)
|
||||||
.setTaskFragment(taskFragment)
|
.setTaskFragment(taskFragment)
|
||||||
.setException(exception)
|
.setException(exception)
|
||||||
.setOpType(opType)
|
.setOpType(opType)
|
||||||
.build();
|
.build());
|
||||||
mPendingTaskFragmentEvents.add(pendingEvent);
|
|
||||||
// Make sure the error event will be dispatched if there are no other changes.
|
// Make sure the error event will be dispatched if there are no other changes.
|
||||||
mAtmService.mWindowManager.mWindowPlacerLocked.requestTraversal();
|
mAtmService.mWindowManager.mWindowPlacerLocked.requestTraversal();
|
||||||
}
|
}
|
||||||
@@ -554,11 +546,18 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
|
|||||||
Slog.w(TAG, "The last TaskFragmentOrganizer no longer exists");
|
Slog.w(TAG, "The last TaskFragmentOrganizer no longer exists");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final PendingTaskFragmentEvent pendingEvent = new PendingTaskFragmentEvent.Builder(
|
addPendingEvent(new PendingTaskFragmentEvent.Builder(
|
||||||
PendingTaskFragmentEvent.EVENT_ACTIVITY_REPARENT_TO_TASK, organizer)
|
PendingTaskFragmentEvent.EVENT_ACTIVITY_REPARENT_TO_TASK, organizer)
|
||||||
.setActivity(activity)
|
.setActivity(activity)
|
||||||
.build();
|
.build());
|
||||||
mPendingTaskFragmentEvents.add(pendingEvent);
|
}
|
||||||
|
|
||||||
|
private void addPendingEvent(@NonNull PendingTaskFragmentEvent event) {
|
||||||
|
mPendingTaskFragmentEvents.get(event.mTaskFragmentOrg.asBinder()).add(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void removePendingEvent(@NonNull PendingTaskFragmentEvent event) {
|
||||||
|
mPendingTaskFragmentEvents.get(event.mTaskFragmentOrg.asBinder()).remove(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean isOrganizerRegistered(@NonNull ITaskFragmentOrganizer organizer) {
|
boolean isOrganizerRegistered(@NonNull ITaskFragmentOrganizer organizer) {
|
||||||
@@ -570,12 +569,7 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
|
|||||||
// remove all of the children of the organized TaskFragment
|
// remove all of the children of the organized TaskFragment
|
||||||
state.dispose();
|
state.dispose();
|
||||||
// Remove any pending event of this organizer.
|
// Remove any pending event of this organizer.
|
||||||
for (int i = mPendingTaskFragmentEvents.size() - 1; i >= 0; i--) {
|
mPendingTaskFragmentEvents.remove(organizer.asBinder());
|
||||||
final PendingTaskFragmentEvent event = mPendingTaskFragmentEvents.get(i);
|
|
||||||
if (event.mTaskFragmentOrg.asBinder().equals(organizer.asBinder())) {
|
|
||||||
mPendingTaskFragmentEvents.remove(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mTaskFragmentOrganizerState.remove(organizer.asBinder());
|
mTaskFragmentOrganizerState.remove(organizer.asBinder());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -631,6 +625,8 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
|
|||||||
private final Throwable mException;
|
private final Throwable mException;
|
||||||
@Nullable
|
@Nullable
|
||||||
private final ActivityRecord mActivity;
|
private final ActivityRecord mActivity;
|
||||||
|
@Nullable
|
||||||
|
private final Task mTask;
|
||||||
// Set when the event is deferred due to the host task is invisible. The defer time will
|
// Set when the event is deferred due to the host task is invisible. The defer time will
|
||||||
// be the last active time of the host task.
|
// be the last active time of the host task.
|
||||||
private long mDeferTime;
|
private long mDeferTime;
|
||||||
@@ -642,6 +638,7 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
|
|||||||
@Nullable IBinder errorCallbackToken,
|
@Nullable IBinder errorCallbackToken,
|
||||||
@Nullable Throwable exception,
|
@Nullable Throwable exception,
|
||||||
@Nullable ActivityRecord activity,
|
@Nullable ActivityRecord activity,
|
||||||
|
@Nullable Task task,
|
||||||
int opType) {
|
int opType) {
|
||||||
mEventType = eventType;
|
mEventType = eventType;
|
||||||
mTaskFragmentOrg = taskFragmentOrg;
|
mTaskFragmentOrg = taskFragmentOrg;
|
||||||
@@ -649,6 +646,7 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
|
|||||||
mErrorCallbackToken = errorCallbackToken;
|
mErrorCallbackToken = errorCallbackToken;
|
||||||
mException = exception;
|
mException = exception;
|
||||||
mActivity = activity;
|
mActivity = activity;
|
||||||
|
mTask = task;
|
||||||
mOpType = opType;
|
mOpType = opType;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -680,11 +678,13 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
|
|||||||
private Throwable mException;
|
private Throwable mException;
|
||||||
@Nullable
|
@Nullable
|
||||||
private ActivityRecord mActivity;
|
private ActivityRecord mActivity;
|
||||||
|
@Nullable
|
||||||
|
private Task mTask;
|
||||||
private int mOpType;
|
private int mOpType;
|
||||||
|
|
||||||
Builder(@EventType int eventType, ITaskFragmentOrganizer taskFragmentOrg) {
|
Builder(@EventType int eventType, @NonNull ITaskFragmentOrganizer taskFragmentOrg) {
|
||||||
mEventType = eventType;
|
mEventType = eventType;
|
||||||
mTaskFragmentOrg = taskFragmentOrg;
|
mTaskFragmentOrg = requireNonNull(taskFragmentOrg);
|
||||||
}
|
}
|
||||||
|
|
||||||
Builder setTaskFragment(@Nullable TaskFragment taskFragment) {
|
Builder setTaskFragment(@Nullable TaskFragment taskFragment) {
|
||||||
@@ -697,13 +697,18 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
Builder setException(@Nullable Throwable exception) {
|
Builder setException(@NonNull Throwable exception) {
|
||||||
mException = exception;
|
mException = requireNonNull(exception);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
Builder setActivity(@Nullable ActivityRecord activity) {
|
Builder setActivity(@NonNull ActivityRecord activity) {
|
||||||
mActivity = activity;
|
mActivity = requireNonNull(activity);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Builder setTask(@NonNull Task task) {
|
||||||
|
mTask = requireNonNull(task);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -714,17 +719,20 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
|
|||||||
|
|
||||||
PendingTaskFragmentEvent build() {
|
PendingTaskFragmentEvent build() {
|
||||||
return new PendingTaskFragmentEvent(mEventType, mTaskFragmentOrg, mTaskFragment,
|
return new PendingTaskFragmentEvent(mEventType, mTaskFragmentOrg, mTaskFragment,
|
||||||
mErrorCallbackToken, mException, mActivity, mOpType);
|
mErrorCallbackToken, mException, mActivity, mTask, mOpType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private PendingTaskFragmentEvent getLastPendingLifecycleEvent(@NonNull TaskFragment tf) {
|
private PendingTaskFragmentEvent getLastPendingLifecycleEvent(@NonNull TaskFragment tf) {
|
||||||
for (int i = mPendingTaskFragmentEvents.size() - 1; i >= 0; i--) {
|
final ITaskFragmentOrganizer organizer = tf.getTaskFragmentOrganizer();
|
||||||
PendingTaskFragmentEvent entry = mPendingTaskFragmentEvents.get(i);
|
final List<PendingTaskFragmentEvent> events = mPendingTaskFragmentEvents
|
||||||
if (tf == entry.mTaskFragment && entry.isLifecycleEvent()) {
|
.get(organizer.asBinder());
|
||||||
return entry;
|
for (int i = events.size() - 1; i >= 0; i--) {
|
||||||
|
final PendingTaskFragmentEvent event = events.get(i);
|
||||||
|
if (tf == event.mTaskFragment && event.isLifecycleEvent()) {
|
||||||
|
return event;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
@@ -733,10 +741,13 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
|
|||||||
@Nullable
|
@Nullable
|
||||||
private PendingTaskFragmentEvent getPendingTaskFragmentEvent(@NonNull TaskFragment taskFragment,
|
private PendingTaskFragmentEvent getPendingTaskFragmentEvent(@NonNull TaskFragment taskFragment,
|
||||||
int type) {
|
int type) {
|
||||||
for (int i = mPendingTaskFragmentEvents.size() - 1; i >= 0; i--) {
|
final ITaskFragmentOrganizer organizer = taskFragment.getTaskFragmentOrganizer();
|
||||||
PendingTaskFragmentEvent entry = mPendingTaskFragmentEvents.get(i);
|
final List<PendingTaskFragmentEvent> events = mPendingTaskFragmentEvents
|
||||||
if (taskFragment == entry.mTaskFragment && type == entry.mEventType) {
|
.get(organizer.asBinder());
|
||||||
return entry;
|
for (int i = events.size() - 1; i >= 0; i--) {
|
||||||
|
final PendingTaskFragmentEvent event = events.get(i);
|
||||||
|
if (taskFragment == event.mTaskFragment && type == event.mEventType) {
|
||||||
|
return event;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
@@ -762,12 +773,25 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
|
|||||||
|| mPendingTaskFragmentEvents.isEmpty()) {
|
|| mPendingTaskFragmentEvents.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
final int organizerNum = mPendingTaskFragmentEvents.size();
|
||||||
|
for (int i = 0; i < organizerNum; i++) {
|
||||||
|
final ITaskFragmentOrganizer organizer = mTaskFragmentOrganizerState.get(
|
||||||
|
mPendingTaskFragmentEvents.keyAt(i)).mOrganizer;
|
||||||
|
dispatchPendingEvents(organizer, mPendingTaskFragmentEvents.valueAt(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void dispatchPendingEvents(@NonNull ITaskFragmentOrganizer organizer,
|
||||||
|
@NonNull List<PendingTaskFragmentEvent> pendingEvents) {
|
||||||
|
if (pendingEvents.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
final ArrayList<Task> visibleTasks = new ArrayList<>();
|
final ArrayList<Task> visibleTasks = new ArrayList<>();
|
||||||
final ArrayList<Task> invisibleTasks = new ArrayList<>();
|
final ArrayList<Task> invisibleTasks = new ArrayList<>();
|
||||||
final ArrayList<PendingTaskFragmentEvent> candidateEvents = new ArrayList<>();
|
final ArrayList<PendingTaskFragmentEvent> candidateEvents = new ArrayList<>();
|
||||||
for (int i = 0, n = mPendingTaskFragmentEvents.size(); i < n; i++) {
|
for (int i = 0, n = pendingEvents.size(); i < n; i++) {
|
||||||
final PendingTaskFragmentEvent event = mPendingTaskFragmentEvents.get(i);
|
final PendingTaskFragmentEvent event = pendingEvents.get(i);
|
||||||
final Task task = event.mTaskFragment != null ? event.mTaskFragment.getTask() : null;
|
final Task task = event.mTaskFragment != null ? event.mTaskFragment.getTask() : null;
|
||||||
if (task != null && (task.lastActiveTime <= event.mDeferTime
|
if (task != null && (task.lastActiveTime <= event.mDeferTime
|
||||||
|| !(isTaskVisible(task, visibleTasks, invisibleTasks)
|
|| !(isTaskVisible(task, visibleTasks, invisibleTasks)
|
||||||
@@ -783,27 +807,26 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
mTmpOrganizerToTransactionMap.clear();
|
mTmpTaskSet.clear();
|
||||||
mTmpOrganizerList.clear();
|
final TaskFragmentTransaction transaction = new TaskFragmentTransaction();
|
||||||
for (int i = 0; i < numEvents; i++) {
|
for (int i = 0; i < numEvents; i++) {
|
||||||
final PendingTaskFragmentEvent event = candidateEvents.get(i);
|
final PendingTaskFragmentEvent event = candidateEvents.get(i);
|
||||||
if (!mTmpOrganizerToTransactionMap.containsKey(event.mTaskFragmentOrg.asBinder())) {
|
if (event.mEventType == PendingTaskFragmentEvent.EVENT_APPEARED
|
||||||
mTmpOrganizerToTransactionMap.put(event.mTaskFragmentOrg.asBinder(),
|
|| event.mEventType == PendingTaskFragmentEvent.EVENT_INFO_CHANGED) {
|
||||||
new TaskFragmentTransaction());
|
final Task task = event.mTaskFragment.getTask();
|
||||||
mTmpOrganizerList.add(event.mTaskFragmentOrg);
|
if (mTmpTaskSet.add(task)) {
|
||||||
|
// Make sure the organizer know about the Task config.
|
||||||
|
transaction.addChange(prepareChange(new PendingTaskFragmentEvent.Builder(
|
||||||
|
PendingTaskFragmentEvent.EVENT_PARENT_INFO_CHANGED, organizer)
|
||||||
|
.setTask(task)
|
||||||
|
.build()));
|
||||||
}
|
}
|
||||||
mTmpOrganizerToTransactionMap.get(event.mTaskFragmentOrg.asBinder())
|
|
||||||
.addChange(prepareChange(event));
|
|
||||||
}
|
}
|
||||||
final int numOrganizers = mTmpOrganizerList.size();
|
transaction.addChange(prepareChange(event));
|
||||||
for (int i = 0; i < numOrganizers; i++) {
|
|
||||||
final ITaskFragmentOrganizer organizer = mTmpOrganizerList.get(i);
|
|
||||||
dispatchTransactionInfo(organizer,
|
|
||||||
mTmpOrganizerToTransactionMap.get(organizer.asBinder()));
|
|
||||||
}
|
}
|
||||||
mPendingTaskFragmentEvents.removeAll(candidateEvents);
|
mTmpTaskSet.clear();
|
||||||
mTmpOrganizerToTransactionMap.clear();
|
dispatchTransactionInfo(organizer, transaction);
|
||||||
mTmpOrganizerList.clear();
|
pendingEvents.removeAll(candidateEvents);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isTaskVisible(@NonNull Task task,
|
private static boolean isTaskVisible(@NonNull Task task,
|
||||||
@@ -831,10 +854,16 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final ITaskFragmentOrganizer organizer = taskFragment.getTaskFragmentOrganizer();
|
||||||
final TaskFragmentTransaction transaction = new TaskFragmentTransaction();
|
final TaskFragmentTransaction transaction = new TaskFragmentTransaction();
|
||||||
|
// Make sure the organizer know about the Task config.
|
||||||
|
transaction.addChange(prepareChange(new PendingTaskFragmentEvent.Builder(
|
||||||
|
PendingTaskFragmentEvent.EVENT_PARENT_INFO_CHANGED, organizer)
|
||||||
|
.setTask(taskFragment.getTask())
|
||||||
|
.build()));
|
||||||
transaction.addChange(prepareChange(event));
|
transaction.addChange(prepareChange(event));
|
||||||
dispatchTransactionInfo(event.mTaskFragmentOrg, transaction);
|
dispatchTransactionInfo(event.mTaskFragmentOrg, transaction);
|
||||||
mPendingTaskFragmentEvents.remove(event);
|
mPendingTaskFragmentEvents.get(organizer.asBinder()).remove(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void dispatchTransactionInfo(@NonNull ITaskFragmentOrganizer organizer,
|
private void dispatchTransactionInfo(@NonNull ITaskFragmentOrganizer organizer,
|
||||||
@@ -867,7 +896,7 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
|
|||||||
case PendingTaskFragmentEvent.EVENT_INFO_CHANGED:
|
case PendingTaskFragmentEvent.EVENT_INFO_CHANGED:
|
||||||
return state.prepareTaskFragmentInfoChanged(taskFragment);
|
return state.prepareTaskFragmentInfoChanged(taskFragment);
|
||||||
case PendingTaskFragmentEvent.EVENT_PARENT_INFO_CHANGED:
|
case PendingTaskFragmentEvent.EVENT_PARENT_INFO_CHANGED:
|
||||||
return state.prepareTaskFragmentParentInfoChanged(taskFragment);
|
return state.prepareTaskFragmentParentInfoChanged(event.mTask);
|
||||||
case PendingTaskFragmentEvent.EVENT_ERROR:
|
case PendingTaskFragmentEvent.EVENT_ERROR:
|
||||||
return state.prepareTaskFragmentError(event.mErrorCallbackToken, taskFragment,
|
return state.prepareTaskFragmentError(event.mErrorCallbackToken, taskFragment,
|
||||||
event.mOpType, event.mException);
|
event.mOpType, event.mException);
|
||||||
|
|||||||
@@ -75,6 +75,8 @@ import org.junit.Before;
|
|||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.mockito.ArgumentCaptor;
|
import org.mockito.ArgumentCaptor;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.MockitoAnnotations;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Build/Install/Run:
|
* Build/Install/Run:
|
||||||
@@ -92,7 +94,6 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
|
|||||||
private TaskFragmentOrganizerToken mOrganizerToken;
|
private TaskFragmentOrganizerToken mOrganizerToken;
|
||||||
private ITaskFragmentOrganizer mIOrganizer;
|
private ITaskFragmentOrganizer mIOrganizer;
|
||||||
private TaskFragment mTaskFragment;
|
private TaskFragment mTaskFragment;
|
||||||
private TaskFragmentInfo mTaskFragmentInfo;
|
|
||||||
private IBinder mFragmentToken;
|
private IBinder mFragmentToken;
|
||||||
private WindowContainerTransaction mTransaction;
|
private WindowContainerTransaction mTransaction;
|
||||||
private WindowContainerToken mFragmentWindowToken;
|
private WindowContainerToken mFragmentWindowToken;
|
||||||
@@ -100,14 +101,19 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
|
|||||||
private IBinder mErrorToken;
|
private IBinder mErrorToken;
|
||||||
private Rect mTaskFragBounds;
|
private Rect mTaskFragBounds;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private TaskFragmentInfo mTaskFragmentInfo;
|
||||||
|
@Mock
|
||||||
|
private Task mTask;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setup() {
|
public void setup() {
|
||||||
|
MockitoAnnotations.initMocks(this);
|
||||||
mWindowOrganizerController = mAtm.mWindowOrganizerController;
|
mWindowOrganizerController = mAtm.mWindowOrganizerController;
|
||||||
mController = mWindowOrganizerController.mTaskFragmentOrganizerController;
|
mController = mWindowOrganizerController.mTaskFragmentOrganizerController;
|
||||||
mOrganizer = new TaskFragmentOrganizer(Runnable::run);
|
mOrganizer = new TaskFragmentOrganizer(Runnable::run);
|
||||||
mOrganizerToken = mOrganizer.getOrganizerToken();
|
mOrganizerToken = mOrganizer.getOrganizerToken();
|
||||||
mIOrganizer = ITaskFragmentOrganizer.Stub.asInterface(mOrganizerToken.asBinder());
|
mIOrganizer = ITaskFragmentOrganizer.Stub.asInterface(mOrganizerToken.asBinder());
|
||||||
mTaskFragmentInfo = mock(TaskFragmentInfo.class);
|
|
||||||
mFragmentToken = new Binder();
|
mFragmentToken = new Binder();
|
||||||
mTaskFragment =
|
mTaskFragment =
|
||||||
new TaskFragment(mAtm, mFragmentToken, true /* createdByOrganizer */);
|
new TaskFragment(mAtm, mFragmentToken, true /* createdByOrganizer */);
|
||||||
@@ -131,6 +137,8 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCallTaskFragmentCallbackWithoutRegister_throwsException() {
|
public void testCallTaskFragmentCallbackWithoutRegister_throwsException() {
|
||||||
|
doReturn(mTask).when(mTaskFragment).getTask();
|
||||||
|
|
||||||
assertThrows(IllegalArgumentException.class, () -> mController
|
assertThrows(IllegalArgumentException.class, () -> mController
|
||||||
.onTaskFragmentAppeared(mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment));
|
.onTaskFragmentAppeared(mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment));
|
||||||
|
|
||||||
@@ -140,16 +148,21 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
|
|||||||
|
|
||||||
assertThrows(IllegalArgumentException.class, () -> mController
|
assertThrows(IllegalArgumentException.class, () -> mController
|
||||||
.onTaskFragmentVanished(mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment));
|
.onTaskFragmentVanished(mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment));
|
||||||
|
|
||||||
assertThrows(IllegalArgumentException.class, () -> mController
|
|
||||||
.onTaskFragmentParentInfoChanged(mTaskFragment.getTaskFragmentOrganizer(),
|
|
||||||
mTaskFragment));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testOnTaskFragmentAppeared() {
|
public void testOnTaskFragmentAppeared() {
|
||||||
mController.registerOrganizer(mIOrganizer);
|
mController.registerOrganizer(mIOrganizer);
|
||||||
|
|
||||||
|
// No-op when the TaskFragment is not attached.
|
||||||
|
mController.onTaskFragmentAppeared(mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment);
|
||||||
|
mController.dispatchPendingEvents();
|
||||||
|
|
||||||
|
verify(mOrganizer, never()).onTaskFragmentAppeared(any());
|
||||||
|
|
||||||
|
// Send callback when the TaskFragment is attached.
|
||||||
|
setupMockParent(mTaskFragment, mTask);
|
||||||
|
|
||||||
mController.onTaskFragmentAppeared(mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment);
|
mController.onTaskFragmentAppeared(mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment);
|
||||||
mController.dispatchPendingEvents();
|
mController.dispatchPendingEvents();
|
||||||
|
|
||||||
@@ -159,9 +172,21 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
|
|||||||
@Test
|
@Test
|
||||||
public void testOnTaskFragmentInfoChanged() {
|
public void testOnTaskFragmentInfoChanged() {
|
||||||
mController.registerOrganizer(mIOrganizer);
|
mController.registerOrganizer(mIOrganizer);
|
||||||
|
setupMockParent(mTaskFragment, mTask);
|
||||||
|
|
||||||
|
// No-op if onTaskFragmentAppeared is not called yet.
|
||||||
|
mController.onTaskFragmentInfoChanged(mTaskFragment.getTaskFragmentOrganizer(),
|
||||||
|
mTaskFragment);
|
||||||
|
mController.dispatchPendingEvents();
|
||||||
|
|
||||||
|
verify(mOrganizer, never()).onTaskFragmentInfoChanged(any());
|
||||||
|
|
||||||
|
// Call onTaskFragmentAppeared first.
|
||||||
mController.onTaskFragmentAppeared(mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment);
|
mController.onTaskFragmentAppeared(mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment);
|
||||||
mController.dispatchPendingEvents();
|
mController.dispatchPendingEvents();
|
||||||
|
|
||||||
|
verify(mOrganizer).onTaskFragmentAppeared(any());
|
||||||
|
|
||||||
// No callback if the info is not changed.
|
// No callback if the info is not changed.
|
||||||
doReturn(true).when(mTaskFragmentInfo).equalsForTaskFragmentOrganizer(any());
|
doReturn(true).when(mTaskFragmentInfo).equalsForTaskFragmentOrganizer(any());
|
||||||
doReturn(new Configuration()).when(mTaskFragmentInfo).getConfiguration();
|
doReturn(new Configuration()).when(mTaskFragmentInfo).getConfiguration();
|
||||||
@@ -193,50 +218,75 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
|
|||||||
verify(mOrganizer).onTaskFragmentVanished(any());
|
verify(mOrganizer).onTaskFragmentVanished(any());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testOnTaskFragmentVanished_clearUpRemaining() {
|
||||||
|
mController.registerOrganizer(mIOrganizer);
|
||||||
|
setupMockParent(mTaskFragment, mTask);
|
||||||
|
|
||||||
|
// Not trigger onTaskFragmentAppeared.
|
||||||
|
mController.onTaskFragmentAppeared(mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment);
|
||||||
|
mController.onTaskFragmentVanished(mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment);
|
||||||
|
mController.dispatchPendingEvents();
|
||||||
|
|
||||||
|
verify(mOrganizer, never()).onTaskFragmentAppeared(any());
|
||||||
|
verify(mOrganizer, never()).onTaskFragmentInfoChanged(any());
|
||||||
|
verify(mOrganizer, never()).onTaskFragmentParentInfoChanged(anyInt(), any());
|
||||||
|
verify(mOrganizer).onTaskFragmentVanished(mTaskFragmentInfo);
|
||||||
|
|
||||||
|
// Not trigger onTaskFragmentInfoChanged.
|
||||||
|
// Call onTaskFragmentAppeared before calling onTaskFragmentInfoChanged.
|
||||||
|
mController.onTaskFragmentAppeared(mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment);
|
||||||
|
mController.dispatchPendingEvents();
|
||||||
|
clearInvocations(mOrganizer);
|
||||||
|
doReturn(true).when(mTaskFragmentInfo).equalsForTaskFragmentOrganizer(any());
|
||||||
|
mController.onTaskFragmentInfoChanged(mTaskFragment.getTaskFragmentOrganizer(),
|
||||||
|
mTaskFragment);
|
||||||
|
mController.onTaskFragmentVanished(mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment);
|
||||||
|
mController.dispatchPendingEvents();
|
||||||
|
|
||||||
|
verify(mOrganizer, never()).onTaskFragmentAppeared(any());
|
||||||
|
verify(mOrganizer, never()).onTaskFragmentInfoChanged(any());
|
||||||
|
verify(mOrganizer, never()).onTaskFragmentParentInfoChanged(anyInt(), any());
|
||||||
|
verify(mOrganizer).onTaskFragmentVanished(mTaskFragmentInfo);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testOnTaskFragmentParentInfoChanged() {
|
public void testOnTaskFragmentParentInfoChanged() {
|
||||||
mController.registerOrganizer(mIOrganizer);
|
mController.registerOrganizer(mIOrganizer);
|
||||||
final Task parent = mock(Task.class);
|
setupMockParent(mTaskFragment, mTask);
|
||||||
final Configuration parentConfig = new Configuration();
|
mTask.getConfiguration().smallestScreenWidthDp = 10;
|
||||||
parentConfig.smallestScreenWidthDp = 10;
|
|
||||||
doReturn(parent).when(mTaskFragment).getTask();
|
|
||||||
doReturn(parentConfig).when(parent).getConfiguration();
|
|
||||||
// Task needs to be visible
|
|
||||||
parent.lastActiveTime = 100;
|
|
||||||
doReturn(true).when(parent).shouldBeVisible(any());
|
|
||||||
|
|
||||||
mTaskFragment.mTaskFragmentAppearedSent = true;
|
mController.onTaskFragmentAppeared(
|
||||||
mController.onTaskFragmentParentInfoChanged(
|
|
||||||
mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment);
|
mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment);
|
||||||
mController.dispatchPendingEvents();
|
mController.dispatchPendingEvents();
|
||||||
|
|
||||||
verify(mOrganizer).onTaskFragmentParentInfoChanged(eq(mFragmentToken), any());
|
verify(mOrganizer).onTaskFragmentParentInfoChanged(eq(mTask.mTaskId), any());
|
||||||
|
|
||||||
// No extra callback if the info is not changed.
|
// No extra callback if the info is not changed.
|
||||||
clearInvocations(mOrganizer);
|
clearInvocations(mOrganizer);
|
||||||
|
|
||||||
mController.onTaskFragmentParentInfoChanged(
|
mController.onTaskFragmentInfoChanged(
|
||||||
mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment);
|
mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment);
|
||||||
mController.dispatchPendingEvents();
|
mController.dispatchPendingEvents();
|
||||||
|
|
||||||
verify(mOrganizer, never()).onTaskFragmentParentInfoChanged(any(), any());
|
verify(mOrganizer, never()).onTaskFragmentParentInfoChanged(anyInt(), any());
|
||||||
|
|
||||||
// Trigger callback if the size is changed.
|
// Trigger callback if the size is changed.
|
||||||
parentConfig.smallestScreenWidthDp = 100;
|
mTask.getConfiguration().smallestScreenWidthDp = 100;
|
||||||
mController.onTaskFragmentParentInfoChanged(
|
mController.onTaskFragmentInfoChanged(
|
||||||
mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment);
|
mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment);
|
||||||
mController.dispatchPendingEvents();
|
mController.dispatchPendingEvents();
|
||||||
|
|
||||||
verify(mOrganizer).onTaskFragmentParentInfoChanged(eq(mFragmentToken), any());
|
verify(mOrganizer).onTaskFragmentParentInfoChanged(eq(mTask.mTaskId), any());
|
||||||
|
|
||||||
// Trigger callback if the windowing mode is changed.
|
// Trigger callback if the windowing mode is changed.
|
||||||
clearInvocations(mOrganizer);
|
clearInvocations(mOrganizer);
|
||||||
parentConfig.windowConfiguration.setWindowingMode(WINDOWING_MODE_PINNED);
|
mTask.getConfiguration().windowConfiguration.setWindowingMode(WINDOWING_MODE_PINNED);
|
||||||
mController.onTaskFragmentParentInfoChanged(
|
mController.onTaskFragmentInfoChanged(
|
||||||
mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment);
|
mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment);
|
||||||
mController.dispatchPendingEvents();
|
mController.dispatchPendingEvents();
|
||||||
|
|
||||||
verify(mOrganizer).onTaskFragmentParentInfoChanged(eq(mFragmentToken), any());
|
verify(mOrganizer).onTaskFragmentParentInfoChanged(eq(mTask.mTaskId), any());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -1091,4 +1141,15 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
|
|||||||
.put(mFragmentToken, mTaskFragment);
|
.put(mFragmentToken, mTaskFragment);
|
||||||
mTaskFragment.getTask().setWindowingMode(WINDOWING_MODE_PINNED);
|
mTaskFragment.getTask().setWindowingMode(WINDOWING_MODE_PINNED);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Setups the mock Task as the parent of the given TaskFragment. */
|
||||||
|
private static void setupMockParent(TaskFragment taskFragment, Task mockParent) {
|
||||||
|
doReturn(mockParent).when(taskFragment).getTask();
|
||||||
|
final Configuration taskConfig = new Configuration();
|
||||||
|
doReturn(taskConfig).when(mockParent).getConfiguration();
|
||||||
|
|
||||||
|
// Task needs to be visible
|
||||||
|
mockParent.lastActiveTime = 100;
|
||||||
|
doReturn(true).when(mockParent).shouldBeVisible(any());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user