Merge "Add TaskFragmentOrganizer#applyTransaction with request transition" into tm-qpr-dev am: 2c9b75902e
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/19714429 Change-Id: I3225c3c79b0a309e9e16abd2f81b92e263a55a90 Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
@@ -57,6 +57,12 @@ interface ITaskFragmentOrganizerController {
|
||||
* 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);
|
||||
void onTransactionHandled(in IBinder transactionToken, in WindowContainerTransaction wct,
|
||||
int transitionType, boolean shouldApplyIndependently);
|
||||
|
||||
/**
|
||||
* Requests the server to apply the given {@link WindowContainerTransaction}.
|
||||
*/
|
||||
void applyTransaction(in WindowContainerTransaction wct, int transitionType,
|
||||
boolean shouldApplyIndependently);
|
||||
}
|
||||
|
||||
@@ -16,17 +16,25 @@
|
||||
|
||||
package android.window;
|
||||
|
||||
import static android.view.WindowManager.TRANSIT_CHANGE;
|
||||
import static android.view.WindowManager.TRANSIT_CLOSE;
|
||||
import static android.view.WindowManager.TRANSIT_NONE;
|
||||
import static android.view.WindowManager.TRANSIT_OPEN;
|
||||
import static android.window.TaskFragmentTransaction.TYPE_ACTIVITY_REPARENTED_TO_TASK;
|
||||
import static android.window.TaskFragmentTransaction.TYPE_TASK_FRAGMENT_APPEARED;
|
||||
import static android.window.TaskFragmentTransaction.TYPE_TASK_FRAGMENT_ERROR;
|
||||
import static android.window.TaskFragmentTransaction.TYPE_TASK_FRAGMENT_INFO_CHANGED;
|
||||
import static android.window.TaskFragmentTransaction.TYPE_TASK_FRAGMENT_PARENT_INFO_CHANGED;
|
||||
import static android.window.TaskFragmentTransaction.TYPE_TASK_FRAGMENT_VANISHED;
|
||||
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_CREATE_TASK_FRAGMENT;
|
||||
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_DELETE_TASK_FRAGMENT;
|
||||
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT;
|
||||
|
||||
import android.annotation.CallSuper;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.TestApi;
|
||||
import android.app.WindowConfiguration;
|
||||
import android.content.Intent;
|
||||
import android.content.res.Configuration;
|
||||
import android.os.Bundle;
|
||||
@@ -34,6 +42,7 @@ import android.os.IBinder;
|
||||
import android.os.RemoteException;
|
||||
import android.util.SparseArray;
|
||||
import android.view.RemoteAnimationDefinition;
|
||||
import android.view.WindowManager;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -168,20 +177,110 @@ public class TaskFragmentOrganizer extends WindowOrganizer {
|
||||
* {@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.
|
||||
* @param transitionType {@link WindowManager.TransitionType} if it needs to start a
|
||||
* transition.
|
||||
* @param shouldApplyIndependently If {@code true}, the {@code wct} will request a new
|
||||
* transition, which will be queued until the sync engine is
|
||||
* free if there is any other active sync. If {@code false},
|
||||
* the {@code wct} will be directly applied to the active sync.
|
||||
* @see com.android.server.wm.WindowOrganizerController#enforceTaskFragmentOrganizerPermission
|
||||
* for permission enforcement.
|
||||
* @hide
|
||||
*/
|
||||
public void onTransactionHandled(@NonNull IBinder transactionToken,
|
||||
@NonNull WindowContainerTransaction wct) {
|
||||
@NonNull WindowContainerTransaction wct,
|
||||
@WindowManager.TransitionType int transitionType, boolean shouldApplyIndependently) {
|
||||
wct.setTaskFragmentOrganizer(mInterface);
|
||||
try {
|
||||
getController().onTransactionHandled(mInterface, transactionToken, wct);
|
||||
getController().onTransactionHandled(transactionToken, wct, transitionType,
|
||||
shouldApplyIndependently);
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Routes to {@link ITaskFragmentOrganizerController#applyTransaction} instead of
|
||||
* {@link IWindowOrganizerController#applyTransaction} for the different transition options.
|
||||
*
|
||||
* @see #applyTransaction(WindowContainerTransaction, int, boolean, boolean)
|
||||
*/
|
||||
@Override
|
||||
public void applyTransaction(@NonNull WindowContainerTransaction wct) {
|
||||
// TODO(b/207070762) doing so to keep CTS compatibility. Remove in the next release.
|
||||
applyTransaction(wct, getTransitionType(wct), false /* shouldApplyIndependently */);
|
||||
}
|
||||
|
||||
/**
|
||||
* Requests the server to apply the given {@link WindowContainerTransaction}.
|
||||
*
|
||||
* @param wct {@link WindowContainerTransaction} to apply.
|
||||
* @param transitionType {@link WindowManager.TransitionType} if it needs to start a
|
||||
* transition.
|
||||
* @param shouldApplyIndependently If {@code true}, the {@code wct} will request a new
|
||||
* transition, which will be queued until the sync engine is
|
||||
* free if there is any other active sync. If {@code false},
|
||||
* the {@code wct} will be directly applied to the active sync.
|
||||
* @see com.android.server.wm.WindowOrganizerController#enforceTaskFragmentOrganizerPermission
|
||||
* for permission enforcement.
|
||||
* @hide
|
||||
*/
|
||||
public void applyTransaction(@NonNull WindowContainerTransaction wct,
|
||||
@WindowManager.TransitionType int transitionType, boolean shouldApplyIndependently) {
|
||||
if (wct.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
wct.setTaskFragmentOrganizer(mInterface);
|
||||
try {
|
||||
getController().applyTransaction(wct, transitionType, shouldApplyIndependently);
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the default {@link WindowManager.TransitionType} based on the requested
|
||||
* {@link WindowContainerTransaction}.
|
||||
* @hide
|
||||
*/
|
||||
// TODO(b/207070762): let Extensions to set the transition type instead.
|
||||
@WindowManager.TransitionType
|
||||
public static int getTransitionType(@NonNull WindowContainerTransaction wct) {
|
||||
if (wct.isEmpty()) {
|
||||
return TRANSIT_NONE;
|
||||
}
|
||||
for (WindowContainerTransaction.Change change : wct.getChanges().values()) {
|
||||
if ((change.getWindowSetMask() & WindowConfiguration.WINDOW_CONFIG_BOUNDS) != 0) {
|
||||
// Treat as TRANSIT_CHANGE when there is TaskFragment resizing.
|
||||
return TRANSIT_CHANGE;
|
||||
}
|
||||
}
|
||||
boolean containsCreatingTaskFragment = false;
|
||||
boolean containsDeleteTaskFragment = false;
|
||||
final List<WindowContainerTransaction.HierarchyOp> ops = wct.getHierarchyOps();
|
||||
for (int i = ops.size() - 1; i >= 0; i--) {
|
||||
final int type = ops.get(i).getType();
|
||||
if (type == HIERARCHY_OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT) {
|
||||
// Treat as TRANSIT_CHANGE when there is activity reparent.
|
||||
return TRANSIT_CHANGE;
|
||||
}
|
||||
if (type == HIERARCHY_OP_TYPE_CREATE_TASK_FRAGMENT) {
|
||||
containsCreatingTaskFragment = true;
|
||||
} else if (type == HIERARCHY_OP_TYPE_DELETE_TASK_FRAGMENT) {
|
||||
containsDeleteTaskFragment = true;
|
||||
}
|
||||
}
|
||||
if (containsCreatingTaskFragment) {
|
||||
return TRANSIT_OPEN;
|
||||
}
|
||||
if (containsDeleteTaskFragment) {
|
||||
return TRANSIT_CLOSE;
|
||||
}
|
||||
|
||||
// Use TRANSIT_CHANGE as default.
|
||||
return TRANSIT_CHANGE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a TaskFragment is created and organized by this organizer.
|
||||
*
|
||||
@@ -424,22 +523,8 @@ public class TaskFragmentOrganizer extends WindowOrganizer {
|
||||
}
|
||||
|
||||
// Notify the server, and the server should apply the WindowContainerTransaction.
|
||||
onTransactionHandled(transaction.getTransactionToken(), wct);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyTransaction(@NonNull WindowContainerTransaction t) {
|
||||
t.setTaskFragmentOrganizer(mInterface);
|
||||
super.applyTransaction(t);
|
||||
}
|
||||
|
||||
// Suppress the lint because it is not a registration method.
|
||||
@SuppressWarnings("ExecutorRegistration")
|
||||
@Override
|
||||
public int applySyncTransaction(@NonNull WindowContainerTransaction t,
|
||||
@NonNull WindowContainerTransactionCallback callback) {
|
||||
t.setTaskFragmentOrganizer(mInterface);
|
||||
return super.applySyncTransaction(t, callback);
|
||||
onTransactionHandled(transaction.getTransactionToken(), wct, getTransitionType(wct),
|
||||
false /* shouldApplyIndependently */);
|
||||
}
|
||||
|
||||
private final ITaskFragmentOrganizer mInterface = new ITaskFragmentOrganizer.Stub() {
|
||||
|
||||
@@ -763,10 +763,8 @@ public final class WindowContainerTransaction implements Parcelable {
|
||||
* @hide
|
||||
*/
|
||||
@NonNull
|
||||
WindowContainerTransaction setTaskFragmentOrganizer(@NonNull ITaskFragmentOrganizer organizer) {
|
||||
if (mTaskFragmentOrganizer != null) {
|
||||
throw new IllegalStateException("Can't set multiple organizers for one transaction.");
|
||||
}
|
||||
public WindowContainerTransaction setTaskFragmentOrganizer(
|
||||
@NonNull ITaskFragmentOrganizer organizer) {
|
||||
mTaskFragmentOrganizer = organizer;
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -1801,6 +1801,12 @@
|
||||
"group": "WM_DEBUG_WINDOW_TRANSITIONS",
|
||||
"at": "com\/android\/server\/wm\/Transition.java"
|
||||
},
|
||||
"-353495930": {
|
||||
"message": "TaskFragmentTransaction changes are not collected in transition because there is an ongoing sync for applySyncTransaction().",
|
||||
"level": "WARN",
|
||||
"group": "WM_DEBUG_WINDOW_TRANSITIONS",
|
||||
"at": "com\/android\/server\/wm\/WindowOrganizerController.java"
|
||||
},
|
||||
"-347866078": {
|
||||
"message": "Setting move animation on %s",
|
||||
"level": "VERBOSE",
|
||||
@@ -2491,6 +2497,12 @@
|
||||
"group": "WM_DEBUG_ANIM",
|
||||
"at": "com\/android\/server\/wm\/WindowState.java"
|
||||
},
|
||||
"286170861": {
|
||||
"message": "Creating Pending Transition for TaskFragment: %s",
|
||||
"level": "VERBOSE",
|
||||
"group": "WM_DEBUG_WINDOW_TRANSITIONS",
|
||||
"at": "com\/android\/server\/wm\/WindowOrganizerController.java"
|
||||
},
|
||||
"288485303": {
|
||||
"message": "Attempted to set remove mode to a display that does not exist: %d",
|
||||
"level": "WARN",
|
||||
|
||||
@@ -22,6 +22,7 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
|
||||
import static android.window.TaskFragmentOrganizer.KEY_ERROR_CALLBACK_OP_TYPE;
|
||||
import static android.window.TaskFragmentOrganizer.KEY_ERROR_CALLBACK_TASK_FRAGMENT_INFO;
|
||||
import static android.window.TaskFragmentOrganizer.KEY_ERROR_CALLBACK_THROWABLE;
|
||||
import static android.window.TaskFragmentOrganizer.getTransitionType;
|
||||
import static android.window.TaskFragmentTransaction.TYPE_ACTIVITY_REPARENTED_TO_TASK;
|
||||
import static android.window.TaskFragmentTransaction.TYPE_TASK_FRAGMENT_APPEARED;
|
||||
import static android.window.TaskFragmentTransaction.TYPE_TASK_FRAGMENT_ERROR;
|
||||
@@ -109,7 +110,7 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
|
||||
private Consumer<List<SplitInfo>> mEmbeddingCallback;
|
||||
private final List<SplitInfo> mLastReportedSplitStates = new ArrayList<>();
|
||||
private final Handler mHandler;
|
||||
private final Object mLock = new Object();
|
||||
final Object mLock = new Object();
|
||||
private final ActivityStartMonitor mActivityStartMonitor;
|
||||
|
||||
public SplitController() {
|
||||
@@ -209,8 +210,10 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
|
||||
}
|
||||
}
|
||||
|
||||
// Notify the server, and the server should apply the WindowContainerTransaction.
|
||||
mPresenter.onTransactionHandled(transaction.getTransactionToken(), wct);
|
||||
// Notify the server, and the server should apply and merge the
|
||||
// WindowContainerTransaction to the active sync to finish the TaskFragmentTransaction.
|
||||
mPresenter.onTransactionHandled(transaction.getTransactionToken(), wct,
|
||||
getTransitionType(wct), false /* shouldApplyIndependently */);
|
||||
updateCallbackIfNecessary();
|
||||
}
|
||||
}
|
||||
@@ -221,6 +224,9 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
|
||||
* @param wct The {@link WindowContainerTransaction} to make any changes with if needed.
|
||||
* @param taskFragmentInfo Info of the TaskFragment that is created.
|
||||
*/
|
||||
// Suppress GuardedBy warning because lint ask to mark this method as
|
||||
// @GuardedBy(container.mController.mLock), which is mLock itself
|
||||
@SuppressWarnings("GuardedBy")
|
||||
@VisibleForTesting
|
||||
@GuardedBy("mLock")
|
||||
void onTaskFragmentAppeared(@NonNull WindowContainerTransaction wct,
|
||||
@@ -245,6 +251,9 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
|
||||
* @param wct The {@link WindowContainerTransaction} to make any changes with if needed.
|
||||
* @param taskFragmentInfo Info of the TaskFragment that is changed.
|
||||
*/
|
||||
// Suppress GuardedBy warning because lint ask to mark this method as
|
||||
// @GuardedBy(container.mController.mLock), which is mLock itself
|
||||
@SuppressWarnings("GuardedBy")
|
||||
@VisibleForTesting
|
||||
@GuardedBy("mLock")
|
||||
void onTaskFragmentInfoChanged(@NonNull WindowContainerTransaction wct,
|
||||
@@ -430,6 +439,9 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
|
||||
* transaction operation.
|
||||
* @param exception exception from the server side.
|
||||
*/
|
||||
// Suppress GuardedBy warning because lint ask to mark this method as
|
||||
// @GuardedBy(container.mController.mLock), which is mLock itself
|
||||
@SuppressWarnings("GuardedBy")
|
||||
@VisibleForTesting
|
||||
@GuardedBy("mLock")
|
||||
void onTaskFragmentError(@NonNull WindowContainerTransaction wct,
|
||||
@@ -869,23 +881,23 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
|
||||
* Called when we have been waiting too long for the TaskFragment to become non-empty after
|
||||
* creation.
|
||||
*/
|
||||
@GuardedBy("mLock")
|
||||
void onTaskFragmentAppearEmptyTimeout(@NonNull TaskFragmentContainer container) {
|
||||
synchronized (mLock) {
|
||||
final WindowContainerTransaction wct = new WindowContainerTransaction();
|
||||
onTaskFragmentAppearEmptyTimeout(wct, container);
|
||||
mPresenter.applyTransaction(wct);
|
||||
}
|
||||
final WindowContainerTransaction wct = new WindowContainerTransaction();
|
||||
onTaskFragmentAppearEmptyTimeout(wct, container);
|
||||
// Can be applied independently as a timeout callback.
|
||||
mPresenter.applyTransaction(wct, getTransitionType(wct),
|
||||
true /* shouldApplyIndependently */);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when we have been waiting too long for the TaskFragment to become non-empty after
|
||||
* creation.
|
||||
*/
|
||||
@GuardedBy("mLock")
|
||||
void onTaskFragmentAppearEmptyTimeout(@NonNull WindowContainerTransaction wct,
|
||||
@NonNull TaskFragmentContainer container) {
|
||||
synchronized (mLock) {
|
||||
mPresenter.cleanupContainer(wct, container, false /* shouldFinishDependent */);
|
||||
}
|
||||
mPresenter.cleanupContainer(wct, container, false /* shouldFinishDependent */);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1714,7 +1726,9 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
|
||||
synchronized (mLock) {
|
||||
final WindowContainerTransaction wct = new WindowContainerTransaction();
|
||||
SplitController.this.onActivityCreated(wct, activity);
|
||||
mPresenter.applyTransaction(wct);
|
||||
// The WCT should be applied and merged to the activity launch transition.
|
||||
mPresenter.applyTransaction(wct, getTransitionType(wct),
|
||||
false /* shouldApplyIndependently */);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1723,7 +1737,10 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
|
||||
synchronized (mLock) {
|
||||
final WindowContainerTransaction wct = new WindowContainerTransaction();
|
||||
SplitController.this.onActivityConfigurationChanged(wct, activity);
|
||||
mPresenter.applyTransaction(wct);
|
||||
// The WCT should be applied and merged to the Task change transition so that the
|
||||
// placeholder is launched in the same transition.
|
||||
mPresenter.applyTransaction(wct, getTransitionType(wct),
|
||||
false /* shouldApplyIndependently */);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1775,7 +1792,10 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
|
||||
final TaskFragmentContainer launchedInTaskFragment = resolveStartActivityIntent(wct,
|
||||
taskId, intent, launchingActivity);
|
||||
if (launchedInTaskFragment != null) {
|
||||
mPresenter.applyTransaction(wct);
|
||||
// Make sure the WCT is applied immediately instead of being queued so that the
|
||||
// TaskFragment will be ready before activity attachment.
|
||||
mPresenter.applyTransaction(wct, getTransitionType(wct),
|
||||
false /* shouldApplyIndependently */);
|
||||
// Amend the request to let the WM know that the activity should be placed in
|
||||
// the dedicated container.
|
||||
options.putBinder(ActivityOptions.KEY_LAUNCH_TASK_FRAGMENT_TOKEN,
|
||||
|
||||
@@ -28,6 +28,7 @@ import android.util.Size;
|
||||
import android.window.TaskFragmentInfo;
|
||||
import android.window.WindowContainerTransaction;
|
||||
|
||||
import androidx.annotation.GuardedBy;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
@@ -251,6 +252,7 @@ class TaskFragmentContainer {
|
||||
return mInfo;
|
||||
}
|
||||
|
||||
@GuardedBy("mController.mLock")
|
||||
void setInfo(@NonNull WindowContainerTransaction wct, @NonNull TaskFragmentInfo info) {
|
||||
if (!mIsFinished && mInfo == null && info.isEmpty()) {
|
||||
// onTaskFragmentAppeared with empty info. We will remove the TaskFragment if no
|
||||
@@ -258,10 +260,12 @@ class TaskFragmentContainer {
|
||||
// it is still empty after timeout.
|
||||
if (mPendingAppearedIntent != null || !mPendingAppearedActivities.isEmpty()) {
|
||||
mAppearEmptyTimeout = () -> {
|
||||
mAppearEmptyTimeout = null;
|
||||
// Call without the pass-in wct when timeout. We need to applyWct directly
|
||||
// in this case.
|
||||
mController.onTaskFragmentAppearEmptyTimeout(this);
|
||||
synchronized (mController.mLock) {
|
||||
mAppearEmptyTimeout = null;
|
||||
// Call without the pass-in wct when timeout. We need to applyWct directly
|
||||
// in this case.
|
||||
mController.onTaskFragmentAppearEmptyTimeout(this);
|
||||
}
|
||||
};
|
||||
mController.getHandler().postDelayed(mAppearEmptyTimeout, APPEAR_EMPTY_TIMEOUT_MS);
|
||||
} else {
|
||||
|
||||
@@ -20,7 +20,6 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
|
||||
|
||||
import static androidx.window.extensions.embedding.EmbeddingTestUtils.TASK_ID;
|
||||
|
||||
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
|
||||
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
|
||||
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
|
||||
|
||||
@@ -33,7 +32,6 @@ import static org.mockito.Mockito.never;
|
||||
import android.content.Intent;
|
||||
import android.content.res.Configuration;
|
||||
import android.graphics.Point;
|
||||
import android.os.Handler;
|
||||
import android.platform.test.annotations.Presubmit;
|
||||
import android.window.TaskFragmentInfo;
|
||||
import android.window.TaskFragmentTransaction;
|
||||
@@ -67,10 +65,7 @@ public class JetpackTaskFragmentOrganizerTest {
|
||||
private WindowContainerTransaction mTransaction;
|
||||
@Mock
|
||||
private JetpackTaskFragmentOrganizer.TaskFragmentCallback mCallback;
|
||||
@Mock
|
||||
private SplitController mSplitController;
|
||||
@Mock
|
||||
private Handler mHandler;
|
||||
private JetpackTaskFragmentOrganizer mOrganizer;
|
||||
|
||||
@Before
|
||||
@@ -78,8 +73,9 @@ public class JetpackTaskFragmentOrganizerTest {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mOrganizer = new JetpackTaskFragmentOrganizer(Runnable::run, mCallback);
|
||||
mOrganizer.registerOrganizer();
|
||||
mSplitController = new SplitController();
|
||||
spyOn(mOrganizer);
|
||||
doReturn(mHandler).when(mSplitController).getHandler();
|
||||
spyOn(mSplitController);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -127,7 +127,7 @@ public class SplitControllerTest {
|
||||
mSplitPresenter = mSplitController.mPresenter;
|
||||
spyOn(mSplitController);
|
||||
spyOn(mSplitPresenter);
|
||||
doNothing().when(mSplitPresenter).applyTransaction(any());
|
||||
doNothing().when(mSplitPresenter).applyTransaction(any(), anyInt(), anyBoolean());
|
||||
final Configuration activityConfig = new Configuration();
|
||||
activityConfig.windowConfiguration.setBounds(TASK_BOUNDS);
|
||||
activityConfig.windowConfiguration.setMaxBounds(TASK_BOUNDS);
|
||||
@@ -1000,7 +1000,8 @@ public class SplitControllerTest {
|
||||
mSplitController.onTransactionReady(transaction);
|
||||
|
||||
verify(mSplitController).onTaskFragmentAppeared(any(), eq(info));
|
||||
verify(mSplitPresenter).onTransactionHandled(eq(transaction.getTransactionToken()), any());
|
||||
verify(mSplitPresenter).onTransactionHandled(eq(transaction.getTransactionToken()), any(),
|
||||
anyInt(), anyBoolean());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -1014,7 +1015,8 @@ public class SplitControllerTest {
|
||||
mSplitController.onTransactionReady(transaction);
|
||||
|
||||
verify(mSplitController).onTaskFragmentInfoChanged(any(), eq(info));
|
||||
verify(mSplitPresenter).onTransactionHandled(eq(transaction.getTransactionToken()), any());
|
||||
verify(mSplitPresenter).onTransactionHandled(eq(transaction.getTransactionToken()), any(),
|
||||
anyInt(), anyBoolean());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -1028,7 +1030,8 @@ public class SplitControllerTest {
|
||||
mSplitController.onTransactionReady(transaction);
|
||||
|
||||
verify(mSplitController).onTaskFragmentVanished(any(), eq(info));
|
||||
verify(mSplitPresenter).onTransactionHandled(eq(transaction.getTransactionToken()), any());
|
||||
verify(mSplitPresenter).onTransactionHandled(eq(transaction.getTransactionToken()), any(),
|
||||
anyInt(), anyBoolean());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -1043,7 +1046,8 @@ public class SplitControllerTest {
|
||||
|
||||
verify(mSplitController).onTaskFragmentParentInfoChanged(any(), eq(TASK_ID),
|
||||
eq(taskConfig));
|
||||
verify(mSplitPresenter).onTransactionHandled(eq(transaction.getTransactionToken()), any());
|
||||
verify(mSplitPresenter).onTransactionHandled(eq(transaction.getTransactionToken()), any(),
|
||||
anyInt(), anyBoolean());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -1062,7 +1066,8 @@ public class SplitControllerTest {
|
||||
|
||||
verify(mSplitController).onTaskFragmentError(any(), eq(errorToken), eq(info), eq(opType),
|
||||
eq(exception));
|
||||
verify(mSplitPresenter).onTransactionHandled(eq(transaction.getTransactionToken()), any());
|
||||
verify(mSplitPresenter).onTransactionHandled(eq(transaction.getTransactionToken()), any(),
|
||||
anyInt(), anyBoolean());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -1078,7 +1083,8 @@ public class SplitControllerTest {
|
||||
|
||||
verify(mSplitController).onActivityReparentedToTask(any(), eq(TASK_ID), eq(intent),
|
||||
eq(activityToken));
|
||||
verify(mSplitPresenter).onTransactionHandled(eq(transaction.getTransactionToken()), any());
|
||||
verify(mSplitPresenter).onTransactionHandled(eq(transaction.getTransactionToken()), any(),
|
||||
anyInt(), anyBoolean());
|
||||
}
|
||||
|
||||
/** Creates a mock activity in the organizer process. */
|
||||
|
||||
@@ -45,6 +45,7 @@ import android.util.ArraySet;
|
||||
import android.util.Slog;
|
||||
import android.util.SparseArray;
|
||||
import android.view.RemoteAnimationDefinition;
|
||||
import android.view.WindowManager;
|
||||
import android.window.ITaskFragmentOrganizer;
|
||||
import android.window.ITaskFragmentOrganizerController;
|
||||
import android.window.TaskFragmentInfo;
|
||||
@@ -484,16 +485,31 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTransactionHandled(@NonNull ITaskFragmentOrganizer organizer,
|
||||
@NonNull IBinder transactionToken, @NonNull WindowContainerTransaction wct) {
|
||||
public void onTransactionHandled(@NonNull IBinder transactionToken,
|
||||
@NonNull WindowContainerTransaction wct,
|
||||
@WindowManager.TransitionType int transitionType, boolean shouldApplyIndependently) {
|
||||
// Keep the calling identity to avoid unsecure change.
|
||||
synchronized (mGlobalLock) {
|
||||
// Keep the calling identity to avoid unsecure change.
|
||||
mWindowOrganizerController.applyTransaction(wct);
|
||||
final TaskFragmentOrganizerState state = validateAndGetState(organizer);
|
||||
applyTransaction(wct, transitionType, shouldApplyIndependently);
|
||||
final TaskFragmentOrganizerState state = validateAndGetState(
|
||||
wct.getTaskFragmentOrganizer());
|
||||
state.onTransactionFinished(transactionToken);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyTransaction(@NonNull WindowContainerTransaction wct,
|
||||
@WindowManager.TransitionType int transitionType, boolean shouldApplyIndependently) {
|
||||
// Keep the calling identity to avoid unsecure change.
|
||||
synchronized (mGlobalLock) {
|
||||
if (wct.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
mWindowOrganizerController.applyTaskFragmentTransactionLocked(wct, transitionType,
|
||||
shouldApplyIndependently);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
|
||||
@@ -75,6 +75,7 @@ import android.util.ArraySet;
|
||||
import android.util.Slog;
|
||||
import android.view.RemoteAnimationAdapter;
|
||||
import android.view.SurfaceControl;
|
||||
import android.view.WindowManager;
|
||||
import android.window.IDisplayAreaOrganizerController;
|
||||
import android.window.ITaskFragmentOrganizer;
|
||||
import android.window.ITaskFragmentOrganizerController;
|
||||
@@ -177,7 +178,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
|
||||
if (t == null) {
|
||||
throw new IllegalArgumentException("Null transaction passed to applyTransaction");
|
||||
}
|
||||
enforceTaskPermission("applyTransaction()", t);
|
||||
enforceTaskPermission("applyTransaction()");
|
||||
final CallerInfo caller = new CallerInfo();
|
||||
final long ident = Binder.clearCallingIdentity();
|
||||
try {
|
||||
@@ -195,7 +196,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
|
||||
if (t == null) {
|
||||
throw new IllegalArgumentException("Null transaction passed to applySyncTransaction");
|
||||
}
|
||||
enforceTaskPermission("applySyncTransaction()", t);
|
||||
enforceTaskPermission("applySyncTransaction()");
|
||||
final CallerInfo caller = new CallerInfo();
|
||||
final long ident = Binder.clearCallingIdentity();
|
||||
try {
|
||||
@@ -374,6 +375,87 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies the {@link WindowContainerTransaction} as a request from
|
||||
* {@link android.window.TaskFragmentOrganizer}.
|
||||
*
|
||||
* @param wct {@link WindowContainerTransaction} to apply.
|
||||
* @param type {@link WindowManager.TransitionType} if it needs to start a new transition.
|
||||
* @param shouldApplyIndependently If {@code true}, the {@code wct} will request a new
|
||||
* transition, which will be queued until the sync engine is
|
||||
* free if there is any other active sync. If {@code false},
|
||||
* the {@code wct} will be directly applied to the active sync.
|
||||
*/
|
||||
void applyTaskFragmentTransactionLocked(@NonNull WindowContainerTransaction wct,
|
||||
@WindowManager.TransitionType int type, boolean shouldApplyIndependently) {
|
||||
if (!isValidTransaction(wct)) {
|
||||
return;
|
||||
}
|
||||
enforceTaskFragmentOrganizerPermission("applyTaskFragmentTransaction()",
|
||||
Objects.requireNonNull(wct.getTaskFragmentOrganizer()),
|
||||
Objects.requireNonNull(wct));
|
||||
final CallerInfo caller = new CallerInfo();
|
||||
final long ident = Binder.clearCallingIdentity();
|
||||
try {
|
||||
if (mTransitionController.getTransitionPlayer() == null) {
|
||||
// No need to worry about transition when Shell transition is not enabled.
|
||||
applyTransaction(wct, -1 /* syncId */, null /* transition */, caller);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mService.mWindowManager.mSyncEngine.hasActiveSync()) {
|
||||
// Sync is for either transition or applySyncTransaction(). We don't support
|
||||
// multiple sync at the same time because it may cause conflict.
|
||||
// Create a new transition when there is no active sync to collect the changes.
|
||||
final Transition transition = mTransitionController.createTransition(type);
|
||||
applyTransaction(wct, -1 /* syncId */, transition, caller);
|
||||
mTransitionController.requestStartTransition(transition, null /* startTask */,
|
||||
null /* remoteTransition */, null /* displayChange */);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!shouldApplyIndependently) {
|
||||
// Although there is an active sync, we want to apply the transaction now.
|
||||
if (!mTransitionController.isCollecting()) {
|
||||
// This should rarely happen, and we should try to avoid using
|
||||
// {@link #applySyncTransaction} with Shell transition.
|
||||
// We still want to apply and merge the transaction to the active sync
|
||||
// because {@code shouldApplyIndependently} is {@code false}.
|
||||
ProtoLog.w(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS,
|
||||
"TaskFragmentTransaction changes are not collected in transition"
|
||||
+ " because there is an ongoing sync for"
|
||||
+ " applySyncTransaction().");
|
||||
}
|
||||
// TODO(b/207070762) make sure changes are all collected.
|
||||
applyTransaction(wct, -1 /* syncId */, null /* transition */, caller);
|
||||
return;
|
||||
}
|
||||
|
||||
// It is ok to queue the WCT until the sync engine is free.
|
||||
final Transition nextTransition = new Transition(type, 0 /* flags */,
|
||||
mTransitionController, mService.mWindowManager.mSyncEngine);
|
||||
ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS,
|
||||
"Creating Pending Transition for TaskFragment: %s", nextTransition);
|
||||
mService.mWindowManager.mSyncEngine.queueSyncSet(
|
||||
// Make sure to collect immediately to prevent another transition
|
||||
// from sneaking in before it. Note: moveToCollecting internally
|
||||
// calls startSyncSet.
|
||||
() -> mTransitionController.moveToCollecting(nextTransition),
|
||||
() -> {
|
||||
if (isValidTransaction(wct)) {
|
||||
applyTransaction(wct, -1 /*syncId*/, nextTransition, caller);
|
||||
mTransitionController.requestStartTransition(nextTransition,
|
||||
null /* startTask */, null /* remoteTransition */,
|
||||
null /* displayChange */);
|
||||
} else {
|
||||
nextTransition.abort();
|
||||
}
|
||||
});
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(ident);
|
||||
}
|
||||
}
|
||||
|
||||
private void applyTransaction(@NonNull WindowContainerTransaction t, int syncId,
|
||||
@Nullable Transition transition, @NonNull CallerInfo caller) {
|
||||
applyTransaction(t, syncId, transition, caller, null /* finishTransition */);
|
||||
@@ -388,12 +470,6 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
|
||||
private void applyTransaction(@NonNull WindowContainerTransaction t, int syncId,
|
||||
@Nullable Transition transition, @NonNull CallerInfo caller,
|
||||
@Nullable Transition finishTransition) {
|
||||
if (t.getTaskFragmentOrganizer() != null && !mTaskFragmentOrganizerController
|
||||
.isOrganizerRegistered(t.getTaskFragmentOrganizer())) {
|
||||
Slog.e(TAG, "Caller organizer=" + t.getTaskFragmentOrganizer()
|
||||
+ " is no longer registered");
|
||||
return;
|
||||
}
|
||||
int effects = 0;
|
||||
ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Apply window transaction, syncId=%d", syncId);
|
||||
mService.deferWindowLayout();
|
||||
@@ -1495,25 +1571,24 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
|
||||
mService.enforceTaskPermission(func);
|
||||
}
|
||||
|
||||
private void enforceTaskPermission(String func, @Nullable WindowContainerTransaction t) {
|
||||
if (t == null || t.getTaskFragmentOrganizer() == null) {
|
||||
enforceTaskPermission(func);
|
||||
return;
|
||||
private boolean isValidTransaction(@NonNull WindowContainerTransaction t) {
|
||||
if (t.getTaskFragmentOrganizer() != null && !mTaskFragmentOrganizerController
|
||||
.isOrganizerRegistered(t.getTaskFragmentOrganizer())) {
|
||||
// Transaction from an unregistered organizer should not be applied. This can happen
|
||||
// when the organizer process died before the transaction is applied.
|
||||
Slog.e(TAG, "Caller organizer=" + t.getTaskFragmentOrganizer()
|
||||
+ " is no longer registered");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Apps may not have the permission to manage Tasks, but we are allowing apps to manage
|
||||
// TaskFragments belonging to their own Task.
|
||||
enforceOperationsAllowedForTaskFragmentOrganizer(func, t);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes sure that the transaction only contains operations that are allowed for the
|
||||
* {@link WindowContainerTransaction#getTaskFragmentOrganizer()}.
|
||||
*/
|
||||
private void enforceOperationsAllowedForTaskFragmentOrganizer(
|
||||
String func, WindowContainerTransaction t) {
|
||||
final ITaskFragmentOrganizer organizer = t.getTaskFragmentOrganizer();
|
||||
|
||||
private void enforceTaskFragmentOrganizerPermission(@NonNull String func,
|
||||
@NonNull ITaskFragmentOrganizer organizer, @NonNull WindowContainerTransaction t) {
|
||||
// Configuration changes
|
||||
final Iterator<Map.Entry<IBinder, WindowContainerTransaction.Change>> entries =
|
||||
t.getChanges().entrySet().iterator();
|
||||
|
||||
@@ -20,6 +20,7 @@ import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
|
||||
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
|
||||
import static android.window.TaskFragmentOrganizer.KEY_ERROR_CALLBACK_OP_TYPE;
|
||||
import static android.window.TaskFragmentOrganizer.KEY_ERROR_CALLBACK_THROWABLE;
|
||||
import static android.window.TaskFragmentOrganizer.getTransitionType;
|
||||
import static android.window.TaskFragmentTransaction.TYPE_ACTIVITY_REPARENTED_TO_TASK;
|
||||
import static android.window.TaskFragmentTransaction.TYPE_TASK_FRAGMENT_APPEARED;
|
||||
import static android.window.TaskFragmentTransaction.TYPE_TASK_FRAGMENT_ERROR;
|
||||
@@ -49,8 +50,8 @@ import static org.junit.Assert.assertNotEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyBoolean;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.clearInvocations;
|
||||
@@ -78,7 +79,6 @@ import android.window.TaskFragmentOrganizerToken;
|
||||
import android.window.TaskFragmentTransaction;
|
||||
import android.window.WindowContainerToken;
|
||||
import android.window.WindowContainerTransaction;
|
||||
import android.window.WindowContainerTransactionCallback;
|
||||
|
||||
import androidx.test.filters.SmallTest;
|
||||
|
||||
@@ -136,6 +136,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
|
||||
mTaskFragment =
|
||||
new TaskFragment(mAtm, mFragmentToken, true /* createdByOrganizer */);
|
||||
mTransaction = new WindowContainerTransaction();
|
||||
mTransaction.setTaskFragmentOrganizer(mIOrganizer);
|
||||
mFragmentWindowToken = mTaskFragment.mRemoteToken.toWindowContainerToken();
|
||||
mDefinition = new RemoteAnimationDefinition();
|
||||
mErrorToken = new Binder();
|
||||
@@ -155,11 +156,16 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
|
||||
doReturn(new Configuration()).when(mTaskFragmentInfo).getConfiguration();
|
||||
|
||||
// To prevent it from calling the real server.
|
||||
doNothing().when(mOrganizer).onTransactionHandled(any(), any());
|
||||
doNothing().when(mOrganizer).applyTransaction(any(), anyInt(), anyBoolean());
|
||||
doNothing().when(mOrganizer).onTransactionHandled(any(), any(), anyInt(), anyBoolean());
|
||||
|
||||
mController.registerOrganizer(mIOrganizer);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCallTaskFragmentCallbackWithoutRegister_throwsException() {
|
||||
mController.unregisterOrganizer(mIOrganizer);
|
||||
|
||||
doReturn(mTask).when(mTaskFragment).getTask();
|
||||
|
||||
assertThrows(IllegalArgumentException.class, () -> mController
|
||||
@@ -175,8 +181,6 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
|
||||
|
||||
@Test
|
||||
public void testOnTaskFragmentAppeared() {
|
||||
mController.registerOrganizer(mIOrganizer);
|
||||
|
||||
// No-op when the TaskFragment is not attached.
|
||||
mController.onTaskFragmentAppeared(mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment);
|
||||
mController.dispatchPendingEvents();
|
||||
@@ -194,7 +198,6 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
|
||||
|
||||
@Test
|
||||
public void testOnTaskFragmentInfoChanged() {
|
||||
mController.registerOrganizer(mIOrganizer);
|
||||
setupMockParent(mTaskFragment, mTask);
|
||||
|
||||
// No-op if onTaskFragmentAppeared is not called yet.
|
||||
@@ -233,8 +236,6 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
|
||||
|
||||
@Test
|
||||
public void testOnTaskFragmentVanished() {
|
||||
mController.registerOrganizer(mIOrganizer);
|
||||
|
||||
mTaskFragment.mTaskFragmentAppearedSent = true;
|
||||
mController.onTaskFragmentVanished(mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment);
|
||||
mController.dispatchPendingEvents();
|
||||
@@ -244,7 +245,6 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
|
||||
|
||||
@Test
|
||||
public void testOnTaskFragmentVanished_clearUpRemaining() {
|
||||
mController.registerOrganizer(mIOrganizer);
|
||||
setupMockParent(mTaskFragment, mTask);
|
||||
|
||||
// Not trigger onTaskFragmentAppeared.
|
||||
@@ -270,7 +270,6 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
|
||||
|
||||
@Test
|
||||
public void testOnTaskFragmentParentInfoChanged() {
|
||||
mController.registerOrganizer(mIOrganizer);
|
||||
setupMockParent(mTaskFragment, mTask);
|
||||
mTask.getConfiguration().smallestScreenWidthDp = 10;
|
||||
|
||||
@@ -317,7 +316,6 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
|
||||
public void testOnTaskFragmentError() {
|
||||
final Throwable exception = new IllegalArgumentException("Test exception");
|
||||
|
||||
mController.registerOrganizer(mIOrganizer);
|
||||
mController.onTaskFragmentError(mTaskFragment.getTaskFragmentOrganizer(),
|
||||
mErrorToken, null /* taskFragment */, HIERARCHY_OP_TYPE_SET_ADJACENT_ROOTS,
|
||||
exception);
|
||||
@@ -332,7 +330,6 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
|
||||
// Make sure the activity pid/uid is the same as the organizer caller.
|
||||
final int pid = Binder.getCallingPid();
|
||||
final int uid = Binder.getCallingUid();
|
||||
mController.registerOrganizer(mIOrganizer);
|
||||
final ActivityRecord activity = createActivityRecord(mDisplayContent);
|
||||
final Task task = activity.getTask();
|
||||
activity.info.applicationInfo.uid = uid;
|
||||
@@ -375,8 +372,6 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
|
||||
mTaskFragment.setTaskFragmentOrganizer(mOrganizer.getOrganizerToken(), uid,
|
||||
DEFAULT_TASK_FRAGMENT_ORGANIZER_PROCESS_NAME);
|
||||
mWindowOrganizerController.mLaunchTaskFragments.put(mFragmentToken, mTaskFragment);
|
||||
mController.registerOrganizer(mIOrganizer);
|
||||
mOrganizer.applyTransaction(mTransaction);
|
||||
final Task task = createTask(mDisplayContent);
|
||||
task.addChild(mTaskFragment, POSITION_TOP);
|
||||
final ActivityRecord activity = createActivityRecord(task);
|
||||
@@ -404,7 +399,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
|
||||
assertEquals(activity.intent, change.getActivityIntent());
|
||||
assertNotEquals(activity.token, change.getActivityToken());
|
||||
mTransaction.reparentActivityToTaskFragment(mFragmentToken, change.getActivityToken());
|
||||
mWindowOrganizerController.applyTransaction(mTransaction);
|
||||
assertApplyTransactionAllowed(mTransaction);
|
||||
|
||||
assertEquals(mTaskFragment, activity.getTaskFragment());
|
||||
// The temporary token can only be used once.
|
||||
@@ -414,7 +409,6 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
|
||||
|
||||
@Test
|
||||
public void testRegisterRemoteAnimations() {
|
||||
mController.registerOrganizer(mIOrganizer);
|
||||
mController.registerRemoteAnimations(mIOrganizer, TASK_ID, mDefinition);
|
||||
|
||||
assertEquals(mDefinition, mController.getRemoteAnimationDefinition(mIOrganizer, TASK_ID));
|
||||
@@ -425,23 +419,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWindowContainerTransaction_setTaskFragmentOrganizer() {
|
||||
mOrganizer.applyTransaction(mTransaction);
|
||||
|
||||
assertEquals(mIOrganizer, mTransaction.getTaskFragmentOrganizer());
|
||||
|
||||
mTransaction = new WindowContainerTransaction();
|
||||
mOrganizer.applySyncTransaction(
|
||||
mTransaction, mock(WindowContainerTransactionCallback.class));
|
||||
|
||||
assertEquals(mIOrganizer, mTransaction.getTaskFragmentOrganizer());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testApplyTransaction_enforceConfigurationChangeOnOrganizedTaskFragment()
|
||||
throws RemoteException {
|
||||
mOrganizer.applyTransaction(mTransaction);
|
||||
|
||||
public void testApplyTransaction_enforceConfigurationChangeOnOrganizedTaskFragment() {
|
||||
// Throw exception if the transaction is trying to change a window that is not organized by
|
||||
// the organizer.
|
||||
mTransaction.setBounds(mFragmentWindowToken, new Rect(0, 0, 100, 100));
|
||||
@@ -457,10 +435,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
|
||||
|
||||
|
||||
@Test
|
||||
public void testApplyTransaction_enforceHierarchyChange_deleteTaskFragment()
|
||||
throws RemoteException {
|
||||
mController.registerOrganizer(mIOrganizer);
|
||||
mOrganizer.applyTransaction(mTransaction);
|
||||
public void testApplyTransaction_enforceHierarchyChange_deleteTaskFragment() {
|
||||
doReturn(true).when(mTaskFragment).isAttached();
|
||||
|
||||
// Throw exception if the transaction is trying to change a window that is not organized by
|
||||
@@ -486,13 +461,10 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testApplyTransaction_enforceHierarchyChange_setAdjacentRoots()
|
||||
throws RemoteException {
|
||||
mAtm.mTaskFragmentOrganizerController.registerOrganizer(mIOrganizer);
|
||||
public void testApplyTransaction_enforceHierarchyChange_setAdjacentRoots() {
|
||||
final TaskFragment taskFragment2 =
|
||||
new TaskFragment(mAtm, new Binder(), true /* createdByOrganizer */);
|
||||
final WindowContainerToken token2 = taskFragment2.mRemoteToken.toWindowContainerToken();
|
||||
mOrganizer.applyTransaction(mTransaction);
|
||||
|
||||
// Throw exception if the transaction is trying to change a window that is not organized by
|
||||
// the organizer.
|
||||
@@ -513,9 +485,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testApplyTransaction_enforceHierarchyChange_createTaskFragment()
|
||||
throws RemoteException {
|
||||
mController.registerOrganizer(mIOrganizer);
|
||||
public void testApplyTransaction_enforceHierarchyChange_createTaskFragment() {
|
||||
final ActivityRecord ownerActivity = createActivityRecord(mDisplayContent);
|
||||
final IBinder fragmentToken = new Binder();
|
||||
|
||||
@@ -526,11 +496,10 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
|
||||
mTransaction.reparentActivityToTaskFragment(mFragmentToken, mock(IBinder.class));
|
||||
mTransaction.setAdjacentTaskFragments(mFragmentToken, mock(IBinder.class),
|
||||
null /* options */);
|
||||
mAtm.getWindowOrganizerController().applyTransaction(mTransaction);
|
||||
assertApplyTransactionAllowed(mTransaction);
|
||||
|
||||
// Successfully created a TaskFragment.
|
||||
final TaskFragment taskFragment = mAtm.mWindowOrganizerController
|
||||
.getTaskFragment(fragmentToken);
|
||||
final TaskFragment taskFragment = mWindowOrganizerController.getTaskFragment(fragmentToken);
|
||||
assertNotNull(taskFragment);
|
||||
assertEquals(ownerActivity.getTask(), taskFragment.getTask());
|
||||
}
|
||||
@@ -539,7 +508,6 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
|
||||
public void testApplyTransaction_enforceTaskFragmentOrganized_startActivityInTaskFragment() {
|
||||
final Task task = createTask(mDisplayContent);
|
||||
final ActivityRecord ownerActivity = createActivityRecord(task);
|
||||
mController.registerOrganizer(mIOrganizer);
|
||||
mTaskFragment = new TaskFragmentBuilder(mAtm)
|
||||
.setParentTask(task)
|
||||
.setFragmentToken(mFragmentToken)
|
||||
@@ -562,7 +530,6 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
|
||||
public void testApplyTransaction_enforceTaskFragmentOrganized_reparentActivityInTaskFragment() {
|
||||
final Task task = createTask(mDisplayContent);
|
||||
final ActivityRecord activity = createActivityRecord(task);
|
||||
mController.registerOrganizer(mIOrganizer);
|
||||
mTaskFragment = new TaskFragmentBuilder(mAtm)
|
||||
.setParentTask(task)
|
||||
.setFragmentToken(mFragmentToken)
|
||||
@@ -583,7 +550,6 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
|
||||
@Test
|
||||
public void testApplyTransaction_enforceTaskFragmentOrganized_setAdjacentTaskFragments() {
|
||||
final Task task = createTask(mDisplayContent);
|
||||
mController.registerOrganizer(mIOrganizer);
|
||||
mTaskFragment = new TaskFragmentBuilder(mAtm)
|
||||
.setParentTask(task)
|
||||
.setFragmentToken(mFragmentToken)
|
||||
@@ -623,7 +589,6 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
|
||||
@Test
|
||||
public void testApplyTransaction_enforceTaskFragmentOrganized_requestFocusOnTaskFragment() {
|
||||
final Task task = createTask(mDisplayContent);
|
||||
mController.registerOrganizer(mIOrganizer);
|
||||
mTaskFragment = new TaskFragmentBuilder(mAtm)
|
||||
.setParentTask(task)
|
||||
.setFragmentToken(mFragmentToken)
|
||||
@@ -642,44 +607,38 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testApplyTransaction_createTaskFragment_failForDifferentUid()
|
||||
throws RemoteException {
|
||||
mController.registerOrganizer(mIOrganizer);
|
||||
public void testApplyTransaction_createTaskFragment_failForDifferentUid() {
|
||||
final ActivityRecord activity = createActivityRecord(mDisplayContent);
|
||||
final int uid = Binder.getCallingUid();
|
||||
final IBinder fragmentToken = new Binder();
|
||||
final TaskFragmentCreationParams params = new TaskFragmentCreationParams.Builder(
|
||||
mOrganizerToken, fragmentToken, activity.token).build();
|
||||
mOrganizer.applyTransaction(mTransaction);
|
||||
mTransaction.createTaskFragment(params);
|
||||
|
||||
// Fail to create TaskFragment when the task uid is different from caller.
|
||||
activity.info.applicationInfo.uid = uid;
|
||||
activity.getTask().effectiveUid = uid + 1;
|
||||
mWindowOrganizerController.applyTransaction(mTransaction);
|
||||
assertApplyTransactionAllowed(mTransaction);
|
||||
|
||||
assertNull(mWindowOrganizerController.getTaskFragment(fragmentToken));
|
||||
|
||||
// Fail to create TaskFragment when the task uid is different from owner activity.
|
||||
activity.info.applicationInfo.uid = uid + 1;
|
||||
activity.getTask().effectiveUid = uid;
|
||||
mWindowOrganizerController.applyTransaction(mTransaction);
|
||||
assertApplyTransactionAllowed(mTransaction);
|
||||
|
||||
assertNull(mWindowOrganizerController.getTaskFragment(fragmentToken));
|
||||
|
||||
// Successfully created a TaskFragment for same uid.
|
||||
activity.info.applicationInfo.uid = uid;
|
||||
activity.getTask().effectiveUid = uid;
|
||||
mWindowOrganizerController.applyTransaction(mTransaction);
|
||||
assertApplyTransactionAllowed(mTransaction);
|
||||
|
||||
assertNotNull(mWindowOrganizerController.getTaskFragment(fragmentToken));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testApplyTransaction_enforceHierarchyChange_reparentChildren()
|
||||
throws RemoteException {
|
||||
mOrganizer.applyTransaction(mTransaction);
|
||||
mController.registerOrganizer(mIOrganizer);
|
||||
public void testApplyTransaction_enforceHierarchyChange_reparentChildren() {
|
||||
doReturn(true).when(mTaskFragment).isAttached();
|
||||
|
||||
// Throw exception if the transaction is trying to change a window that is not organized by
|
||||
@@ -699,14 +658,12 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testApplyTransaction_reparentActivityToTaskFragment_triggerLifecycleUpdate()
|
||||
throws RemoteException {
|
||||
public void testApplyTransaction_reparentActivityToTaskFragment_triggerLifecycleUpdate() {
|
||||
final Task task = createTask(mDisplayContent);
|
||||
final ActivityRecord activity = createActivityRecord(task);
|
||||
// Skip manipulate the SurfaceControl.
|
||||
doNothing().when(activity).setDropInputMode(anyInt());
|
||||
mOrganizer.applyTransaction(mTransaction);
|
||||
mController.registerOrganizer(mIOrganizer);
|
||||
mTaskFragment = new TaskFragmentBuilder(mAtm)
|
||||
.setParentTask(task)
|
||||
.setFragmentToken(mFragmentToken)
|
||||
@@ -717,15 +674,13 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
|
||||
doReturn(EMBEDDING_ALLOWED).when(mTaskFragment).isAllowedToEmbedActivity(activity);
|
||||
clearInvocations(mAtm.mRootWindowContainer);
|
||||
|
||||
mAtm.getWindowOrganizerController().applyTransaction(mTransaction);
|
||||
assertApplyTransactionAllowed(mTransaction);
|
||||
|
||||
verify(mAtm.mRootWindowContainer).resumeFocusedTasksTopActivities();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testApplyTransaction_requestFocusOnTaskFragment() {
|
||||
mOrganizer.applyTransaction(mTransaction);
|
||||
mController.registerOrganizer(mIOrganizer);
|
||||
final Task task = createTask(mDisplayContent);
|
||||
final IBinder token0 = new Binder();
|
||||
final TaskFragment tf0 = new TaskFragmentBuilder(mAtm)
|
||||
@@ -750,7 +705,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
|
||||
final ActivityRecord activityInOtherTask = createActivityRecord(mDefaultDisplay);
|
||||
mDisplayContent.setFocusedApp(activityInOtherTask);
|
||||
mTransaction.requestFocusOnTaskFragment(token0);
|
||||
mWindowOrganizerController.applyTransaction(mTransaction);
|
||||
assertApplyTransactionAllowed(mTransaction);
|
||||
|
||||
assertEquals(activityInOtherTask, mDisplayContent.mFocusedApp);
|
||||
|
||||
@@ -758,7 +713,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
|
||||
activity0.setState(ActivityRecord.State.PAUSED, "test");
|
||||
activity1.setState(ActivityRecord.State.RESUMED, "test");
|
||||
mDisplayContent.setFocusedApp(activity1);
|
||||
mWindowOrganizerController.applyTransaction(mTransaction);
|
||||
assertApplyTransactionAllowed(mTransaction);
|
||||
|
||||
assertEquals(activity1, mDisplayContent.mFocusedApp);
|
||||
|
||||
@@ -766,28 +721,29 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
|
||||
// has a resumed activity.
|
||||
activity0.setState(ActivityRecord.State.RESUMED, "test");
|
||||
mDisplayContent.setFocusedApp(activity1);
|
||||
mWindowOrganizerController.applyTransaction(mTransaction);
|
||||
assertApplyTransactionAllowed(mTransaction);
|
||||
|
||||
assertEquals(activity0, mDisplayContent.mFocusedApp);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testApplyTransaction_skipTransactionForUnregisterOrganizer() {
|
||||
mController.unregisterOrganizer(mIOrganizer);
|
||||
final ActivityRecord ownerActivity = createActivityRecord(mDisplayContent);
|
||||
final IBinder fragmentToken = new Binder();
|
||||
|
||||
// Allow organizer to create TaskFragment and start/reparent activity to TaskFragment.
|
||||
createTaskFragmentFromOrganizer(mTransaction, ownerActivity, fragmentToken);
|
||||
mAtm.mWindowOrganizerController.applyTransaction(mTransaction);
|
||||
assertApplyTransactionAllowed(mTransaction);
|
||||
|
||||
// Nothing should happen as the organizer is not registered.
|
||||
assertNull(mAtm.mWindowOrganizerController.getTaskFragment(fragmentToken));
|
||||
assertNull(mWindowOrganizerController.getTaskFragment(fragmentToken));
|
||||
|
||||
mController.registerOrganizer(mIOrganizer);
|
||||
mAtm.mWindowOrganizerController.applyTransaction(mTransaction);
|
||||
assertApplyTransactionAllowed(mTransaction);
|
||||
|
||||
// Successfully created when the organizer is registered.
|
||||
assertNotNull(mAtm.mWindowOrganizerController.getTaskFragment(fragmentToken));
|
||||
assertNotNull(mWindowOrganizerController.getTaskFragment(fragmentToken));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -799,13 +755,13 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
|
||||
|
||||
// Not allow to start activity in a TaskFragment that is in a PIP Task.
|
||||
mTransaction.startActivityInTaskFragment(
|
||||
mFragmentToken, activity.token, new Intent(), null /* activityOptions */)
|
||||
mFragmentToken, activity.token, new Intent(), null /* activityOptions */)
|
||||
.setErrorCallbackToken(mErrorToken);
|
||||
mWindowOrganizerController.applyTransaction(mTransaction);
|
||||
assertApplyTransactionAllowed(mTransaction);
|
||||
|
||||
verify(mAtm.getActivityStartController(), never()).startActivityInTaskFragment(any(), any(),
|
||||
any(), any(), anyInt(), anyInt(), any());
|
||||
verify(mAtm.mWindowOrganizerController).sendTaskFragmentOperationFailure(eq(mIOrganizer),
|
||||
verify(mWindowOrganizerController).sendTaskFragmentOperationFailure(eq(mIOrganizer),
|
||||
eq(mErrorToken), eq(mTaskFragment),
|
||||
eq(HIERARCHY_OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT),
|
||||
any(IllegalArgumentException.class));
|
||||
@@ -820,7 +776,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
|
||||
// Not allow to reparent activity to a TaskFragment that is in a PIP Task.
|
||||
mTransaction.reparentActivityToTaskFragment(mFragmentToken, activity.token)
|
||||
.setErrorCallbackToken(mErrorToken);
|
||||
mWindowOrganizerController.applyTransaction(mTransaction);
|
||||
assertApplyTransactionAllowed(mTransaction);
|
||||
|
||||
verify(mWindowOrganizerController).sendTaskFragmentOperationFailure(eq(mIOrganizer),
|
||||
eq(mErrorToken), eq(mTaskFragment),
|
||||
@@ -836,9 +792,9 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
|
||||
|
||||
// Not allow to set adjacent on a TaskFragment that is in a PIP Task.
|
||||
mTransaction.setAdjacentTaskFragments(mFragmentToken, null /* fragmentToken2 */,
|
||||
null /* options */)
|
||||
null /* options */)
|
||||
.setErrorCallbackToken(mErrorToken);
|
||||
mWindowOrganizerController.applyTransaction(mTransaction);
|
||||
assertApplyTransactionAllowed(mTransaction);
|
||||
|
||||
verify(mWindowOrganizerController).sendTaskFragmentOperationFailure(eq(mIOrganizer),
|
||||
eq(mErrorToken), eq(mTaskFragment),
|
||||
@@ -849,7 +805,6 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
|
||||
|
||||
@Test
|
||||
public void testTaskFragmentInPip_createTaskFragment() {
|
||||
mController.registerOrganizer(mIOrganizer);
|
||||
final Task pipTask = createTask(mDisplayContent, WINDOWING_MODE_PINNED,
|
||||
ACTIVITY_TYPE_STANDARD);
|
||||
final ActivityRecord activity = createActivityRecord(pipTask);
|
||||
@@ -859,7 +814,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
|
||||
// Not allow to create TaskFragment in a PIP Task.
|
||||
createTaskFragmentFromOrganizer(mTransaction, activity, fragmentToken);
|
||||
mTransaction.setErrorCallbackToken(mErrorToken);
|
||||
mWindowOrganizerController.applyTransaction(mTransaction);
|
||||
assertApplyTransactionAllowed(mTransaction);
|
||||
|
||||
verify(mWindowOrganizerController).sendTaskFragmentOperationFailure(eq(mIOrganizer),
|
||||
eq(mErrorToken), eq(null), eq(HIERARCHY_OP_TYPE_CREATE_TASK_FRAGMENT),
|
||||
@@ -875,7 +830,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
|
||||
// Not allow to delete a TaskFragment that is in a PIP Task.
|
||||
mTransaction.deleteTaskFragment(mFragmentWindowToken)
|
||||
.setErrorCallbackToken(mErrorToken);
|
||||
mWindowOrganizerController.applyTransaction(mTransaction);
|
||||
assertApplyTransactionAllowed(mTransaction);
|
||||
|
||||
verify(mWindowOrganizerController).sendTaskFragmentOperationFailure(eq(mIOrganizer),
|
||||
eq(mErrorToken), eq(mTaskFragment), eq(HIERARCHY_OP_TYPE_DELETE_TASK_FRAGMENT),
|
||||
@@ -885,7 +840,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
|
||||
// Allow organizer to delete empty TaskFragment for cleanup.
|
||||
final Task task = mTaskFragment.getTask();
|
||||
mTaskFragment.removeChild(mTaskFragment.getTopMostActivity());
|
||||
mWindowOrganizerController.applyTransaction(mTransaction);
|
||||
assertApplyTransactionAllowed(mTransaction);
|
||||
|
||||
assertNull(mWindowOrganizerController.getTaskFragment(mFragmentToken));
|
||||
assertNull(task.getTopChild());
|
||||
@@ -916,7 +871,6 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
|
||||
doReturn(false).when(task).shouldBeVisible(any());
|
||||
|
||||
// Sending events
|
||||
mController.registerOrganizer(mIOrganizer);
|
||||
taskFragment.mTaskFragmentAppearedSent = true;
|
||||
mController.onTaskFragmentInfoChanged(mIOrganizer, taskFragment);
|
||||
mController.dispatchPendingEvents();
|
||||
@@ -942,7 +896,6 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
|
||||
taskFragment.setResumedActivity(null, "test");
|
||||
|
||||
// Sending events
|
||||
mController.registerOrganizer(mIOrganizer);
|
||||
taskFragment.mTaskFragmentAppearedSent = true;
|
||||
mController.onTaskFragmentInfoChanged(mIOrganizer, taskFragment);
|
||||
mController.dispatchPendingEvents();
|
||||
@@ -977,7 +930,6 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
|
||||
assertTrue(parentTask.shouldBeVisible(null));
|
||||
|
||||
// Dispatch pending info changed event from creating the activity
|
||||
mController.registerOrganizer(mIOrganizer);
|
||||
taskFragment.mTaskFragmentAppearedSent = true;
|
||||
mController.onTaskFragmentInfoChanged(mIOrganizer, taskFragment);
|
||||
mController.dispatchPendingEvents();
|
||||
@@ -1013,7 +965,6 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
|
||||
assertTrue(task.shouldBeVisible(null));
|
||||
|
||||
// Dispatch pending info changed event from creating the activity
|
||||
mController.registerOrganizer(mIOrganizer);
|
||||
taskFragment.mTaskFragmentAppearedSent = true;
|
||||
mController.onTaskFragmentInfoChanged(mIOrganizer, taskFragment);
|
||||
mController.dispatchPendingEvents();
|
||||
@@ -1039,13 +990,11 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
|
||||
* {@link WindowOrganizerController}.
|
||||
*/
|
||||
@Test
|
||||
public void testTaskFragmentRemoved_cleanUpEmbeddedTaskFragment()
|
||||
throws RemoteException {
|
||||
mController.registerOrganizer(mIOrganizer);
|
||||
public void testTaskFragmentRemoved_cleanUpEmbeddedTaskFragment() {
|
||||
final ActivityRecord ownerActivity = createActivityRecord(mDisplayContent);
|
||||
final IBinder fragmentToken = new Binder();
|
||||
createTaskFragmentFromOrganizer(mTransaction, ownerActivity, fragmentToken);
|
||||
mAtm.getWindowOrganizerController().applyTransaction(mTransaction);
|
||||
assertApplyTransactionAllowed(mTransaction);
|
||||
final TaskFragment taskFragment = mWindowOrganizerController.getTaskFragment(fragmentToken);
|
||||
|
||||
assertNotNull(taskFragment);
|
||||
@@ -1060,9 +1009,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
|
||||
* its parent bounds.
|
||||
*/
|
||||
@Test
|
||||
public void testUntrustedEmbedding_configChange() throws RemoteException {
|
||||
mController.registerOrganizer(mIOrganizer);
|
||||
mOrganizer.applyTransaction(mTransaction);
|
||||
public void testUntrustedEmbedding_configChange() {
|
||||
mTaskFragment.setTaskFragmentOrganizer(mOrganizerToken, 10 /* uid */,
|
||||
"Test:TaskFragmentOrganizer" /* processName */);
|
||||
doReturn(false).when(mTaskFragment).isAllowedToBeEmbeddedInTrustedMode();
|
||||
@@ -1123,8 +1070,6 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
|
||||
// Make minWidth/minHeight exceeds the TaskFragment bounds.
|
||||
activity.info.windowLayout = new ActivityInfo.WindowLayout(
|
||||
0, 0, 0, 0, 0, mTaskFragBounds.width() + 10, mTaskFragBounds.height() + 10);
|
||||
mOrganizer.applyTransaction(mTransaction);
|
||||
mController.registerOrganizer(mIOrganizer);
|
||||
mTaskFragment = new TaskFragmentBuilder(mAtm)
|
||||
.setParentTask(task)
|
||||
.setFragmentToken(mFragmentToken)
|
||||
@@ -1137,7 +1082,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
|
||||
// minimum dimensions.
|
||||
mTransaction.reparentActivityToTaskFragment(mFragmentToken, activity.token)
|
||||
.setErrorCallbackToken(mErrorToken);
|
||||
mWindowOrganizerController.applyTransaction(mTransaction);
|
||||
assertApplyTransactionAllowed(mTransaction);
|
||||
// The pending event will be dispatched on the handler (from requestTraversal).
|
||||
waitHandlerIdle(mWm.mAnimationHandler);
|
||||
|
||||
@@ -1148,8 +1093,6 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
|
||||
@Test
|
||||
public void testMinDimensionViolation_ReparentChildren() {
|
||||
final Task task = createTask(mDisplayContent);
|
||||
mOrganizer.applyTransaction(mTransaction);
|
||||
mController.registerOrganizer(mIOrganizer);
|
||||
final IBinder oldFragToken = new Binder();
|
||||
final TaskFragment oldTaskFrag = new TaskFragmentBuilder(mAtm)
|
||||
.setParentTask(task)
|
||||
@@ -1175,7 +1118,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
|
||||
mTransaction.reparentChildren(oldTaskFrag.mRemoteToken.toWindowContainerToken(),
|
||||
mTaskFragment.mRemoteToken.toWindowContainerToken())
|
||||
.setErrorCallbackToken(mErrorToken);
|
||||
mWindowOrganizerController.applyTransaction(mTransaction);
|
||||
assertApplyTransactionAllowed(mTransaction);
|
||||
// The pending event will be dispatched on the handler (from requestTraversal).
|
||||
waitHandlerIdle(mWm.mAnimationHandler);
|
||||
|
||||
@@ -1186,8 +1129,6 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
|
||||
@Test
|
||||
public void testMinDimensionViolation_SetBounds() {
|
||||
final Task task = createTask(mDisplayContent);
|
||||
mOrganizer.applyTransaction(mTransaction);
|
||||
mController.registerOrganizer(mIOrganizer);
|
||||
mTaskFragment = new TaskFragmentBuilder(mAtm)
|
||||
.setParentTask(task)
|
||||
.createActivityCount(1)
|
||||
@@ -1206,7 +1147,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
|
||||
// minimum dimensions.
|
||||
mTransaction.setBounds(mTaskFragment.mRemoteToken.toWindowContainerToken(), mTaskFragBounds)
|
||||
.setErrorCallbackToken(mErrorToken);
|
||||
mWindowOrganizerController.applyTransaction(mTransaction);
|
||||
assertApplyTransactionAllowed(mTransaction);
|
||||
|
||||
assertWithMessage("setBounds must not be performed.")
|
||||
.that(mTaskFragment.getBounds()).isEqualTo(task.getBounds());
|
||||
@@ -1214,18 +1155,17 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
|
||||
|
||||
@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());
|
||||
verify(mOrganizer).onTransactionHandled(eq(transaction.getTransactionToken()), any(),
|
||||
anyInt(), anyBoolean());
|
||||
verify(mOrganizer, never()).applyTransaction(any(), anyInt(), anyBoolean());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDispatchTransaction_deferTransitionReady() {
|
||||
mController.registerOrganizer(mIOrganizer);
|
||||
setupMockParent(mTaskFragment, mTask);
|
||||
final ArgumentCaptor<IBinder> tokenCaptor = ArgumentCaptor.forClass(IBinder.class);
|
||||
final ArgumentCaptor<WindowContainerTransaction> wctCaptor =
|
||||
@@ -1238,12 +1178,15 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
|
||||
|
||||
// Defer transition when send TaskFragment transaction during transition collection.
|
||||
verify(mTransitionController).deferTransitionReady();
|
||||
verify(mOrganizer).onTransactionHandled(tokenCaptor.capture(), wctCaptor.capture());
|
||||
verify(mOrganizer).onTransactionHandled(tokenCaptor.capture(), wctCaptor.capture(),
|
||||
anyInt(), anyBoolean());
|
||||
|
||||
mController.onTransactionHandled(mIOrganizer, tokenCaptor.getValue(), wctCaptor.getValue());
|
||||
final IBinder transactionToken = tokenCaptor.getValue();
|
||||
final WindowContainerTransaction wct = wctCaptor.getValue();
|
||||
wct.setTaskFragmentOrganizer(mIOrganizer);
|
||||
mController.onTransactionHandled(transactionToken, wct, getTransitionType(wct),
|
||||
false /* shouldApplyIndependently */);
|
||||
|
||||
// Apply the organizer change and continue transition.
|
||||
verify(mWindowOrganizerController).applyTransaction(wctCaptor.getValue());
|
||||
verify(mTransitionController).continueTransitionReady();
|
||||
}
|
||||
|
||||
@@ -1258,7 +1201,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
|
||||
ownerActivity.getTask().effectiveUid = uid;
|
||||
final TaskFragmentCreationParams params = new TaskFragmentCreationParams.Builder(
|
||||
mOrganizerToken, fragmentToken, ownerActivity.token).build();
|
||||
mOrganizer.applyTransaction(wct);
|
||||
wct.setTaskFragmentOrganizer(mIOrganizer);
|
||||
|
||||
// Allow organizer to create TaskFragment and start/reparent activity to TaskFragment.
|
||||
wct.createTaskFragment(params);
|
||||
@@ -1266,22 +1209,14 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
|
||||
|
||||
/** Asserts that applying the given transaction will throw a {@link SecurityException}. */
|
||||
private void assertApplyTransactionDisallowed(WindowContainerTransaction t) {
|
||||
assertThrows(SecurityException.class, () -> {
|
||||
try {
|
||||
mAtm.getWindowOrganizerController().applyTransaction(t);
|
||||
} catch (RemoteException e) {
|
||||
fail();
|
||||
}
|
||||
});
|
||||
assertThrows(SecurityException.class, () ->
|
||||
mController.applyTransaction(t, getTransitionType(t),
|
||||
false /* shouldApplyIndependently */));
|
||||
}
|
||||
|
||||
/** Asserts that applying the given transaction will not throw any exception. */
|
||||
private void assertApplyTransactionAllowed(WindowContainerTransaction t) {
|
||||
try {
|
||||
mAtm.getWindowOrganizerController().applyTransaction(t);
|
||||
} catch (RemoteException e) {
|
||||
fail();
|
||||
}
|
||||
mController.applyTransaction(t, getTransitionType(t), false /* shouldApplyIndependently */);
|
||||
}
|
||||
|
||||
/** Asserts that there will be a transaction for TaskFragment appeared. */
|
||||
@@ -1367,8 +1302,6 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
|
||||
|
||||
/** Setups an embedded TaskFragment in a PIP Task. */
|
||||
private void setupTaskFragmentInPip() {
|
||||
mOrganizer.applyTransaction(mTransaction);
|
||||
mController.registerOrganizer(mIOrganizer);
|
||||
mTaskFragment = new TaskFragmentBuilder(mAtm)
|
||||
.setCreateParentTask()
|
||||
.setFragmentToken(mFragmentToken)
|
||||
@@ -1376,8 +1309,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
|
||||
.createActivityCount(1)
|
||||
.build();
|
||||
mFragmentWindowToken = mTaskFragment.mRemoteToken.toWindowContainerToken();
|
||||
mAtm.mWindowOrganizerController.mLaunchTaskFragments
|
||||
.put(mFragmentToken, mTaskFragment);
|
||||
mWindowOrganizerController.mLaunchTaskFragments.put(mFragmentToken, mTaskFragment);
|
||||
mTaskFragment.getTask().setWindowingMode(WINDOWING_MODE_PINNED);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user