summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/window/TaskFragmentOrganizer.java72
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizer.java17
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java34
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskSupervisor.java5
-rw-r--r--services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java333
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java111
6 files changed, 352 insertions, 220 deletions
diff --git a/core/java/android/window/TaskFragmentOrganizer.java b/core/java/android/window/TaskFragmentOrganizer.java
index c9a568815fb1..84302dd19097 100644
--- a/core/java/android/window/TaskFragmentOrganizer.java
+++ b/core/java/android/window/TaskFragmentOrganizer.java
@@ -32,8 +32,10 @@ import android.content.res.Configuration;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
+import android.util.SparseArray;
import android.view.RemoteAnimationDefinition;
+import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executor;
@@ -72,6 +74,12 @@ public class TaskFragmentOrganizer extends WindowOrganizer {
*/
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) {
mExecutor = executor;
}
@@ -161,6 +169,27 @@ public class TaskFragmentOrganizer extends WindowOrganizer {
@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
* {@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();
for (TaskFragmentTransaction.Change change : changes) {
// TODO(b/240519866): apply all changes in one WCT.
+ final int taskId = change.getTaskId();
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());
+ // TODO(b/240519866): doing so to keep CTS compatibility. Remove in the next
+ // release.
+ if (!mTaskIdToFragmentTokens.contains(taskId)) {
+ mTaskIdToFragmentTokens.put(taskId, new ArrayList<>());
}
+ mTaskIdToFragmentTokens.get(taskId).add(change.getTaskFragmentToken());
+ onTaskFragmentParentInfoChanged(change.getTaskFragmentToken(),
+ mTaskIdToConfigurations.get(taskId));
+
+ onTaskFragmentAppeared(change.getTaskFragmentInfo());
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:
+ // 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());
break;
case TYPE_TASK_FRAGMENT_PARENT_INFO_CHANGED:
- onTaskFragmentParentInfoChanged(
- change.getTaskFragmentToken(),
- change.getTaskConfiguration());
+ // TODO(b/240519866): doing so to keep CTS compatibility. Remove in the next
+ // release.
+ mTaskIdToConfigurations.put(taskId, change.getTaskConfiguration());
+
+ onTaskFragmentParentInfoChanged(taskId, change.getTaskConfiguration());
break;
case TYPE_TASK_FRAGMENT_ERROR:
final Bundle errorBundle = change.getErrorBundle();
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizer.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizer.java
index 0dba6b0049c0..d42fca244120 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizer.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizer.java
@@ -51,12 +51,6 @@ class JetpackTaskFragmentOrganizer extends TaskFragmentOrganizer {
@VisibleForTesting
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;
@VisibleForTesting
TaskFragmentAnimationController mAnimationController;
@@ -68,8 +62,7 @@ class JetpackTaskFragmentOrganizer extends TaskFragmentOrganizer {
void onTaskFragmentAppeared(@NonNull TaskFragmentInfo taskFragmentInfo);
void onTaskFragmentInfoChanged(@NonNull TaskFragmentInfo taskFragmentInfo);
void onTaskFragmentVanished(@NonNull TaskFragmentInfo taskFragmentInfo);
- void onTaskFragmentParentInfoChanged(@NonNull IBinder fragmentToken,
- @NonNull Configuration parentConfig);
+ void onTaskFragmentParentInfoChanged(int taskId, @NonNull Configuration parentConfig);
void onActivityReparentToTask(int taskId, @NonNull Intent activityIntent,
@NonNull IBinder activityToken);
void onTaskFragmentError(@Nullable TaskFragmentInfo taskFragmentInfo, int opType);
@@ -300,7 +293,6 @@ class JetpackTaskFragmentOrganizer extends TaskFragmentOrganizer {
@Override
public void onTaskFragmentVanished(@NonNull TaskFragmentInfo taskFragmentInfo) {
mFragmentInfos.remove(taskFragmentInfo.getFragmentToken());
- mFragmentParentConfigs.remove(taskFragmentInfo.getFragmentToken());
if (mCallback != null) {
mCallback.onTaskFragmentVanished(taskFragmentInfo);
@@ -308,12 +300,9 @@ class JetpackTaskFragmentOrganizer extends TaskFragmentOrganizer {
}
@Override
- public void onTaskFragmentParentInfoChanged(
- @NonNull IBinder fragmentToken, @NonNull Configuration parentConfig) {
- mFragmentParentConfigs.put(fragmentToken, parentConfig);
-
+ public void onTaskFragmentParentInfoChanged(int taskId, @NonNull Configuration parentConfig) {
if (mCallback != null) {
- mCallback.onTaskFragmentParentInfoChanged(fragmentToken, parentConfig);
+ mCallback.onTaskFragmentParentInfoChanged(taskId, parentConfig);
}
}
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
index c688080ad929..dad07394e3fb 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
@@ -155,6 +155,9 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
container.setInfo(taskFragmentInfo);
if (container.isFinished()) {
mPresenter.cleanupContainer(container, false /* shouldFinishDependent */);
+ } else {
+ // Update with the latest Task configuration.
+ mPresenter.updateContainer(container);
}
updateCallbackIfNecessary();
}
@@ -233,19 +236,30 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
}
@Override
- public void onTaskFragmentParentInfoChanged(@NonNull IBinder fragmentToken,
- @NonNull Configuration parentConfig) {
+ public void onTaskFragmentParentInfoChanged(int taskId, @NonNull Configuration parentConfig) {
synchronized (mLock) {
- final TaskFragmentContainer container = getContainer(fragmentToken);
- if (container != null) {
- onTaskConfigurationChanged(container.getTaskId(), parentConfig);
- if (isInPictureInPicture(parentConfig)) {
- // No need to update presentation in PIP until the Task exit PIP.
- return;
+ onTaskConfigurationChanged(taskId, parentConfig);
+ if (isInPictureInPicture(parentConfig)) {
+ // No need to update presentation in PIP until the Task exit PIP.
+ return;
+ }
+ final TaskContainer taskContainer = getTaskContainer(taskId);
+ 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);
}
- mPresenter.updateContainer(container);
- updateCallbackIfNecessary();
}
+ updateCallbackIfNecessary();
}
}
diff --git a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
index 84740683f6aa..8878944e142e 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
@@ -887,11 +887,12 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks {
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
// the activity creation.
mService.mTaskFragmentOrganizerController.dispatchPendingInfoChangedEvent(
- r.getOrganizedTaskFragment());
+ organizedTaskFragment);
}
// Create activity launch transaction.
diff --git a/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java b/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java
index a4d6f70b011e..6ca564833d41 100644
--- a/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java
+++ b/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java
@@ -16,6 +16,7 @@
package com.android.server.wm;
+import static android.app.ActivityTaskManager.INVALID_TASK_ID;
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;
@@ -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.WindowOrganizerController.configurationsAreEqualForOrganizer;
+import static java.util.Objects.requireNonNull;
+
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -38,6 +41,7 @@ import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.ArrayMap;
+import android.util.ArraySet;
import android.util.Slog;
import android.util.SparseArray;
import android.view.RemoteAnimationDefinition;
@@ -51,6 +55,7 @@ import com.android.internal.protolog.common.ProtoLog;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
+import java.util.List;
import java.util.Map;
import java.util.WeakHashMap;
@@ -70,15 +75,12 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
private final ArrayMap<IBinder, TaskFragmentOrganizerState> mTaskFragmentOrganizerState =
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 =
- new ArrayList<>();
-
- /** Map from {@link ITaskFragmentOrganizer} to {@link TaskFragmentTransaction}. */
- private final ArrayMap<IBinder, TaskFragmentTransaction> mTmpOrganizerToTransactionMap =
+ private final ArrayMap<IBinder, List<PendingTaskFragmentEvent>> mPendingTaskFragmentEvents =
new ArrayMap<>();
- private final ArrayList<ITaskFragmentOrganizer> mTmpOrganizerList = new ArrayList<>();
+
+ private final ArraySet<Task> mTmpTaskSet = new ArraySet<>();
TaskFragmentOrganizerController(ActivityTaskManagerService atm) {
mAtmService = atm;
@@ -94,10 +96,30 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
private final ITaskFragmentOrganizer mOrganizer;
private final int mOrganizerPid;
private final int mOrganizerUid;
+
+ /**
+ * Map from {@link TaskFragment} to the last {@link TaskFragmentInfo} sent to the
+ * organizer.
+ */
private final Map<TaskFragment, TaskFragmentInfo> mLastSentTaskFragmentInfos =
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 =
new WeakHashMap<>();
@@ -161,21 +183,15 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
TaskFragmentTransaction.Change prepareTaskFragmentAppeared(@NonNull TaskFragment tf) {
ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "TaskFragment appeared name=%s", tf.getName());
final TaskFragmentInfo info = tf.getTaskFragmentInfo();
+ final int taskId = tf.getTask().mTaskId;
tf.mTaskFragmentAppearedSent = true;
mLastSentTaskFragmentInfos.put(tf, info);
- final TaskFragmentTransaction.Change change =
- new TaskFragmentTransaction.Change(TYPE_TASK_FRAGMENT_APPEARED)
- .setTaskFragmentToken(tf.getFragmentToken())
- .setTaskFragmentInfo(info);
- if (shouldSendTaskFragmentParentInfoChanged(tf)) {
- // TODO(b/240519866): convert to pass TaskConfiguration for all TFs in the same Task
- final Task task = tf.getTask();
- mLastSentTaskFragmentParentConfigs
- .put(tf, new Configuration(task.getConfiguration()));
- change.setTaskId(task.mTaskId)
- .setTaskConfiguration(task.getConfiguration());
- }
- return change;
+ mTaskFragmentTaskIds.put(tf, taskId);
+ return new TaskFragmentTransaction.Change(
+ TYPE_TASK_FRAGMENT_APPEARED)
+ .setTaskFragmentToken(tf.getFragmentToken())
+ .setTaskFragmentInfo(info)
+ .setTaskId(taskId);
}
@NonNull
@@ -183,10 +199,24 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "TaskFragment vanished name=%s", tf.getName());
tf.mTaskFragmentAppearedSent = false;
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)
.setTaskFragmentToken(tf.getFragmentToken())
- .setTaskFragmentInfo(tf.getTaskFragmentInfo());
+ .setTaskFragmentInfo(tf.getTaskFragmentInfo())
+ .setTaskId(taskId);
}
@Nullable
@@ -197,65 +227,39 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
final TaskFragmentInfo lastInfo = mLastSentTaskFragmentInfos.get(tf);
if (info.equalsForTaskFragmentOrganizer(lastInfo) && configurationsAreEqualForOrganizer(
info.getConfiguration(), lastInfo.getConfiguration())) {
- // Parent config may have changed. The controller will check if there is any
- // important config change for the organizer.
- return prepareTaskFragmentParentInfoChanged(tf);
+ return null;
}
ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "TaskFragment info changed name=%s",
tf.getName());
mLastSentTaskFragmentInfos.put(tf, info);
- final TaskFragmentTransaction.Change change =
- new TaskFragmentTransaction.Change(TYPE_TASK_FRAGMENT_INFO_CHANGED)
- .setTaskFragmentToken(tf.getFragmentToken())
- .setTaskFragmentInfo(info);
- if (shouldSendTaskFragmentParentInfoChanged(tf)) {
- // TODO(b/240519866): convert to pass TaskConfiguration for all TFs in the same Task
- // at once.
- // Parent config may have changed. The controller will check if there is any
- // important config change for the organizer.
- final Task task = tf.getTask();
- mLastSentTaskFragmentParentConfigs
- .put(tf, new Configuration(task.getConfiguration()));
- change.setTaskId(task.mTaskId)
- .setTaskConfiguration(task.getConfiguration());
- }
- return change;
+ return new TaskFragmentTransaction.Change(
+ TYPE_TASK_FRAGMENT_INFO_CHANGED)
+ .setTaskFragmentToken(tf.getFragmentToken())
+ .setTaskFragmentInfo(info)
+ .setTaskId(tf.getTask().mTaskId);
}
@Nullable
TaskFragmentTransaction.Change prepareTaskFragmentParentInfoChanged(
- @NonNull TaskFragment tf) {
- if (!shouldSendTaskFragmentParentInfoChanged(tf)) {
+ @NonNull Task task) {
+ final int taskId = task.mTaskId;
+ // Check if the parent info is different from the last reported parent info.
+ final Configuration taskConfig = task.getConfiguration();
+ final Configuration lastParentConfig = mLastSentTaskFragmentParentConfigs.get(taskId);
+ if (configurationsAreEqualForOrganizer(taskConfig, lastParentConfig)
+ && taskConfig.windowConfiguration.getWindowingMode()
+ == lastParentConfig.windowConfiguration.getWindowingMode()) {
return null;
}
- final Task parent = tf.getTask();
- final Configuration parentConfig = parent.getConfiguration();
ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER,
"TaskFragment parent info changed name=%s parentTaskId=%d",
- tf.getName(), parent.mTaskId);
- mLastSentTaskFragmentParentConfigs.put(tf, new Configuration(parentConfig));
+ task.getName(), taskId);
+ mLastSentTaskFragmentParentConfigs.put(taskId, new Configuration(taskConfig));
return new TaskFragmentTransaction.Change(TYPE_TASK_FRAGMENT_PARENT_INFO_CHANGED)
- .setTaskFragmentToken(tf.getFragmentToken())
- .setTaskId(parent.mTaskId)
- .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();
+ .setTaskId(taskId)
+ .setTaskConfiguration(taskConfig);
}
@NonNull
@@ -345,6 +349,7 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
}
mTaskFragmentOrganizerState.put(organizer.asBinder(),
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,
@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);
if (!state.addTaskFragment(taskFragment)) {
return;
@@ -441,28 +451,15 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
PendingTaskFragmentEvent pendingEvent = getPendingTaskFragmentEvent(taskFragment,
PendingTaskFragmentEvent.EVENT_APPEARED);
if (pendingEvent == null) {
- pendingEvent = new PendingTaskFragmentEvent.Builder(
+ addPendingEvent(new PendingTaskFragmentEvent.Builder(
PendingTaskFragmentEvent.EVENT_APPEARED, organizer)
.setTaskFragment(taskFragment)
- .build();
- mPendingTaskFragmentEvents.add(pendingEvent);
+ .build());
}
}
void onTaskFragmentInfoChanged(@NonNull ITaskFragmentOrganizer organizer,
@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);
if (!taskFragment.mTaskFragmentAppearedSent) {
// Skip if TaskFragment still not appeared.
@@ -470,45 +467,41 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
}
PendingTaskFragmentEvent pendingEvent = getLastPendingLifecycleEvent(taskFragment);
if (pendingEvent == null) {
- pendingEvent = new PendingTaskFragmentEvent.Builder(eventType, organizer)
- .setTaskFragment(taskFragment)
- .build();
+ pendingEvent = new PendingTaskFragmentEvent.Builder(
+ PendingTaskFragmentEvent.EVENT_INFO_CHANGED, organizer)
+ .setTaskFragment(taskFragment)
+ .build();
} else {
if (pendingEvent.mEventType == PendingTaskFragmentEvent.EVENT_VANISHED) {
// Skipped the info changed event if vanished event is pending.
return;
}
// 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
// the event should be sent to the organizer, for example the TaskFragment may become
// empty.
pendingEvent.mDeferTime = 0;
}
- mPendingTaskFragmentEvents.add(pendingEvent);
+ addPendingEvent(pendingEvent);
}
void onTaskFragmentVanished(@NonNull ITaskFragmentOrganizer organizer,
@NonNull TaskFragment taskFragment) {
final TaskFragmentOrganizerState state = validateAndGetState(organizer);
- for (int i = mPendingTaskFragmentEvents.size() - 1; i >= 0; i--) {
- PendingTaskFragmentEvent entry = mPendingTaskFragmentEvents.get(i);
- if (taskFragment == entry.mTaskFragment) {
- mPendingTaskFragmentEvents.remove(i);
- if (entry.mEventType == PendingTaskFragmentEvent.EVENT_APPEARED) {
- // If taskFragment appeared callback is pending, ignore the vanished request.
- return;
- }
+ final List<PendingTaskFragmentEvent> pendingEvents = mPendingTaskFragmentEvents
+ .get(organizer.asBinder());
+ // Remove any pending events since this TaskFragment is being removed.
+ for (int i = pendingEvents.size() - 1; i >= 0; i--) {
+ final PendingTaskFragmentEvent event = pendingEvents.get(i);
+ if (taskFragment == event.mTaskFragment) {
+ pendingEvents.remove(i);
}
}
- if (!taskFragment.mTaskFragmentAppearedSent) {
- return;
- }
- final PendingTaskFragmentEvent pendingEvent = new PendingTaskFragmentEvent.Builder(
+ addPendingEvent(new PendingTaskFragmentEvent.Builder(
PendingTaskFragmentEvent.EVENT_VANISHED, organizer)
.setTaskFragment(taskFragment)
- .build();
- mPendingTaskFragmentEvents.add(pendingEvent);
+ .build());
state.removeTaskFragment(taskFragment);
}
@@ -517,14 +510,13 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
int opType, @NonNull Throwable exception) {
validateAndGetState(organizer);
Slog.w(TAG, "onTaskFragmentError ", exception);
- final PendingTaskFragmentEvent pendingEvent = new PendingTaskFragmentEvent.Builder(
+ addPendingEvent(new PendingTaskFragmentEvent.Builder(
PendingTaskFragmentEvent.EVENT_ERROR, organizer)
.setErrorCallbackToken(errorCallbackToken)
.setTaskFragment(taskFragment)
.setException(exception)
.setOpType(opType)
- .build();
- mPendingTaskFragmentEvents.add(pendingEvent);
+ .build());
// Make sure the error event will be dispatched if there are no other changes.
mAtmService.mWindowManager.mWindowPlacerLocked.requestTraversal();
}
@@ -554,11 +546,18 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
Slog.w(TAG, "The last TaskFragmentOrganizer no longer exists");
return;
}
- final PendingTaskFragmentEvent pendingEvent = new PendingTaskFragmentEvent.Builder(
+ addPendingEvent(new PendingTaskFragmentEvent.Builder(
PendingTaskFragmentEvent.EVENT_ACTIVITY_REPARENT_TO_TASK, organizer)
.setActivity(activity)
- .build();
- mPendingTaskFragmentEvents.add(pendingEvent);
+ .build());
+ }
+
+ 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) {
@@ -570,12 +569,7 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
// remove all of the children of the organized TaskFragment
state.dispose();
// Remove any pending event of this organizer.
- for (int i = mPendingTaskFragmentEvents.size() - 1; i >= 0; i--) {
- final PendingTaskFragmentEvent event = mPendingTaskFragmentEvents.get(i);
- if (event.mTaskFragmentOrg.asBinder().equals(organizer.asBinder())) {
- mPendingTaskFragmentEvents.remove(i);
- }
- }
+ mPendingTaskFragmentEvents.remove(organizer.asBinder());
mTaskFragmentOrganizerState.remove(organizer.asBinder());
}
@@ -631,6 +625,8 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
private final Throwable mException;
@Nullable
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
// be the last active time of the host task.
private long mDeferTime;
@@ -642,6 +638,7 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
@Nullable IBinder errorCallbackToken,
@Nullable Throwable exception,
@Nullable ActivityRecord activity,
+ @Nullable Task task,
int opType) {
mEventType = eventType;
mTaskFragmentOrg = taskFragmentOrg;
@@ -649,6 +646,7 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
mErrorCallbackToken = errorCallbackToken;
mException = exception;
mActivity = activity;
+ mTask = task;
mOpType = opType;
}
@@ -680,11 +678,13 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
private Throwable mException;
@Nullable
private ActivityRecord mActivity;
+ @Nullable
+ private Task mTask;
private int mOpType;
- Builder(@EventType int eventType, ITaskFragmentOrganizer taskFragmentOrg) {
+ Builder(@EventType int eventType, @NonNull ITaskFragmentOrganizer taskFragmentOrg) {
mEventType = eventType;
- mTaskFragmentOrg = taskFragmentOrg;
+ mTaskFragmentOrg = requireNonNull(taskFragmentOrg);
}
Builder setTaskFragment(@Nullable TaskFragment taskFragment) {
@@ -697,13 +697,18 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
return this;
}
- Builder setException(@Nullable Throwable exception) {
- mException = exception;
+ Builder setException(@NonNull Throwable exception) {
+ mException = requireNonNull(exception);
return this;
}
- Builder setActivity(@Nullable ActivityRecord activity) {
- mActivity = activity;
+ Builder setActivity(@NonNull ActivityRecord activity) {
+ mActivity = requireNonNull(activity);
+ return this;
+ }
+
+ Builder setTask(@NonNull Task task) {
+ mTask = requireNonNull(task);
return this;
}
@@ -714,17 +719,20 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
PendingTaskFragmentEvent build() {
return new PendingTaskFragmentEvent(mEventType, mTaskFragmentOrg, mTaskFragment,
- mErrorCallbackToken, mException, mActivity, mOpType);
+ mErrorCallbackToken, mException, mActivity, mTask, mOpType);
}
}
}
@Nullable
private PendingTaskFragmentEvent getLastPendingLifecycleEvent(@NonNull TaskFragment tf) {
- for (int i = mPendingTaskFragmentEvents.size() - 1; i >= 0; i--) {
- PendingTaskFragmentEvent entry = mPendingTaskFragmentEvents.get(i);
- if (tf == entry.mTaskFragment && entry.isLifecycleEvent()) {
- return entry;
+ final ITaskFragmentOrganizer organizer = tf.getTaskFragmentOrganizer();
+ final List<PendingTaskFragmentEvent> events = mPendingTaskFragmentEvents
+ .get(organizer.asBinder());
+ 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;
@@ -733,10 +741,13 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
@Nullable
private PendingTaskFragmentEvent getPendingTaskFragmentEvent(@NonNull TaskFragment taskFragment,
int type) {
- for (int i = mPendingTaskFragmentEvents.size() - 1; i >= 0; i--) {
- PendingTaskFragmentEvent entry = mPendingTaskFragmentEvents.get(i);
- if (taskFragment == entry.mTaskFragment && type == entry.mEventType) {
- return entry;
+ final ITaskFragmentOrganizer organizer = taskFragment.getTaskFragmentOrganizer();
+ final List<PendingTaskFragmentEvent> events = mPendingTaskFragmentEvents
+ .get(organizer.asBinder());
+ 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;
@@ -762,12 +773,25 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
|| mPendingTaskFragmentEvents.isEmpty()) {
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> invisibleTasks = new ArrayList<>();
final ArrayList<PendingTaskFragmentEvent> candidateEvents = new ArrayList<>();
- for (int i = 0, n = mPendingTaskFragmentEvents.size(); i < n; i++) {
- final PendingTaskFragmentEvent event = mPendingTaskFragmentEvents.get(i);
+ for (int i = 0, n = pendingEvents.size(); i < n; i++) {
+ final PendingTaskFragmentEvent event = pendingEvents.get(i);
final Task task = event.mTaskFragment != null ? event.mTaskFragment.getTask() : null;
if (task != null && (task.lastActiveTime <= event.mDeferTime
|| !(isTaskVisible(task, visibleTasks, invisibleTasks)
@@ -783,27 +807,26 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
return;
}
- mTmpOrganizerToTransactionMap.clear();
- mTmpOrganizerList.clear();
+ mTmpTaskSet.clear();
+ final TaskFragmentTransaction transaction = new TaskFragmentTransaction();
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();
+ if (event.mEventType == PendingTaskFragmentEvent.EVENT_APPEARED
+ || event.mEventType == PendingTaskFragmentEvent.EVENT_INFO_CHANGED) {
+ final Task task = event.mTaskFragment.getTask();
+ 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()));
+ }
+ }
+ transaction.addChange(prepareChange(event));
+ }
+ mTmpTaskSet.clear();
+ dispatchTransactionInfo(organizer, transaction);
+ pendingEvents.removeAll(candidateEvents);
}
private static boolean isTaskVisible(@NonNull Task task,
@@ -831,10 +854,16 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
return;
}
+ final ITaskFragmentOrganizer organizer = taskFragment.getTaskFragmentOrganizer();
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));
dispatchTransactionInfo(event.mTaskFragmentOrg, transaction);
- mPendingTaskFragmentEvents.remove(event);
+ mPendingTaskFragmentEvents.get(organizer.asBinder()).remove(event);
}
private void dispatchTransactionInfo(@NonNull ITaskFragmentOrganizer organizer,
@@ -867,7 +896,7 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
case PendingTaskFragmentEvent.EVENT_INFO_CHANGED:
return state.prepareTaskFragmentInfoChanged(taskFragment);
case PendingTaskFragmentEvent.EVENT_PARENT_INFO_CHANGED:
- return state.prepareTaskFragmentParentInfoChanged(taskFragment);
+ return state.prepareTaskFragmentParentInfoChanged(event.mTask);
case PendingTaskFragmentEvent.EVENT_ERROR:
return state.prepareTaskFragmentError(event.mErrorCallbackToken, taskFragment,
event.mOpType, event.mException);
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java
index f38731b2f739..8b3cff8039d4 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java
@@ -75,6 +75,8 @@ import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
/**
* Build/Install/Run:
@@ -92,7 +94,6 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
private TaskFragmentOrganizerToken mOrganizerToken;
private ITaskFragmentOrganizer mIOrganizer;
private TaskFragment mTaskFragment;
- private TaskFragmentInfo mTaskFragmentInfo;
private IBinder mFragmentToken;
private WindowContainerTransaction mTransaction;
private WindowContainerToken mFragmentWindowToken;
@@ -100,14 +101,19 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
private IBinder mErrorToken;
private Rect mTaskFragBounds;
+ @Mock
+ private TaskFragmentInfo mTaskFragmentInfo;
+ @Mock
+ private Task mTask;
+
@Before
public void setup() {
+ MockitoAnnotations.initMocks(this);
mWindowOrganizerController = mAtm.mWindowOrganizerController;
mController = mWindowOrganizerController.mTaskFragmentOrganizerController;
mOrganizer = new TaskFragmentOrganizer(Runnable::run);
mOrganizerToken = mOrganizer.getOrganizerToken();
mIOrganizer = ITaskFragmentOrganizer.Stub.asInterface(mOrganizerToken.asBinder());
- mTaskFragmentInfo = mock(TaskFragmentInfo.class);
mFragmentToken = new Binder();
mTaskFragment =
new TaskFragment(mAtm, mFragmentToken, true /* createdByOrganizer */);
@@ -131,6 +137,8 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
@Test
public void testCallTaskFragmentCallbackWithoutRegister_throwsException() {
+ doReturn(mTask).when(mTaskFragment).getTask();
+
assertThrows(IllegalArgumentException.class, () -> mController
.onTaskFragmentAppeared(mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment));
@@ -140,16 +148,21 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
assertThrows(IllegalArgumentException.class, () -> mController
.onTaskFragmentVanished(mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment));
-
- assertThrows(IllegalArgumentException.class, () -> mController
- .onTaskFragmentParentInfoChanged(mTaskFragment.getTaskFragmentOrganizer(),
- mTaskFragment));
}
@Test
public void testOnTaskFragmentAppeared() {
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.dispatchPendingEvents();
@@ -159,9 +172,21 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
@Test
public void testOnTaskFragmentInfoChanged() {
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.dispatchPendingEvents();
+ verify(mOrganizer).onTaskFragmentAppeared(any());
+
// No callback if the info is not changed.
doReturn(true).when(mTaskFragmentInfo).equalsForTaskFragmentOrganizer(any());
doReturn(new Configuration()).when(mTaskFragmentInfo).getConfiguration();
@@ -194,49 +219,74 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
}
@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
public void testOnTaskFragmentParentInfoChanged() {
mController.registerOrganizer(mIOrganizer);
- final Task parent = mock(Task.class);
- final Configuration parentConfig = new Configuration();
- 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());
+ setupMockParent(mTaskFragment, mTask);
+ mTask.getConfiguration().smallestScreenWidthDp = 10;
- mTaskFragment.mTaskFragmentAppearedSent = true;
- mController.onTaskFragmentParentInfoChanged(
+ mController.onTaskFragmentAppeared(
mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment);
mController.dispatchPendingEvents();
- verify(mOrganizer).onTaskFragmentParentInfoChanged(eq(mFragmentToken), any());
+ verify(mOrganizer).onTaskFragmentParentInfoChanged(eq(mTask.mTaskId), any());
// No extra callback if the info is not changed.
clearInvocations(mOrganizer);
- mController.onTaskFragmentParentInfoChanged(
+ mController.onTaskFragmentInfoChanged(
mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment);
mController.dispatchPendingEvents();
- verify(mOrganizer, never()).onTaskFragmentParentInfoChanged(any(), any());
+ verify(mOrganizer, never()).onTaskFragmentParentInfoChanged(anyInt(), any());
// Trigger callback if the size is changed.
- parentConfig.smallestScreenWidthDp = 100;
- mController.onTaskFragmentParentInfoChanged(
+ mTask.getConfiguration().smallestScreenWidthDp = 100;
+ mController.onTaskFragmentInfoChanged(
mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment);
mController.dispatchPendingEvents();
- verify(mOrganizer).onTaskFragmentParentInfoChanged(eq(mFragmentToken), any());
+ verify(mOrganizer).onTaskFragmentParentInfoChanged(eq(mTask.mTaskId), any());
// Trigger callback if the windowing mode is changed.
clearInvocations(mOrganizer);
- parentConfig.windowConfiguration.setWindowingMode(WINDOWING_MODE_PINNED);
- mController.onTaskFragmentParentInfoChanged(
+ mTask.getConfiguration().windowConfiguration.setWindowingMode(WINDOWING_MODE_PINNED);
+ mController.onTaskFragmentInfoChanged(
mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment);
mController.dispatchPendingEvents();
- verify(mOrganizer).onTaskFragmentParentInfoChanged(eq(mFragmentToken), any());
+ verify(mOrganizer).onTaskFragmentParentInfoChanged(eq(mTask.mTaskId), any());
}
@Test
@@ -1091,4 +1141,15 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
.put(mFragmentToken, mTaskFragment);
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());
+ }
}