Wait for TaskFragmentOrganizer to finish handling transaction
When a TaskFragmentTransaction is sent to the organizer during a transition, have the transition wait for the organizer to finish handling the transaction. Bug: 207070762 Test: atest WmTests:TaskFragmentOrganizerControllerTest Change-Id: I4b7955171cd8ce386686ff2cd64b7c04a6436ddf
This commit is contained in:
@@ -16,8 +16,10 @@
|
||||
|
||||
package android.window;
|
||||
|
||||
import android.os.IBinder;
|
||||
import android.view.RemoteAnimationDefinition;
|
||||
import android.window.ITaskFragmentOrganizer;
|
||||
import android.window.WindowContainerTransaction;
|
||||
|
||||
/** @hide */
|
||||
interface ITaskFragmentOrganizerController {
|
||||
@@ -46,8 +48,15 @@ interface ITaskFragmentOrganizerController {
|
||||
void unregisterRemoteAnimations(in ITaskFragmentOrganizer organizer, int taskId);
|
||||
|
||||
/**
|
||||
* Checks if an activity organized by a {@link android.window.TaskFragmentOrganizer} and
|
||||
* only occupies a portion of Task bounds.
|
||||
*/
|
||||
* Checks if an activity organized by a {@link android.window.TaskFragmentOrganizer} and
|
||||
* only occupies a portion of Task bounds.
|
||||
*/
|
||||
boolean isActivityEmbedded(in IBinder activityToken);
|
||||
|
||||
/**
|
||||
* Notifies the server that the organizer has finished handling the given transaction. The
|
||||
* server should apply the given {@link WindowContainerTransaction} for the necessary changes.
|
||||
*/
|
||||
void onTransactionHandled(in ITaskFragmentOrganizer organizer, in IBinder transactionToken,
|
||||
in WindowContainerTransaction wct);
|
||||
}
|
||||
|
||||
@@ -26,7 +26,6 @@ import static android.window.TaskFragmentTransaction.TYPE_TASK_FRAGMENT_VANISHED
|
||||
import android.annotation.CallSuper;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.annotation.TestApi;
|
||||
import android.content.Intent;
|
||||
import android.content.res.Configuration;
|
||||
@@ -148,6 +147,28 @@ public class TaskFragmentOrganizer extends WindowOrganizer {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies the server that the organizer has finished handling the given transaction. The
|
||||
* server should apply the given {@link WindowContainerTransaction} for the necessary changes.
|
||||
*
|
||||
* @param transactionToken {@link TaskFragmentTransaction#getTransactionToken()} from
|
||||
* {@link #onTransactionReady(TaskFragmentTransaction)}
|
||||
* @param wct {@link WindowContainerTransaction} that the server should apply for
|
||||
* update of the transaction.
|
||||
* @see com.android.server.wm.WindowOrganizerController#enforceTaskPermission for permission
|
||||
* requirement.
|
||||
* @hide
|
||||
*/
|
||||
public void onTransactionHandled(@NonNull IBinder transactionToken,
|
||||
@NonNull WindowContainerTransaction wct) {
|
||||
wct.setTaskFragmentOrganizer(mInterface);
|
||||
try {
|
||||
getController().onTransactionHandled(mInterface, transactionToken, wct);
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a TaskFragment is created and organized by this organizer.
|
||||
*
|
||||
@@ -318,12 +339,8 @@ public class TaskFragmentOrganizer extends WindowOrganizer {
|
||||
/**
|
||||
* Called when the transaction is ready so that the organizer can update the TaskFragments based
|
||||
* on the changes in transaction.
|
||||
* Note: {@link WindowOrganizer#applyTransaction} permission requirement is conditional for
|
||||
* {@link TaskFragmentOrganizer}.
|
||||
* @see com.android.server.wm.WindowOrganizerController#enforceTaskPermission
|
||||
* @hide
|
||||
*/
|
||||
@SuppressLint("AndroidFrameworkRequiresPermission")
|
||||
public void onTransactionReady(@NonNull TaskFragmentTransaction transaction) {
|
||||
final WindowContainerTransaction wct = new WindowContainerTransaction();
|
||||
final List<TaskFragmentTransaction.Change> changes = transaction.getChanges();
|
||||
@@ -389,8 +406,9 @@ public class TaskFragmentOrganizer extends WindowOrganizer {
|
||||
"Unknown TaskFragmentEvent=" + change.getType());
|
||||
}
|
||||
}
|
||||
// TODO(b/240519866): notify TaskFragmentOrganizerController that the transition is done.
|
||||
applyTransaction(wct);
|
||||
|
||||
// Notify the server, and the server should apply the WindowContainerTransaction.
|
||||
onTransactionHandled(transaction.getTransactionToken(), wct);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -23,6 +23,7 @@ import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.content.Intent;
|
||||
import android.content.res.Configuration;
|
||||
import android.os.Binder;
|
||||
import android.os.Bundle;
|
||||
import android.os.IBinder;
|
||||
import android.os.Parcel;
|
||||
@@ -41,19 +42,31 @@ import java.util.List;
|
||||
*/
|
||||
public final class TaskFragmentTransaction implements Parcelable {
|
||||
|
||||
/** Unique token to represent this transaction. */
|
||||
private final IBinder mTransactionToken;
|
||||
|
||||
/** Changes in this transaction. */
|
||||
private final ArrayList<Change> mChanges = new ArrayList<>();
|
||||
|
||||
public TaskFragmentTransaction() {}
|
||||
public TaskFragmentTransaction() {
|
||||
mTransactionToken = new Binder();
|
||||
}
|
||||
|
||||
private TaskFragmentTransaction(Parcel in) {
|
||||
mTransactionToken = in.readStrongBinder();
|
||||
in.readTypedList(mChanges, Change.CREATOR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(@NonNull Parcel dest, int flags) {
|
||||
dest.writeStrongBinder(mTransactionToken);
|
||||
dest.writeTypedList(mChanges);
|
||||
}
|
||||
|
||||
public IBinder getTransactionToken() {
|
||||
return mTransactionToken;
|
||||
}
|
||||
|
||||
/** Adds a {@link Change} to this transaction. */
|
||||
public void addChange(@Nullable Change change) {
|
||||
if (change != null) {
|
||||
@@ -74,7 +87,9 @@ public final class TaskFragmentTransaction implements Parcelable {
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("TaskFragmentTransaction{changes=[");
|
||||
sb.append("TaskFragmentTransaction{token=");
|
||||
sb.append(mTransactionToken);
|
||||
sb.append(" changes=[");
|
||||
for (int i = 0; i < mChanges.size(); ++i) {
|
||||
if (i > 0) {
|
||||
sb.append(',');
|
||||
|
||||
@@ -2041,6 +2041,12 @@
|
||||
"group": "WM_DEBUG_CONFIGURATION",
|
||||
"at": "com\/android\/server\/wm\/ActivityRecord.java"
|
||||
},
|
||||
"-108248992": {
|
||||
"message": "Defer transition ready for TaskFragmentTransaction=%s",
|
||||
"level": "VERBOSE",
|
||||
"group": "WM_DEBUG_WINDOW_TRANSITIONS",
|
||||
"at": "com\/android\/server\/wm\/TaskFragmentOrganizerController.java"
|
||||
},
|
||||
"-106400104": {
|
||||
"message": "Preload recents with %s",
|
||||
"level": "DEBUG",
|
||||
@@ -2089,6 +2095,12 @@
|
||||
"group": "WM_DEBUG_STATES",
|
||||
"at": "com\/android\/server\/wm\/TaskFragment.java"
|
||||
},
|
||||
"-79016993": {
|
||||
"message": "Continue transition ready for TaskFragmentTransaction=%s",
|
||||
"level": "VERBOSE",
|
||||
"group": "WM_DEBUG_WINDOW_TRANSITIONS",
|
||||
"at": "com\/android\/server\/wm\/TaskFragmentOrganizerController.java"
|
||||
},
|
||||
"-70719599": {
|
||||
"message": "Unregister remote animations for organizer=%s uid=%d pid=%d",
|
||||
"level": "VERBOSE",
|
||||
|
||||
@@ -49,7 +49,9 @@ import android.window.ITaskFragmentOrganizer;
|
||||
import android.window.ITaskFragmentOrganizerController;
|
||||
import android.window.TaskFragmentInfo;
|
||||
import android.window.TaskFragmentTransaction;
|
||||
import android.window.WindowContainerTransaction;
|
||||
|
||||
import com.android.internal.protolog.ProtoLogGroup;
|
||||
import com.android.internal.protolog.common.ProtoLog;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
@@ -68,6 +70,8 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
|
||||
|
||||
private final ActivityTaskManagerService mAtmService;
|
||||
private final WindowManagerGlobalLock mGlobalLock;
|
||||
private final WindowOrganizerController mWindowOrganizerController;
|
||||
|
||||
/**
|
||||
* A Map which manages the relationship between
|
||||
* {@link ITaskFragmentOrganizer} and {@link TaskFragmentOrganizerState}
|
||||
@@ -82,9 +86,11 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
|
||||
|
||||
private final ArraySet<Task> mTmpTaskSet = new ArraySet<>();
|
||||
|
||||
TaskFragmentOrganizerController(ActivityTaskManagerService atm) {
|
||||
mAtmService = atm;
|
||||
TaskFragmentOrganizerController(@NonNull ActivityTaskManagerService atm,
|
||||
@NonNull WindowOrganizerController windowOrganizerController) {
|
||||
mAtmService = requireNonNull(atm);
|
||||
mGlobalLock = atm.mGlobalLock;
|
||||
mWindowOrganizerController = requireNonNull(windowOrganizerController);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -131,6 +137,14 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
|
||||
private final SparseArray<RemoteAnimationDefinition> mRemoteAnimationDefinitions =
|
||||
new SparseArray<>();
|
||||
|
||||
/**
|
||||
* List of {@link TaskFragmentTransaction#getTransactionToken()} that have been sent to the
|
||||
* organizer. If the transaction is sent during a transition, the
|
||||
* {@link TransitionController} will wait until the transaction is finished.
|
||||
* @see #onTransactionFinished(IBinder)
|
||||
*/
|
||||
private final List<IBinder> mRunningTransactions = new ArrayList<>();
|
||||
|
||||
TaskFragmentOrganizerState(ITaskFragmentOrganizer organizer, int pid, int uid) {
|
||||
mOrganizer = organizer;
|
||||
mOrganizerPid = pid;
|
||||
@@ -176,6 +190,10 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
|
||||
taskFragment.removeImmediately();
|
||||
mOrganizedTaskFragments.remove(taskFragment);
|
||||
}
|
||||
for (int i = mRunningTransactions.size() - 1; i >= 0; i--) {
|
||||
// Cleanup any running transaction to unblock the current transition.
|
||||
onTransactionFinished(mRunningTransactions.get(i));
|
||||
}
|
||||
mOrganizer.asBinder().unlinkToDeath(this, 0 /*flags*/);
|
||||
}
|
||||
|
||||
@@ -320,6 +338,40 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
|
||||
.setActivityIntent(activity.intent)
|
||||
.setActivityToken(activityToken);
|
||||
}
|
||||
|
||||
void dispatchTransaction(@NonNull TaskFragmentTransaction transaction) {
|
||||
if (transaction.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
mOrganizer.onTransactionReady(transaction);
|
||||
} catch (RemoteException e) {
|
||||
Slog.d(TAG, "Exception sending TaskFragmentTransaction", e);
|
||||
return;
|
||||
}
|
||||
onTransactionStarted(transaction.getTransactionToken());
|
||||
}
|
||||
|
||||
/** Called when the transaction is sent to the organizer. */
|
||||
void onTransactionStarted(@NonNull IBinder transactionToken) {
|
||||
if (!mWindowOrganizerController.getTransitionController().isCollecting()) {
|
||||
return;
|
||||
}
|
||||
ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS,
|
||||
"Defer transition ready for TaskFragmentTransaction=%s", transactionToken);
|
||||
mRunningTransactions.add(transactionToken);
|
||||
mWindowOrganizerController.getTransitionController().deferTransitionReady();
|
||||
}
|
||||
|
||||
/** Called when the transaction is finished. */
|
||||
void onTransactionFinished(@NonNull IBinder transactionToken) {
|
||||
if (!mRunningTransactions.remove(transactionToken)) {
|
||||
return;
|
||||
}
|
||||
ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS,
|
||||
"Continue transition ready for TaskFragmentTransaction=%s", transactionToken);
|
||||
mWindowOrganizerController.getTransitionController().continueTransitionReady();
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -336,7 +388,7 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerOrganizer(ITaskFragmentOrganizer organizer) {
|
||||
public void registerOrganizer(@NonNull ITaskFragmentOrganizer organizer) {
|
||||
final int pid = Binder.getCallingPid();
|
||||
final int uid = Binder.getCallingUid();
|
||||
synchronized (mGlobalLock) {
|
||||
@@ -354,7 +406,7 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregisterOrganizer(ITaskFragmentOrganizer organizer) {
|
||||
public void unregisterOrganizer(@NonNull ITaskFragmentOrganizer organizer) {
|
||||
validateAndGetState(organizer);
|
||||
final int pid = Binder.getCallingPid();
|
||||
final long uid = Binder.getCallingUid();
|
||||
@@ -372,8 +424,8 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerRemoteAnimations(ITaskFragmentOrganizer organizer, int taskId,
|
||||
RemoteAnimationDefinition definition) {
|
||||
public void registerRemoteAnimations(@NonNull ITaskFragmentOrganizer organizer, int taskId,
|
||||
@NonNull RemoteAnimationDefinition definition) {
|
||||
final int pid = Binder.getCallingPid();
|
||||
final int uid = Binder.getCallingUid();
|
||||
synchronized (mGlobalLock) {
|
||||
@@ -398,7 +450,7 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregisterRemoteAnimations(ITaskFragmentOrganizer organizer, int taskId) {
|
||||
public void unregisterRemoteAnimations(@NonNull ITaskFragmentOrganizer organizer, int taskId) {
|
||||
final int pid = Binder.getCallingPid();
|
||||
final long uid = Binder.getCallingUid();
|
||||
synchronized (mGlobalLock) {
|
||||
@@ -416,6 +468,17 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTransactionHandled(@NonNull ITaskFragmentOrganizer organizer,
|
||||
@NonNull IBinder transactionToken, @NonNull WindowContainerTransaction wct) {
|
||||
synchronized (mGlobalLock) {
|
||||
// Keep the calling identity to avoid unsecure change.
|
||||
mWindowOrganizerController.applyTransaction(wct);
|
||||
final TaskFragmentOrganizerState state = validateAndGetState(organizer);
|
||||
state.onTransactionFinished(transactionToken);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the {@link RemoteAnimationDefinition} set on the given organizer if exists. Returns
|
||||
* {@code null} if it doesn't, or if the organizer has activity(ies) embedded in untrusted mode.
|
||||
@@ -775,13 +838,13 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
|
||||
}
|
||||
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));
|
||||
final TaskFragmentOrganizerState state =
|
||||
mTaskFragmentOrganizerState.get(mPendingTaskFragmentEvents.keyAt(i));
|
||||
dispatchPendingEvents(state, mPendingTaskFragmentEvents.valueAt(i));
|
||||
}
|
||||
}
|
||||
|
||||
void dispatchPendingEvents(@NonNull ITaskFragmentOrganizer organizer,
|
||||
void dispatchPendingEvents(@NonNull TaskFragmentOrganizerState state,
|
||||
@NonNull List<PendingTaskFragmentEvent> pendingEvents) {
|
||||
if (pendingEvents.isEmpty()) {
|
||||
return;
|
||||
@@ -817,7 +880,7 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
|
||||
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)
|
||||
PendingTaskFragmentEvent.EVENT_PARENT_INFO_CHANGED, state.mOrganizer)
|
||||
.setTask(task)
|
||||
.build()));
|
||||
}
|
||||
@@ -825,7 +888,7 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
|
||||
transaction.addChange(prepareChange(event));
|
||||
}
|
||||
mTmpTaskSet.clear();
|
||||
dispatchTransactionInfo(organizer, transaction);
|
||||
state.dispatchTransaction(transaction);
|
||||
pendingEvents.removeAll(candidateEvents);
|
||||
}
|
||||
|
||||
@@ -855,6 +918,7 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
|
||||
}
|
||||
|
||||
final ITaskFragmentOrganizer organizer = taskFragment.getTaskFragmentOrganizer();
|
||||
final TaskFragmentOrganizerState state = validateAndGetState(organizer);
|
||||
final TaskFragmentTransaction transaction = new TaskFragmentTransaction();
|
||||
// Make sure the organizer know about the Task config.
|
||||
transaction.addChange(prepareChange(new PendingTaskFragmentEvent.Builder(
|
||||
@@ -862,22 +926,10 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
|
||||
.setTask(taskFragment.getTask())
|
||||
.build()));
|
||||
transaction.addChange(prepareChange(event));
|
||||
dispatchTransactionInfo(event.mTaskFragmentOrg, transaction);
|
||||
state.dispatchTransaction(transaction);
|
||||
mPendingTaskFragmentEvents.get(organizer.asBinder()).remove(event);
|
||||
}
|
||||
|
||||
private void dispatchTransactionInfo(@NonNull ITaskFragmentOrganizer organizer,
|
||||
@NonNull TaskFragmentTransaction transaction) {
|
||||
if (transaction.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
organizer.onTransactionReady(transaction);
|
||||
} catch (RemoteException e) {
|
||||
Slog.d(TAG, "Exception sending TaskFragmentTransaction", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private TaskFragmentTransaction.Change prepareChange(
|
||||
@NonNull PendingTaskFragmentEvent event) {
|
||||
|
||||
@@ -1802,6 +1802,8 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe
|
||||
/** This undoes one call to {@link #deferTransitionReady}. */
|
||||
void continueTransitionReady() {
|
||||
--mReadyTracker.mDeferReadyDepth;
|
||||
// Apply ready in case it is waiting for the previous defer call.
|
||||
applyReady();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -147,7 +147,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
|
||||
mGlobalLock = atm.mGlobalLock;
|
||||
mTaskOrganizerController = new TaskOrganizerController(mService);
|
||||
mDisplayAreaOrganizerController = new DisplayAreaOrganizerController(mService);
|
||||
mTaskFragmentOrganizerController = new TaskFragmentOrganizerController(atm);
|
||||
mTaskFragmentOrganizerController = new TaskFragmentOrganizerController(atm, this);
|
||||
}
|
||||
|
||||
void setWindowManager(WindowManagerService wms) {
|
||||
|
||||
@@ -25,6 +25,7 @@ import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP
|
||||
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS;
|
||||
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT;
|
||||
|
||||
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
|
||||
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
|
||||
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
|
||||
import static com.android.server.wm.TaskFragment.EMBEDDING_ALLOWED;
|
||||
@@ -46,7 +47,6 @@ import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.clearInvocations;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.reset;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
@@ -65,6 +65,7 @@ import android.window.TaskFragmentCreationParams;
|
||||
import android.window.TaskFragmentInfo;
|
||||
import android.window.TaskFragmentOrganizer;
|
||||
import android.window.TaskFragmentOrganizerToken;
|
||||
import android.window.TaskFragmentTransaction;
|
||||
import android.window.WindowContainerToken;
|
||||
import android.window.WindowContainerTransaction;
|
||||
import android.window.WindowContainerTransactionCallback;
|
||||
@@ -90,6 +91,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
|
||||
|
||||
private TaskFragmentOrganizerController mController;
|
||||
private WindowOrganizerController mWindowOrganizerController;
|
||||
private TransitionController mTransitionController;
|
||||
private TaskFragmentOrganizer mOrganizer;
|
||||
private TaskFragmentOrganizerToken mOrganizerToken;
|
||||
private ITaskFragmentOrganizer mIOrganizer;
|
||||
@@ -107,9 +109,10 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
|
||||
private Task mTask;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
public void setup() throws RemoteException {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mWindowOrganizerController = mAtm.mWindowOrganizerController;
|
||||
mTransitionController = mWindowOrganizerController.mTransitionController;
|
||||
mController = mWindowOrganizerController.mTaskFragmentOrganizerController;
|
||||
mOrganizer = new TaskFragmentOrganizer(Runnable::run);
|
||||
mOrganizerToken = mOrganizer.getOrganizerToken();
|
||||
@@ -128,11 +131,16 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
|
||||
spyOn(mController);
|
||||
spyOn(mOrganizer);
|
||||
spyOn(mTaskFragment);
|
||||
spyOn(mWindowOrganizerController);
|
||||
spyOn(mTransitionController);
|
||||
doReturn(mIOrganizer).when(mTaskFragment).getTaskFragmentOrganizer();
|
||||
doReturn(mTaskFragmentInfo).when(mTaskFragment).getTaskFragmentInfo();
|
||||
doReturn(new SurfaceControl()).when(mTaskFragment).getSurfaceControl();
|
||||
doReturn(mFragmentToken).when(mTaskFragment).getFragmentToken();
|
||||
doReturn(new Configuration()).when(mTaskFragmentInfo).getConfiguration();
|
||||
|
||||
// To prevent it from calling the real server.
|
||||
doNothing().when(mOrganizer).onTransactionHandled(any(), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -866,7 +874,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
|
||||
assertFalse(parentTask.shouldBeVisible(null));
|
||||
|
||||
// Verify the info changed callback still occurred despite the task being invisible
|
||||
reset(mOrganizer);
|
||||
clearInvocations(mOrganizer);
|
||||
mController.onTaskFragmentInfoChanged(mIOrganizer, taskFragment);
|
||||
mController.dispatchPendingEvents();
|
||||
verify(mOrganizer).onTaskFragmentInfoChanged(any(), any());
|
||||
@@ -899,7 +907,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
|
||||
verify(mOrganizer).onTaskFragmentInfoChanged(any(), any());
|
||||
|
||||
// Verify the info changed callback is not called when the task is invisible
|
||||
reset(mOrganizer);
|
||||
clearInvocations(mOrganizer);
|
||||
doReturn(false).when(task).shouldBeVisible(any());
|
||||
mController.onTaskFragmentInfoChanged(mIOrganizer, taskFragment);
|
||||
mController.dispatchPendingEvents();
|
||||
@@ -1092,6 +1100,40 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
|
||||
.that(mTaskFragment.getBounds()).isEqualTo(task.getBounds());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOnTransactionReady_invokeOnTransactionHandled() {
|
||||
mController.registerOrganizer(mIOrganizer);
|
||||
final TaskFragmentTransaction transaction = new TaskFragmentTransaction();
|
||||
mOrganizer.onTransactionReady(transaction);
|
||||
|
||||
// Organizer should always trigger #onTransactionHandled when receives #onTransactionReady
|
||||
verify(mOrganizer).onTransactionHandled(eq(transaction.getTransactionToken()), any());
|
||||
verify(mOrganizer, never()).applyTransaction(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDispatchTransaction_deferTransitionReady() {
|
||||
mController.registerOrganizer(mIOrganizer);
|
||||
setupMockParent(mTaskFragment, mTask);
|
||||
final ArgumentCaptor<IBinder> tokenCaptor = ArgumentCaptor.forClass(IBinder.class);
|
||||
final ArgumentCaptor<WindowContainerTransaction> wctCaptor =
|
||||
ArgumentCaptor.forClass(WindowContainerTransaction.class);
|
||||
doReturn(true).when(mTransitionController).isCollecting();
|
||||
|
||||
mController.onTaskFragmentAppeared(mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment);
|
||||
mController.dispatchPendingEvents();
|
||||
|
||||
// Defer transition when send TaskFragment transaction during transition collection.
|
||||
verify(mTransitionController).deferTransitionReady();
|
||||
verify(mOrganizer).onTransactionHandled(tokenCaptor.capture(), wctCaptor.capture());
|
||||
|
||||
mController.onTransactionHandled(mIOrganizer, tokenCaptor.getValue(), wctCaptor.getValue());
|
||||
|
||||
// Apply the organizer change and continue transition.
|
||||
verify(mWindowOrganizerController).applyTransaction(wctCaptor.getValue());
|
||||
verify(mTransitionController).continueTransitionReady();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link TaskFragment} with the {@link WindowContainerTransaction}. Calls
|
||||
* {@link WindowOrganizerController#applyTransaction} to apply the transaction,
|
||||
|
||||
Reference in New Issue
Block a user