Merge "Add TaskFragmentOrganizer#applyTransaction with request transition" into tm-qpr-dev
This commit is contained in:
@@ -57,6 +57,12 @@ interface ITaskFragmentOrganizerController {
|
|||||||
* Notifies the server that the organizer has finished handling the given transaction. The
|
* Notifies the server that the organizer has finished handling the given transaction. The
|
||||||
* server should apply the given {@link WindowContainerTransaction} for the necessary changes.
|
* server should apply the given {@link WindowContainerTransaction} for the necessary changes.
|
||||||
*/
|
*/
|
||||||
void onTransactionHandled(in ITaskFragmentOrganizer organizer, in IBinder transactionToken,
|
void onTransactionHandled(in IBinder transactionToken, in WindowContainerTransaction wct,
|
||||||
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;
|
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_ACTIVITY_REPARENTED_TO_TASK;
|
||||||
import static android.window.TaskFragmentTransaction.TYPE_TASK_FRAGMENT_APPEARED;
|
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_ERROR;
|
||||||
import static android.window.TaskFragmentTransaction.TYPE_TASK_FRAGMENT_INFO_CHANGED;
|
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_PARENT_INFO_CHANGED;
|
||||||
import static android.window.TaskFragmentTransaction.TYPE_TASK_FRAGMENT_VANISHED;
|
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.CallSuper;
|
||||||
import android.annotation.NonNull;
|
import android.annotation.NonNull;
|
||||||
import android.annotation.Nullable;
|
import android.annotation.Nullable;
|
||||||
import android.annotation.TestApi;
|
import android.annotation.TestApi;
|
||||||
|
import android.app.WindowConfiguration;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.res.Configuration;
|
import android.content.res.Configuration;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
@@ -34,6 +42,7 @@ import android.os.IBinder;
|
|||||||
import android.os.RemoteException;
|
import android.os.RemoteException;
|
||||||
import android.util.SparseArray;
|
import android.util.SparseArray;
|
||||||
import android.view.RemoteAnimationDefinition;
|
import android.view.RemoteAnimationDefinition;
|
||||||
|
import android.view.WindowManager;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -168,20 +177,110 @@ public class TaskFragmentOrganizer extends WindowOrganizer {
|
|||||||
* {@link #onTransactionReady(TaskFragmentTransaction)}
|
* {@link #onTransactionReady(TaskFragmentTransaction)}
|
||||||
* @param wct {@link WindowContainerTransaction} that the server should apply for
|
* @param wct {@link WindowContainerTransaction} that the server should apply for
|
||||||
* update of the transaction.
|
* update of the transaction.
|
||||||
* @see com.android.server.wm.WindowOrganizerController#enforceTaskPermission for permission
|
* @param transitionType {@link WindowManager.TransitionType} if it needs to start a
|
||||||
* requirement.
|
* 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
|
* @hide
|
||||||
*/
|
*/
|
||||||
public void onTransactionHandled(@NonNull IBinder transactionToken,
|
public void onTransactionHandled(@NonNull IBinder transactionToken,
|
||||||
@NonNull WindowContainerTransaction wct) {
|
@NonNull WindowContainerTransaction wct,
|
||||||
|
@WindowManager.TransitionType int transitionType, boolean shouldApplyIndependently) {
|
||||||
wct.setTaskFragmentOrganizer(mInterface);
|
wct.setTaskFragmentOrganizer(mInterface);
|
||||||
try {
|
try {
|
||||||
getController().onTransactionHandled(mInterface, transactionToken, wct);
|
getController().onTransactionHandled(transactionToken, wct, transitionType,
|
||||||
|
shouldApplyIndependently);
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
throw e.rethrowFromSystemServer();
|
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.
|
* 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.
|
// Notify the server, and the server should apply the WindowContainerTransaction.
|
||||||
onTransactionHandled(transaction.getTransactionToken(), wct);
|
onTransactionHandled(transaction.getTransactionToken(), wct, getTransitionType(wct),
|
||||||
}
|
false /* shouldApplyIndependently */);
|
||||||
|
|
||||||
@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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private final ITaskFragmentOrganizer mInterface = new ITaskFragmentOrganizer.Stub() {
|
private final ITaskFragmentOrganizer mInterface = new ITaskFragmentOrganizer.Stub() {
|
||||||
|
|||||||
@@ -763,10 +763,8 @@ public final class WindowContainerTransaction implements Parcelable {
|
|||||||
* @hide
|
* @hide
|
||||||
*/
|
*/
|
||||||
@NonNull
|
@NonNull
|
||||||
WindowContainerTransaction setTaskFragmentOrganizer(@NonNull ITaskFragmentOrganizer organizer) {
|
public WindowContainerTransaction setTaskFragmentOrganizer(
|
||||||
if (mTaskFragmentOrganizer != null) {
|
@NonNull ITaskFragmentOrganizer organizer) {
|
||||||
throw new IllegalStateException("Can't set multiple organizers for one transaction.");
|
|
||||||
}
|
|
||||||
mTaskFragmentOrganizer = organizer;
|
mTaskFragmentOrganizer = organizer;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1801,6 +1801,12 @@
|
|||||||
"group": "WM_DEBUG_WINDOW_TRANSITIONS",
|
"group": "WM_DEBUG_WINDOW_TRANSITIONS",
|
||||||
"at": "com\/android\/server\/wm\/Transition.java"
|
"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": {
|
"-347866078": {
|
||||||
"message": "Setting move animation on %s",
|
"message": "Setting move animation on %s",
|
||||||
"level": "VERBOSE",
|
"level": "VERBOSE",
|
||||||
@@ -2491,6 +2497,12 @@
|
|||||||
"group": "WM_DEBUG_ANIM",
|
"group": "WM_DEBUG_ANIM",
|
||||||
"at": "com\/android\/server\/wm\/WindowState.java"
|
"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": {
|
"288485303": {
|
||||||
"message": "Attempted to set remove mode to a display that does not exist: %d",
|
"message": "Attempted to set remove mode to a display that does not exist: %d",
|
||||||
"level": "WARN",
|
"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_OP_TYPE;
|
||||||
import static android.window.TaskFragmentOrganizer.KEY_ERROR_CALLBACK_TASK_FRAGMENT_INFO;
|
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.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_ACTIVITY_REPARENTED_TO_TASK;
|
||||||
import static android.window.TaskFragmentTransaction.TYPE_TASK_FRAGMENT_APPEARED;
|
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_ERROR;
|
||||||
@@ -109,7 +110,7 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
|
|||||||
private Consumer<List<SplitInfo>> mEmbeddingCallback;
|
private Consumer<List<SplitInfo>> mEmbeddingCallback;
|
||||||
private final List<SplitInfo> mLastReportedSplitStates = new ArrayList<>();
|
private final List<SplitInfo> mLastReportedSplitStates = new ArrayList<>();
|
||||||
private final Handler mHandler;
|
private final Handler mHandler;
|
||||||
private final Object mLock = new Object();
|
final Object mLock = new Object();
|
||||||
private final ActivityStartMonitor mActivityStartMonitor;
|
private final ActivityStartMonitor mActivityStartMonitor;
|
||||||
|
|
||||||
public SplitController() {
|
public SplitController() {
|
||||||
@@ -209,8 +210,10 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Notify the server, and the server should apply the WindowContainerTransaction.
|
// Notify the server, and the server should apply and merge the
|
||||||
mPresenter.onTransactionHandled(transaction.getTransactionToken(), wct);
|
// WindowContainerTransaction to the active sync to finish the TaskFragmentTransaction.
|
||||||
|
mPresenter.onTransactionHandled(transaction.getTransactionToken(), wct,
|
||||||
|
getTransitionType(wct), false /* shouldApplyIndependently */);
|
||||||
updateCallbackIfNecessary();
|
updateCallbackIfNecessary();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -221,6 +224,9 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
|
|||||||
* @param wct The {@link WindowContainerTransaction} to make any changes with if needed.
|
* @param wct The {@link WindowContainerTransaction} to make any changes with if needed.
|
||||||
* @param taskFragmentInfo Info of the TaskFragment that is created.
|
* @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
|
@VisibleForTesting
|
||||||
@GuardedBy("mLock")
|
@GuardedBy("mLock")
|
||||||
void onTaskFragmentAppeared(@NonNull WindowContainerTransaction wct,
|
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 wct The {@link WindowContainerTransaction} to make any changes with if needed.
|
||||||
* @param taskFragmentInfo Info of the TaskFragment that is changed.
|
* @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
|
@VisibleForTesting
|
||||||
@GuardedBy("mLock")
|
@GuardedBy("mLock")
|
||||||
void onTaskFragmentInfoChanged(@NonNull WindowContainerTransaction wct,
|
void onTaskFragmentInfoChanged(@NonNull WindowContainerTransaction wct,
|
||||||
@@ -430,6 +439,9 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
|
|||||||
* transaction operation.
|
* transaction operation.
|
||||||
* @param exception exception from the server side.
|
* @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
|
@VisibleForTesting
|
||||||
@GuardedBy("mLock")
|
@GuardedBy("mLock")
|
||||||
void onTaskFragmentError(@NonNull WindowContainerTransaction wct,
|
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
|
* Called when we have been waiting too long for the TaskFragment to become non-empty after
|
||||||
* creation.
|
* creation.
|
||||||
*/
|
*/
|
||||||
|
@GuardedBy("mLock")
|
||||||
void onTaskFragmentAppearEmptyTimeout(@NonNull TaskFragmentContainer container) {
|
void onTaskFragmentAppearEmptyTimeout(@NonNull TaskFragmentContainer container) {
|
||||||
synchronized (mLock) {
|
final WindowContainerTransaction wct = new WindowContainerTransaction();
|
||||||
final WindowContainerTransaction wct = new WindowContainerTransaction();
|
onTaskFragmentAppearEmptyTimeout(wct, container);
|
||||||
onTaskFragmentAppearEmptyTimeout(wct, container);
|
// Can be applied independently as a timeout callback.
|
||||||
mPresenter.applyTransaction(wct);
|
mPresenter.applyTransaction(wct, getTransitionType(wct),
|
||||||
}
|
true /* shouldApplyIndependently */);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when we have been waiting too long for the TaskFragment to become non-empty after
|
* Called when we have been waiting too long for the TaskFragment to become non-empty after
|
||||||
* creation.
|
* creation.
|
||||||
*/
|
*/
|
||||||
|
@GuardedBy("mLock")
|
||||||
void onTaskFragmentAppearEmptyTimeout(@NonNull WindowContainerTransaction wct,
|
void onTaskFragmentAppearEmptyTimeout(@NonNull WindowContainerTransaction wct,
|
||||||
@NonNull TaskFragmentContainer container) {
|
@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) {
|
synchronized (mLock) {
|
||||||
final WindowContainerTransaction wct = new WindowContainerTransaction();
|
final WindowContainerTransaction wct = new WindowContainerTransaction();
|
||||||
SplitController.this.onActivityCreated(wct, activity);
|
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) {
|
synchronized (mLock) {
|
||||||
final WindowContainerTransaction wct = new WindowContainerTransaction();
|
final WindowContainerTransaction wct = new WindowContainerTransaction();
|
||||||
SplitController.this.onActivityConfigurationChanged(wct, activity);
|
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,
|
final TaskFragmentContainer launchedInTaskFragment = resolveStartActivityIntent(wct,
|
||||||
taskId, intent, launchingActivity);
|
taskId, intent, launchingActivity);
|
||||||
if (launchedInTaskFragment != null) {
|
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
|
// Amend the request to let the WM know that the activity should be placed in
|
||||||
// the dedicated container.
|
// the dedicated container.
|
||||||
options.putBinder(ActivityOptions.KEY_LAUNCH_TASK_FRAGMENT_TOKEN,
|
options.putBinder(ActivityOptions.KEY_LAUNCH_TASK_FRAGMENT_TOKEN,
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ import android.util.Size;
|
|||||||
import android.window.TaskFragmentInfo;
|
import android.window.TaskFragmentInfo;
|
||||||
import android.window.WindowContainerTransaction;
|
import android.window.WindowContainerTransaction;
|
||||||
|
|
||||||
|
import androidx.annotation.GuardedBy;
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
@@ -251,6 +252,7 @@ class TaskFragmentContainer {
|
|||||||
return mInfo;
|
return mInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GuardedBy("mController.mLock")
|
||||||
void setInfo(@NonNull WindowContainerTransaction wct, @NonNull TaskFragmentInfo info) {
|
void setInfo(@NonNull WindowContainerTransaction wct, @NonNull TaskFragmentInfo info) {
|
||||||
if (!mIsFinished && mInfo == null && info.isEmpty()) {
|
if (!mIsFinished && mInfo == null && info.isEmpty()) {
|
||||||
// onTaskFragmentAppeared with empty info. We will remove the TaskFragment if no
|
// onTaskFragmentAppeared with empty info. We will remove the TaskFragment if no
|
||||||
@@ -258,10 +260,12 @@ class TaskFragmentContainer {
|
|||||||
// it is still empty after timeout.
|
// it is still empty after timeout.
|
||||||
if (mPendingAppearedIntent != null || !mPendingAppearedActivities.isEmpty()) {
|
if (mPendingAppearedIntent != null || !mPendingAppearedActivities.isEmpty()) {
|
||||||
mAppearEmptyTimeout = () -> {
|
mAppearEmptyTimeout = () -> {
|
||||||
mAppearEmptyTimeout = null;
|
synchronized (mController.mLock) {
|
||||||
// Call without the pass-in wct when timeout. We need to applyWct directly
|
mAppearEmptyTimeout = null;
|
||||||
// in this case.
|
// Call without the pass-in wct when timeout. We need to applyWct directly
|
||||||
mController.onTaskFragmentAppearEmptyTimeout(this);
|
// in this case.
|
||||||
|
mController.onTaskFragmentAppearEmptyTimeout(this);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
mController.getHandler().postDelayed(mAppearEmptyTimeout, APPEAR_EMPTY_TIMEOUT_MS);
|
mController.getHandler().postDelayed(mAppearEmptyTimeout, APPEAR_EMPTY_TIMEOUT_MS);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -20,7 +20,6 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
|
|||||||
|
|
||||||
import static androidx.window.extensions.embedding.EmbeddingTestUtils.TASK_ID;
|
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.spyOn;
|
||||||
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
|
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.Intent;
|
||||||
import android.content.res.Configuration;
|
import android.content.res.Configuration;
|
||||||
import android.graphics.Point;
|
import android.graphics.Point;
|
||||||
import android.os.Handler;
|
|
||||||
import android.platform.test.annotations.Presubmit;
|
import android.platform.test.annotations.Presubmit;
|
||||||
import android.window.TaskFragmentInfo;
|
import android.window.TaskFragmentInfo;
|
||||||
import android.window.TaskFragmentTransaction;
|
import android.window.TaskFragmentTransaction;
|
||||||
@@ -67,10 +65,7 @@ public class JetpackTaskFragmentOrganizerTest {
|
|||||||
private WindowContainerTransaction mTransaction;
|
private WindowContainerTransaction mTransaction;
|
||||||
@Mock
|
@Mock
|
||||||
private JetpackTaskFragmentOrganizer.TaskFragmentCallback mCallback;
|
private JetpackTaskFragmentOrganizer.TaskFragmentCallback mCallback;
|
||||||
@Mock
|
|
||||||
private SplitController mSplitController;
|
private SplitController mSplitController;
|
||||||
@Mock
|
|
||||||
private Handler mHandler;
|
|
||||||
private JetpackTaskFragmentOrganizer mOrganizer;
|
private JetpackTaskFragmentOrganizer mOrganizer;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
@@ -78,8 +73,9 @@ public class JetpackTaskFragmentOrganizerTest {
|
|||||||
MockitoAnnotations.initMocks(this);
|
MockitoAnnotations.initMocks(this);
|
||||||
mOrganizer = new JetpackTaskFragmentOrganizer(Runnable::run, mCallback);
|
mOrganizer = new JetpackTaskFragmentOrganizer(Runnable::run, mCallback);
|
||||||
mOrganizer.registerOrganizer();
|
mOrganizer.registerOrganizer();
|
||||||
|
mSplitController = new SplitController();
|
||||||
spyOn(mOrganizer);
|
spyOn(mOrganizer);
|
||||||
doReturn(mHandler).when(mSplitController).getHandler();
|
spyOn(mSplitController);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
@@ -127,7 +127,7 @@ public class SplitControllerTest {
|
|||||||
mSplitPresenter = mSplitController.mPresenter;
|
mSplitPresenter = mSplitController.mPresenter;
|
||||||
spyOn(mSplitController);
|
spyOn(mSplitController);
|
||||||
spyOn(mSplitPresenter);
|
spyOn(mSplitPresenter);
|
||||||
doNothing().when(mSplitPresenter).applyTransaction(any());
|
doNothing().when(mSplitPresenter).applyTransaction(any(), anyInt(), anyBoolean());
|
||||||
final Configuration activityConfig = new Configuration();
|
final Configuration activityConfig = new Configuration();
|
||||||
activityConfig.windowConfiguration.setBounds(TASK_BOUNDS);
|
activityConfig.windowConfiguration.setBounds(TASK_BOUNDS);
|
||||||
activityConfig.windowConfiguration.setMaxBounds(TASK_BOUNDS);
|
activityConfig.windowConfiguration.setMaxBounds(TASK_BOUNDS);
|
||||||
@@ -1000,7 +1000,8 @@ public class SplitControllerTest {
|
|||||||
mSplitController.onTransactionReady(transaction);
|
mSplitController.onTransactionReady(transaction);
|
||||||
|
|
||||||
verify(mSplitController).onTaskFragmentAppeared(any(), eq(info));
|
verify(mSplitController).onTaskFragmentAppeared(any(), eq(info));
|
||||||
verify(mSplitPresenter).onTransactionHandled(eq(transaction.getTransactionToken()), any());
|
verify(mSplitPresenter).onTransactionHandled(eq(transaction.getTransactionToken()), any(),
|
||||||
|
anyInt(), anyBoolean());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -1014,7 +1015,8 @@ public class SplitControllerTest {
|
|||||||
mSplitController.onTransactionReady(transaction);
|
mSplitController.onTransactionReady(transaction);
|
||||||
|
|
||||||
verify(mSplitController).onTaskFragmentInfoChanged(any(), eq(info));
|
verify(mSplitController).onTaskFragmentInfoChanged(any(), eq(info));
|
||||||
verify(mSplitPresenter).onTransactionHandled(eq(transaction.getTransactionToken()), any());
|
verify(mSplitPresenter).onTransactionHandled(eq(transaction.getTransactionToken()), any(),
|
||||||
|
anyInt(), anyBoolean());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -1028,7 +1030,8 @@ public class SplitControllerTest {
|
|||||||
mSplitController.onTransactionReady(transaction);
|
mSplitController.onTransactionReady(transaction);
|
||||||
|
|
||||||
verify(mSplitController).onTaskFragmentVanished(any(), eq(info));
|
verify(mSplitController).onTaskFragmentVanished(any(), eq(info));
|
||||||
verify(mSplitPresenter).onTransactionHandled(eq(transaction.getTransactionToken()), any());
|
verify(mSplitPresenter).onTransactionHandled(eq(transaction.getTransactionToken()), any(),
|
||||||
|
anyInt(), anyBoolean());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -1043,7 +1046,8 @@ public class SplitControllerTest {
|
|||||||
|
|
||||||
verify(mSplitController).onTaskFragmentParentInfoChanged(any(), eq(TASK_ID),
|
verify(mSplitController).onTaskFragmentParentInfoChanged(any(), eq(TASK_ID),
|
||||||
eq(taskConfig));
|
eq(taskConfig));
|
||||||
verify(mSplitPresenter).onTransactionHandled(eq(transaction.getTransactionToken()), any());
|
verify(mSplitPresenter).onTransactionHandled(eq(transaction.getTransactionToken()), any(),
|
||||||
|
anyInt(), anyBoolean());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -1062,7 +1066,8 @@ public class SplitControllerTest {
|
|||||||
|
|
||||||
verify(mSplitController).onTaskFragmentError(any(), eq(errorToken), eq(info), eq(opType),
|
verify(mSplitController).onTaskFragmentError(any(), eq(errorToken), eq(info), eq(opType),
|
||||||
eq(exception));
|
eq(exception));
|
||||||
verify(mSplitPresenter).onTransactionHandled(eq(transaction.getTransactionToken()), any());
|
verify(mSplitPresenter).onTransactionHandled(eq(transaction.getTransactionToken()), any(),
|
||||||
|
anyInt(), anyBoolean());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -1078,7 +1083,8 @@ public class SplitControllerTest {
|
|||||||
|
|
||||||
verify(mSplitController).onActivityReparentedToTask(any(), eq(TASK_ID), eq(intent),
|
verify(mSplitController).onActivityReparentedToTask(any(), eq(TASK_ID), eq(intent),
|
||||||
eq(activityToken));
|
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. */
|
/** Creates a mock activity in the organizer process. */
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ import android.util.ArraySet;
|
|||||||
import android.util.Slog;
|
import android.util.Slog;
|
||||||
import android.util.SparseArray;
|
import android.util.SparseArray;
|
||||||
import android.view.RemoteAnimationDefinition;
|
import android.view.RemoteAnimationDefinition;
|
||||||
|
import android.view.WindowManager;
|
||||||
import android.window.ITaskFragmentOrganizer;
|
import android.window.ITaskFragmentOrganizer;
|
||||||
import android.window.ITaskFragmentOrganizerController;
|
import android.window.ITaskFragmentOrganizerController;
|
||||||
import android.window.TaskFragmentInfo;
|
import android.window.TaskFragmentInfo;
|
||||||
@@ -484,16 +485,31 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onTransactionHandled(@NonNull ITaskFragmentOrganizer organizer,
|
public void onTransactionHandled(@NonNull IBinder transactionToken,
|
||||||
@NonNull IBinder transactionToken, @NonNull WindowContainerTransaction wct) {
|
@NonNull WindowContainerTransaction wct,
|
||||||
|
@WindowManager.TransitionType int transitionType, boolean shouldApplyIndependently) {
|
||||||
|
// Keep the calling identity to avoid unsecure change.
|
||||||
synchronized (mGlobalLock) {
|
synchronized (mGlobalLock) {
|
||||||
// Keep the calling identity to avoid unsecure change.
|
applyTransaction(wct, transitionType, shouldApplyIndependently);
|
||||||
mWindowOrganizerController.applyTransaction(wct);
|
final TaskFragmentOrganizerState state = validateAndGetState(
|
||||||
final TaskFragmentOrganizerState state = validateAndGetState(organizer);
|
wct.getTaskFragmentOrganizer());
|
||||||
state.onTransactionFinished(transactionToken);
|
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
|
* 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.
|
* {@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.util.Slog;
|
||||||
import android.view.RemoteAnimationAdapter;
|
import android.view.RemoteAnimationAdapter;
|
||||||
import android.view.SurfaceControl;
|
import android.view.SurfaceControl;
|
||||||
|
import android.view.WindowManager;
|
||||||
import android.window.IDisplayAreaOrganizerController;
|
import android.window.IDisplayAreaOrganizerController;
|
||||||
import android.window.ITaskFragmentOrganizer;
|
import android.window.ITaskFragmentOrganizer;
|
||||||
import android.window.ITaskFragmentOrganizerController;
|
import android.window.ITaskFragmentOrganizerController;
|
||||||
@@ -177,7 +178,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
|
|||||||
if (t == null) {
|
if (t == null) {
|
||||||
throw new IllegalArgumentException("Null transaction passed to applyTransaction");
|
throw new IllegalArgumentException("Null transaction passed to applyTransaction");
|
||||||
}
|
}
|
||||||
enforceTaskPermission("applyTransaction()", t);
|
enforceTaskPermission("applyTransaction()");
|
||||||
final CallerInfo caller = new CallerInfo();
|
final CallerInfo caller = new CallerInfo();
|
||||||
final long ident = Binder.clearCallingIdentity();
|
final long ident = Binder.clearCallingIdentity();
|
||||||
try {
|
try {
|
||||||
@@ -195,7 +196,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
|
|||||||
if (t == null) {
|
if (t == null) {
|
||||||
throw new IllegalArgumentException("Null transaction passed to applySyncTransaction");
|
throw new IllegalArgumentException("Null transaction passed to applySyncTransaction");
|
||||||
}
|
}
|
||||||
enforceTaskPermission("applySyncTransaction()", t);
|
enforceTaskPermission("applySyncTransaction()");
|
||||||
final CallerInfo caller = new CallerInfo();
|
final CallerInfo caller = new CallerInfo();
|
||||||
final long ident = Binder.clearCallingIdentity();
|
final long ident = Binder.clearCallingIdentity();
|
||||||
try {
|
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,
|
private void applyTransaction(@NonNull WindowContainerTransaction t, int syncId,
|
||||||
@Nullable Transition transition, @NonNull CallerInfo caller) {
|
@Nullable Transition transition, @NonNull CallerInfo caller) {
|
||||||
applyTransaction(t, syncId, transition, caller, null /* finishTransition */);
|
applyTransaction(t, syncId, transition, caller, null /* finishTransition */);
|
||||||
@@ -388,12 +470,6 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
|
|||||||
private void applyTransaction(@NonNull WindowContainerTransaction t, int syncId,
|
private void applyTransaction(@NonNull WindowContainerTransaction t, int syncId,
|
||||||
@Nullable Transition transition, @NonNull CallerInfo caller,
|
@Nullable Transition transition, @NonNull CallerInfo caller,
|
||||||
@Nullable Transition finishTransition) {
|
@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;
|
int effects = 0;
|
||||||
ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Apply window transaction, syncId=%d", syncId);
|
ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Apply window transaction, syncId=%d", syncId);
|
||||||
mService.deferWindowLayout();
|
mService.deferWindowLayout();
|
||||||
@@ -1495,25 +1571,24 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
|
|||||||
mService.enforceTaskPermission(func);
|
mService.enforceTaskPermission(func);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void enforceTaskPermission(String func, @Nullable WindowContainerTransaction t) {
|
private boolean isValidTransaction(@NonNull WindowContainerTransaction t) {
|
||||||
if (t == null || t.getTaskFragmentOrganizer() == null) {
|
if (t.getTaskFragmentOrganizer() != null && !mTaskFragmentOrganizerController
|
||||||
enforceTaskPermission(func);
|
.isOrganizerRegistered(t.getTaskFragmentOrganizer())) {
|
||||||
return;
|
// 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;
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
// 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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Makes sure that the transaction only contains operations that are allowed for the
|
* Makes sure that the transaction only contains operations that are allowed for the
|
||||||
* {@link WindowContainerTransaction#getTaskFragmentOrganizer()}.
|
* {@link WindowContainerTransaction#getTaskFragmentOrganizer()}.
|
||||||
*/
|
*/
|
||||||
private void enforceOperationsAllowedForTaskFragmentOrganizer(
|
private void enforceTaskFragmentOrganizerPermission(@NonNull String func,
|
||||||
String func, WindowContainerTransaction t) {
|
@NonNull ITaskFragmentOrganizer organizer, @NonNull WindowContainerTransaction t) {
|
||||||
final ITaskFragmentOrganizer organizer = t.getTaskFragmentOrganizer();
|
|
||||||
|
|
||||||
// Configuration changes
|
// Configuration changes
|
||||||
final Iterator<Map.Entry<IBinder, WindowContainerTransaction.Change>> entries =
|
final Iterator<Map.Entry<IBinder, WindowContainerTransaction.Change>> entries =
|
||||||
t.getChanges().entrySet().iterator();
|
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.app.WindowConfiguration.WINDOWING_MODE_PINNED;
|
||||||
import static android.window.TaskFragmentOrganizer.KEY_ERROR_CALLBACK_OP_TYPE;
|
import static android.window.TaskFragmentOrganizer.KEY_ERROR_CALLBACK_OP_TYPE;
|
||||||
import static android.window.TaskFragmentOrganizer.KEY_ERROR_CALLBACK_THROWABLE;
|
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_ACTIVITY_REPARENTED_TO_TASK;
|
||||||
import static android.window.TaskFragmentTransaction.TYPE_TASK_FRAGMENT_APPEARED;
|
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_ERROR;
|
||||||
@@ -49,8 +50,8 @@ import static org.junit.Assert.assertNotEquals;
|
|||||||
import static org.junit.Assert.assertNotNull;
|
import static org.junit.Assert.assertNotNull;
|
||||||
import static org.junit.Assert.assertNull;
|
import static org.junit.Assert.assertNull;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
import static org.junit.Assert.fail;
|
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
|
import static org.mockito.ArgumentMatchers.anyBoolean;
|
||||||
import static org.mockito.ArgumentMatchers.anyInt;
|
import static org.mockito.ArgumentMatchers.anyInt;
|
||||||
import static org.mockito.ArgumentMatchers.eq;
|
import static org.mockito.ArgumentMatchers.eq;
|
||||||
import static org.mockito.Mockito.clearInvocations;
|
import static org.mockito.Mockito.clearInvocations;
|
||||||
@@ -78,7 +79,6 @@ import android.window.TaskFragmentOrganizerToken;
|
|||||||
import android.window.TaskFragmentTransaction;
|
import android.window.TaskFragmentTransaction;
|
||||||
import android.window.WindowContainerToken;
|
import android.window.WindowContainerToken;
|
||||||
import android.window.WindowContainerTransaction;
|
import android.window.WindowContainerTransaction;
|
||||||
import android.window.WindowContainerTransactionCallback;
|
|
||||||
|
|
||||||
import androidx.test.filters.SmallTest;
|
import androidx.test.filters.SmallTest;
|
||||||
|
|
||||||
@@ -136,6 +136,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
|
|||||||
mTaskFragment =
|
mTaskFragment =
|
||||||
new TaskFragment(mAtm, mFragmentToken, true /* createdByOrganizer */);
|
new TaskFragment(mAtm, mFragmentToken, true /* createdByOrganizer */);
|
||||||
mTransaction = new WindowContainerTransaction();
|
mTransaction = new WindowContainerTransaction();
|
||||||
|
mTransaction.setTaskFragmentOrganizer(mIOrganizer);
|
||||||
mFragmentWindowToken = mTaskFragment.mRemoteToken.toWindowContainerToken();
|
mFragmentWindowToken = mTaskFragment.mRemoteToken.toWindowContainerToken();
|
||||||
mDefinition = new RemoteAnimationDefinition();
|
mDefinition = new RemoteAnimationDefinition();
|
||||||
mErrorToken = new Binder();
|
mErrorToken = new Binder();
|
||||||
@@ -155,11 +156,16 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
|
|||||||
doReturn(new Configuration()).when(mTaskFragmentInfo).getConfiguration();
|
doReturn(new Configuration()).when(mTaskFragmentInfo).getConfiguration();
|
||||||
|
|
||||||
// To prevent it from calling the real server.
|
// 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
|
@Test
|
||||||
public void testCallTaskFragmentCallbackWithoutRegister_throwsException() {
|
public void testCallTaskFragmentCallbackWithoutRegister_throwsException() {
|
||||||
|
mController.unregisterOrganizer(mIOrganizer);
|
||||||
|
|
||||||
doReturn(mTask).when(mTaskFragment).getTask();
|
doReturn(mTask).when(mTaskFragment).getTask();
|
||||||
|
|
||||||
assertThrows(IllegalArgumentException.class, () -> mController
|
assertThrows(IllegalArgumentException.class, () -> mController
|
||||||
@@ -175,8 +181,6 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testOnTaskFragmentAppeared() {
|
public void testOnTaskFragmentAppeared() {
|
||||||
mController.registerOrganizer(mIOrganizer);
|
|
||||||
|
|
||||||
// No-op when the TaskFragment is not attached.
|
// No-op when the TaskFragment is not attached.
|
||||||
mController.onTaskFragmentAppeared(mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment);
|
mController.onTaskFragmentAppeared(mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment);
|
||||||
mController.dispatchPendingEvents();
|
mController.dispatchPendingEvents();
|
||||||
@@ -194,7 +198,6 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testOnTaskFragmentInfoChanged() {
|
public void testOnTaskFragmentInfoChanged() {
|
||||||
mController.registerOrganizer(mIOrganizer);
|
|
||||||
setupMockParent(mTaskFragment, mTask);
|
setupMockParent(mTaskFragment, mTask);
|
||||||
|
|
||||||
// No-op if onTaskFragmentAppeared is not called yet.
|
// No-op if onTaskFragmentAppeared is not called yet.
|
||||||
@@ -233,8 +236,6 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testOnTaskFragmentVanished() {
|
public void testOnTaskFragmentVanished() {
|
||||||
mController.registerOrganizer(mIOrganizer);
|
|
||||||
|
|
||||||
mTaskFragment.mTaskFragmentAppearedSent = true;
|
mTaskFragment.mTaskFragmentAppearedSent = true;
|
||||||
mController.onTaskFragmentVanished(mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment);
|
mController.onTaskFragmentVanished(mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment);
|
||||||
mController.dispatchPendingEvents();
|
mController.dispatchPendingEvents();
|
||||||
@@ -244,7 +245,6 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testOnTaskFragmentVanished_clearUpRemaining() {
|
public void testOnTaskFragmentVanished_clearUpRemaining() {
|
||||||
mController.registerOrganizer(mIOrganizer);
|
|
||||||
setupMockParent(mTaskFragment, mTask);
|
setupMockParent(mTaskFragment, mTask);
|
||||||
|
|
||||||
// Not trigger onTaskFragmentAppeared.
|
// Not trigger onTaskFragmentAppeared.
|
||||||
@@ -270,7 +270,6 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testOnTaskFragmentParentInfoChanged() {
|
public void testOnTaskFragmentParentInfoChanged() {
|
||||||
mController.registerOrganizer(mIOrganizer);
|
|
||||||
setupMockParent(mTaskFragment, mTask);
|
setupMockParent(mTaskFragment, mTask);
|
||||||
mTask.getConfiguration().smallestScreenWidthDp = 10;
|
mTask.getConfiguration().smallestScreenWidthDp = 10;
|
||||||
|
|
||||||
@@ -317,7 +316,6 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
|
|||||||
public void testOnTaskFragmentError() {
|
public void testOnTaskFragmentError() {
|
||||||
final Throwable exception = new IllegalArgumentException("Test exception");
|
final Throwable exception = new IllegalArgumentException("Test exception");
|
||||||
|
|
||||||
mController.registerOrganizer(mIOrganizer);
|
|
||||||
mController.onTaskFragmentError(mTaskFragment.getTaskFragmentOrganizer(),
|
mController.onTaskFragmentError(mTaskFragment.getTaskFragmentOrganizer(),
|
||||||
mErrorToken, null /* taskFragment */, HIERARCHY_OP_TYPE_SET_ADJACENT_ROOTS,
|
mErrorToken, null /* taskFragment */, HIERARCHY_OP_TYPE_SET_ADJACENT_ROOTS,
|
||||||
exception);
|
exception);
|
||||||
@@ -332,7 +330,6 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
|
|||||||
// Make sure the activity pid/uid is the same as the organizer caller.
|
// Make sure the activity pid/uid is the same as the organizer caller.
|
||||||
final int pid = Binder.getCallingPid();
|
final int pid = Binder.getCallingPid();
|
||||||
final int uid = Binder.getCallingUid();
|
final int uid = Binder.getCallingUid();
|
||||||
mController.registerOrganizer(mIOrganizer);
|
|
||||||
final ActivityRecord activity = createActivityRecord(mDisplayContent);
|
final ActivityRecord activity = createActivityRecord(mDisplayContent);
|
||||||
final Task task = activity.getTask();
|
final Task task = activity.getTask();
|
||||||
activity.info.applicationInfo.uid = uid;
|
activity.info.applicationInfo.uid = uid;
|
||||||
@@ -375,8 +372,6 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
|
|||||||
mTaskFragment.setTaskFragmentOrganizer(mOrganizer.getOrganizerToken(), uid,
|
mTaskFragment.setTaskFragmentOrganizer(mOrganizer.getOrganizerToken(), uid,
|
||||||
DEFAULT_TASK_FRAGMENT_ORGANIZER_PROCESS_NAME);
|
DEFAULT_TASK_FRAGMENT_ORGANIZER_PROCESS_NAME);
|
||||||
mWindowOrganizerController.mLaunchTaskFragments.put(mFragmentToken, mTaskFragment);
|
mWindowOrganizerController.mLaunchTaskFragments.put(mFragmentToken, mTaskFragment);
|
||||||
mController.registerOrganizer(mIOrganizer);
|
|
||||||
mOrganizer.applyTransaction(mTransaction);
|
|
||||||
final Task task = createTask(mDisplayContent);
|
final Task task = createTask(mDisplayContent);
|
||||||
task.addChild(mTaskFragment, POSITION_TOP);
|
task.addChild(mTaskFragment, POSITION_TOP);
|
||||||
final ActivityRecord activity = createActivityRecord(task);
|
final ActivityRecord activity = createActivityRecord(task);
|
||||||
@@ -404,7 +399,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
|
|||||||
assertEquals(activity.intent, change.getActivityIntent());
|
assertEquals(activity.intent, change.getActivityIntent());
|
||||||
assertNotEquals(activity.token, change.getActivityToken());
|
assertNotEquals(activity.token, change.getActivityToken());
|
||||||
mTransaction.reparentActivityToTaskFragment(mFragmentToken, change.getActivityToken());
|
mTransaction.reparentActivityToTaskFragment(mFragmentToken, change.getActivityToken());
|
||||||
mWindowOrganizerController.applyTransaction(mTransaction);
|
assertApplyTransactionAllowed(mTransaction);
|
||||||
|
|
||||||
assertEquals(mTaskFragment, activity.getTaskFragment());
|
assertEquals(mTaskFragment, activity.getTaskFragment());
|
||||||
// The temporary token can only be used once.
|
// The temporary token can only be used once.
|
||||||
@@ -414,7 +409,6 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRegisterRemoteAnimations() {
|
public void testRegisterRemoteAnimations() {
|
||||||
mController.registerOrganizer(mIOrganizer);
|
|
||||||
mController.registerRemoteAnimations(mIOrganizer, TASK_ID, mDefinition);
|
mController.registerRemoteAnimations(mIOrganizer, TASK_ID, mDefinition);
|
||||||
|
|
||||||
assertEquals(mDefinition, mController.getRemoteAnimationDefinition(mIOrganizer, TASK_ID));
|
assertEquals(mDefinition, mController.getRemoteAnimationDefinition(mIOrganizer, TASK_ID));
|
||||||
@@ -425,23 +419,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testWindowContainerTransaction_setTaskFragmentOrganizer() {
|
public void testApplyTransaction_enforceConfigurationChangeOnOrganizedTaskFragment() {
|
||||||
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);
|
|
||||||
|
|
||||||
// Throw exception if the transaction is trying to change a window that is not organized by
|
// Throw exception if the transaction is trying to change a window that is not organized by
|
||||||
// the organizer.
|
// the organizer.
|
||||||
mTransaction.setBounds(mFragmentWindowToken, new Rect(0, 0, 100, 100));
|
mTransaction.setBounds(mFragmentWindowToken, new Rect(0, 0, 100, 100));
|
||||||
@@ -457,10 +435,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
|
|||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testApplyTransaction_enforceHierarchyChange_deleteTaskFragment()
|
public void testApplyTransaction_enforceHierarchyChange_deleteTaskFragment() {
|
||||||
throws RemoteException {
|
|
||||||
mController.registerOrganizer(mIOrganizer);
|
|
||||||
mOrganizer.applyTransaction(mTransaction);
|
|
||||||
doReturn(true).when(mTaskFragment).isAttached();
|
doReturn(true).when(mTaskFragment).isAttached();
|
||||||
|
|
||||||
// Throw exception if the transaction is trying to change a window that is not organized by
|
// 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
|
@Test
|
||||||
public void testApplyTransaction_enforceHierarchyChange_setAdjacentRoots()
|
public void testApplyTransaction_enforceHierarchyChange_setAdjacentRoots() {
|
||||||
throws RemoteException {
|
|
||||||
mAtm.mTaskFragmentOrganizerController.registerOrganizer(mIOrganizer);
|
|
||||||
final TaskFragment taskFragment2 =
|
final TaskFragment taskFragment2 =
|
||||||
new TaskFragment(mAtm, new Binder(), true /* createdByOrganizer */);
|
new TaskFragment(mAtm, new Binder(), true /* createdByOrganizer */);
|
||||||
final WindowContainerToken token2 = taskFragment2.mRemoteToken.toWindowContainerToken();
|
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
|
// Throw exception if the transaction is trying to change a window that is not organized by
|
||||||
// the organizer.
|
// the organizer.
|
||||||
@@ -513,9 +485,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testApplyTransaction_enforceHierarchyChange_createTaskFragment()
|
public void testApplyTransaction_enforceHierarchyChange_createTaskFragment() {
|
||||||
throws RemoteException {
|
|
||||||
mController.registerOrganizer(mIOrganizer);
|
|
||||||
final ActivityRecord ownerActivity = createActivityRecord(mDisplayContent);
|
final ActivityRecord ownerActivity = createActivityRecord(mDisplayContent);
|
||||||
final IBinder fragmentToken = new Binder();
|
final IBinder fragmentToken = new Binder();
|
||||||
|
|
||||||
@@ -526,11 +496,10 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
|
|||||||
mTransaction.reparentActivityToTaskFragment(mFragmentToken, mock(IBinder.class));
|
mTransaction.reparentActivityToTaskFragment(mFragmentToken, mock(IBinder.class));
|
||||||
mTransaction.setAdjacentTaskFragments(mFragmentToken, mock(IBinder.class),
|
mTransaction.setAdjacentTaskFragments(mFragmentToken, mock(IBinder.class),
|
||||||
null /* options */);
|
null /* options */);
|
||||||
mAtm.getWindowOrganizerController().applyTransaction(mTransaction);
|
assertApplyTransactionAllowed(mTransaction);
|
||||||
|
|
||||||
// Successfully created a TaskFragment.
|
// Successfully created a TaskFragment.
|
||||||
final TaskFragment taskFragment = mAtm.mWindowOrganizerController
|
final TaskFragment taskFragment = mWindowOrganizerController.getTaskFragment(fragmentToken);
|
||||||
.getTaskFragment(fragmentToken);
|
|
||||||
assertNotNull(taskFragment);
|
assertNotNull(taskFragment);
|
||||||
assertEquals(ownerActivity.getTask(), taskFragment.getTask());
|
assertEquals(ownerActivity.getTask(), taskFragment.getTask());
|
||||||
}
|
}
|
||||||
@@ -539,7 +508,6 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
|
|||||||
public void testApplyTransaction_enforceTaskFragmentOrganized_startActivityInTaskFragment() {
|
public void testApplyTransaction_enforceTaskFragmentOrganized_startActivityInTaskFragment() {
|
||||||
final Task task = createTask(mDisplayContent);
|
final Task task = createTask(mDisplayContent);
|
||||||
final ActivityRecord ownerActivity = createActivityRecord(task);
|
final ActivityRecord ownerActivity = createActivityRecord(task);
|
||||||
mController.registerOrganizer(mIOrganizer);
|
|
||||||
mTaskFragment = new TaskFragmentBuilder(mAtm)
|
mTaskFragment = new TaskFragmentBuilder(mAtm)
|
||||||
.setParentTask(task)
|
.setParentTask(task)
|
||||||
.setFragmentToken(mFragmentToken)
|
.setFragmentToken(mFragmentToken)
|
||||||
@@ -562,7 +530,6 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
|
|||||||
public void testApplyTransaction_enforceTaskFragmentOrganized_reparentActivityInTaskFragment() {
|
public void testApplyTransaction_enforceTaskFragmentOrganized_reparentActivityInTaskFragment() {
|
||||||
final Task task = createTask(mDisplayContent);
|
final Task task = createTask(mDisplayContent);
|
||||||
final ActivityRecord activity = createActivityRecord(task);
|
final ActivityRecord activity = createActivityRecord(task);
|
||||||
mController.registerOrganizer(mIOrganizer);
|
|
||||||
mTaskFragment = new TaskFragmentBuilder(mAtm)
|
mTaskFragment = new TaskFragmentBuilder(mAtm)
|
||||||
.setParentTask(task)
|
.setParentTask(task)
|
||||||
.setFragmentToken(mFragmentToken)
|
.setFragmentToken(mFragmentToken)
|
||||||
@@ -583,7 +550,6 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
|
|||||||
@Test
|
@Test
|
||||||
public void testApplyTransaction_enforceTaskFragmentOrganized_setAdjacentTaskFragments() {
|
public void testApplyTransaction_enforceTaskFragmentOrganized_setAdjacentTaskFragments() {
|
||||||
final Task task = createTask(mDisplayContent);
|
final Task task = createTask(mDisplayContent);
|
||||||
mController.registerOrganizer(mIOrganizer);
|
|
||||||
mTaskFragment = new TaskFragmentBuilder(mAtm)
|
mTaskFragment = new TaskFragmentBuilder(mAtm)
|
||||||
.setParentTask(task)
|
.setParentTask(task)
|
||||||
.setFragmentToken(mFragmentToken)
|
.setFragmentToken(mFragmentToken)
|
||||||
@@ -623,7 +589,6 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
|
|||||||
@Test
|
@Test
|
||||||
public void testApplyTransaction_enforceTaskFragmentOrganized_requestFocusOnTaskFragment() {
|
public void testApplyTransaction_enforceTaskFragmentOrganized_requestFocusOnTaskFragment() {
|
||||||
final Task task = createTask(mDisplayContent);
|
final Task task = createTask(mDisplayContent);
|
||||||
mController.registerOrganizer(mIOrganizer);
|
|
||||||
mTaskFragment = new TaskFragmentBuilder(mAtm)
|
mTaskFragment = new TaskFragmentBuilder(mAtm)
|
||||||
.setParentTask(task)
|
.setParentTask(task)
|
||||||
.setFragmentToken(mFragmentToken)
|
.setFragmentToken(mFragmentToken)
|
||||||
@@ -642,44 +607,38 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testApplyTransaction_createTaskFragment_failForDifferentUid()
|
public void testApplyTransaction_createTaskFragment_failForDifferentUid() {
|
||||||
throws RemoteException {
|
|
||||||
mController.registerOrganizer(mIOrganizer);
|
|
||||||
final ActivityRecord activity = createActivityRecord(mDisplayContent);
|
final ActivityRecord activity = createActivityRecord(mDisplayContent);
|
||||||
final int uid = Binder.getCallingUid();
|
final int uid = Binder.getCallingUid();
|
||||||
final IBinder fragmentToken = new Binder();
|
final IBinder fragmentToken = new Binder();
|
||||||
final TaskFragmentCreationParams params = new TaskFragmentCreationParams.Builder(
|
final TaskFragmentCreationParams params = new TaskFragmentCreationParams.Builder(
|
||||||
mOrganizerToken, fragmentToken, activity.token).build();
|
mOrganizerToken, fragmentToken, activity.token).build();
|
||||||
mOrganizer.applyTransaction(mTransaction);
|
|
||||||
mTransaction.createTaskFragment(params);
|
mTransaction.createTaskFragment(params);
|
||||||
|
|
||||||
// Fail to create TaskFragment when the task uid is different from caller.
|
// Fail to create TaskFragment when the task uid is different from caller.
|
||||||
activity.info.applicationInfo.uid = uid;
|
activity.info.applicationInfo.uid = uid;
|
||||||
activity.getTask().effectiveUid = uid + 1;
|
activity.getTask().effectiveUid = uid + 1;
|
||||||
mWindowOrganizerController.applyTransaction(mTransaction);
|
assertApplyTransactionAllowed(mTransaction);
|
||||||
|
|
||||||
assertNull(mWindowOrganizerController.getTaskFragment(fragmentToken));
|
assertNull(mWindowOrganizerController.getTaskFragment(fragmentToken));
|
||||||
|
|
||||||
// Fail to create TaskFragment when the task uid is different from owner activity.
|
// Fail to create TaskFragment when the task uid is different from owner activity.
|
||||||
activity.info.applicationInfo.uid = uid + 1;
|
activity.info.applicationInfo.uid = uid + 1;
|
||||||
activity.getTask().effectiveUid = uid;
|
activity.getTask().effectiveUid = uid;
|
||||||
mWindowOrganizerController.applyTransaction(mTransaction);
|
assertApplyTransactionAllowed(mTransaction);
|
||||||
|
|
||||||
assertNull(mWindowOrganizerController.getTaskFragment(fragmentToken));
|
assertNull(mWindowOrganizerController.getTaskFragment(fragmentToken));
|
||||||
|
|
||||||
// Successfully created a TaskFragment for same uid.
|
// Successfully created a TaskFragment for same uid.
|
||||||
activity.info.applicationInfo.uid = uid;
|
activity.info.applicationInfo.uid = uid;
|
||||||
activity.getTask().effectiveUid = uid;
|
activity.getTask().effectiveUid = uid;
|
||||||
mWindowOrganizerController.applyTransaction(mTransaction);
|
assertApplyTransactionAllowed(mTransaction);
|
||||||
|
|
||||||
assertNotNull(mWindowOrganizerController.getTaskFragment(fragmentToken));
|
assertNotNull(mWindowOrganizerController.getTaskFragment(fragmentToken));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testApplyTransaction_enforceHierarchyChange_reparentChildren()
|
public void testApplyTransaction_enforceHierarchyChange_reparentChildren() {
|
||||||
throws RemoteException {
|
|
||||||
mOrganizer.applyTransaction(mTransaction);
|
|
||||||
mController.registerOrganizer(mIOrganizer);
|
|
||||||
doReturn(true).when(mTaskFragment).isAttached();
|
doReturn(true).when(mTaskFragment).isAttached();
|
||||||
|
|
||||||
// Throw exception if the transaction is trying to change a window that is not organized by
|
// 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
|
@Test
|
||||||
public void testApplyTransaction_reparentActivityToTaskFragment_triggerLifecycleUpdate()
|
public void testApplyTransaction_reparentActivityToTaskFragment_triggerLifecycleUpdate() {
|
||||||
throws RemoteException {
|
|
||||||
final Task task = createTask(mDisplayContent);
|
final Task task = createTask(mDisplayContent);
|
||||||
final ActivityRecord activity = createActivityRecord(task);
|
final ActivityRecord activity = createActivityRecord(task);
|
||||||
// Skip manipulate the SurfaceControl.
|
// Skip manipulate the SurfaceControl.
|
||||||
doNothing().when(activity).setDropInputMode(anyInt());
|
doNothing().when(activity).setDropInputMode(anyInt());
|
||||||
mOrganizer.applyTransaction(mTransaction);
|
mOrganizer.applyTransaction(mTransaction);
|
||||||
mController.registerOrganizer(mIOrganizer);
|
|
||||||
mTaskFragment = new TaskFragmentBuilder(mAtm)
|
mTaskFragment = new TaskFragmentBuilder(mAtm)
|
||||||
.setParentTask(task)
|
.setParentTask(task)
|
||||||
.setFragmentToken(mFragmentToken)
|
.setFragmentToken(mFragmentToken)
|
||||||
@@ -717,15 +674,13 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
|
|||||||
doReturn(EMBEDDING_ALLOWED).when(mTaskFragment).isAllowedToEmbedActivity(activity);
|
doReturn(EMBEDDING_ALLOWED).when(mTaskFragment).isAllowedToEmbedActivity(activity);
|
||||||
clearInvocations(mAtm.mRootWindowContainer);
|
clearInvocations(mAtm.mRootWindowContainer);
|
||||||
|
|
||||||
mAtm.getWindowOrganizerController().applyTransaction(mTransaction);
|
assertApplyTransactionAllowed(mTransaction);
|
||||||
|
|
||||||
verify(mAtm.mRootWindowContainer).resumeFocusedTasksTopActivities();
|
verify(mAtm.mRootWindowContainer).resumeFocusedTasksTopActivities();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testApplyTransaction_requestFocusOnTaskFragment() {
|
public void testApplyTransaction_requestFocusOnTaskFragment() {
|
||||||
mOrganizer.applyTransaction(mTransaction);
|
|
||||||
mController.registerOrganizer(mIOrganizer);
|
|
||||||
final Task task = createTask(mDisplayContent);
|
final Task task = createTask(mDisplayContent);
|
||||||
final IBinder token0 = new Binder();
|
final IBinder token0 = new Binder();
|
||||||
final TaskFragment tf0 = new TaskFragmentBuilder(mAtm)
|
final TaskFragment tf0 = new TaskFragmentBuilder(mAtm)
|
||||||
@@ -750,7 +705,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
|
|||||||
final ActivityRecord activityInOtherTask = createActivityRecord(mDefaultDisplay);
|
final ActivityRecord activityInOtherTask = createActivityRecord(mDefaultDisplay);
|
||||||
mDisplayContent.setFocusedApp(activityInOtherTask);
|
mDisplayContent.setFocusedApp(activityInOtherTask);
|
||||||
mTransaction.requestFocusOnTaskFragment(token0);
|
mTransaction.requestFocusOnTaskFragment(token0);
|
||||||
mWindowOrganizerController.applyTransaction(mTransaction);
|
assertApplyTransactionAllowed(mTransaction);
|
||||||
|
|
||||||
assertEquals(activityInOtherTask, mDisplayContent.mFocusedApp);
|
assertEquals(activityInOtherTask, mDisplayContent.mFocusedApp);
|
||||||
|
|
||||||
@@ -758,7 +713,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
|
|||||||
activity0.setState(ActivityRecord.State.PAUSED, "test");
|
activity0.setState(ActivityRecord.State.PAUSED, "test");
|
||||||
activity1.setState(ActivityRecord.State.RESUMED, "test");
|
activity1.setState(ActivityRecord.State.RESUMED, "test");
|
||||||
mDisplayContent.setFocusedApp(activity1);
|
mDisplayContent.setFocusedApp(activity1);
|
||||||
mWindowOrganizerController.applyTransaction(mTransaction);
|
assertApplyTransactionAllowed(mTransaction);
|
||||||
|
|
||||||
assertEquals(activity1, mDisplayContent.mFocusedApp);
|
assertEquals(activity1, mDisplayContent.mFocusedApp);
|
||||||
|
|
||||||
@@ -766,28 +721,29 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
|
|||||||
// has a resumed activity.
|
// has a resumed activity.
|
||||||
activity0.setState(ActivityRecord.State.RESUMED, "test");
|
activity0.setState(ActivityRecord.State.RESUMED, "test");
|
||||||
mDisplayContent.setFocusedApp(activity1);
|
mDisplayContent.setFocusedApp(activity1);
|
||||||
mWindowOrganizerController.applyTransaction(mTransaction);
|
assertApplyTransactionAllowed(mTransaction);
|
||||||
|
|
||||||
assertEquals(activity0, mDisplayContent.mFocusedApp);
|
assertEquals(activity0, mDisplayContent.mFocusedApp);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testApplyTransaction_skipTransactionForUnregisterOrganizer() {
|
public void testApplyTransaction_skipTransactionForUnregisterOrganizer() {
|
||||||
|
mController.unregisterOrganizer(mIOrganizer);
|
||||||
final ActivityRecord ownerActivity = createActivityRecord(mDisplayContent);
|
final ActivityRecord ownerActivity = createActivityRecord(mDisplayContent);
|
||||||
final IBinder fragmentToken = new Binder();
|
final IBinder fragmentToken = new Binder();
|
||||||
|
|
||||||
// Allow organizer to create TaskFragment and start/reparent activity to TaskFragment.
|
// Allow organizer to create TaskFragment and start/reparent activity to TaskFragment.
|
||||||
createTaskFragmentFromOrganizer(mTransaction, ownerActivity, fragmentToken);
|
createTaskFragmentFromOrganizer(mTransaction, ownerActivity, fragmentToken);
|
||||||
mAtm.mWindowOrganizerController.applyTransaction(mTransaction);
|
assertApplyTransactionAllowed(mTransaction);
|
||||||
|
|
||||||
// Nothing should happen as the organizer is not registered.
|
// Nothing should happen as the organizer is not registered.
|
||||||
assertNull(mAtm.mWindowOrganizerController.getTaskFragment(fragmentToken));
|
assertNull(mWindowOrganizerController.getTaskFragment(fragmentToken));
|
||||||
|
|
||||||
mController.registerOrganizer(mIOrganizer);
|
mController.registerOrganizer(mIOrganizer);
|
||||||
mAtm.mWindowOrganizerController.applyTransaction(mTransaction);
|
assertApplyTransactionAllowed(mTransaction);
|
||||||
|
|
||||||
// Successfully created when the organizer is registered.
|
// Successfully created when the organizer is registered.
|
||||||
assertNotNull(mAtm.mWindowOrganizerController.getTaskFragment(fragmentToken));
|
assertNotNull(mWindowOrganizerController.getTaskFragment(fragmentToken));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -799,13 +755,13 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
|
|||||||
|
|
||||||
// Not allow to start activity in a TaskFragment that is in a PIP Task.
|
// Not allow to start activity in a TaskFragment that is in a PIP Task.
|
||||||
mTransaction.startActivityInTaskFragment(
|
mTransaction.startActivityInTaskFragment(
|
||||||
mFragmentToken, activity.token, new Intent(), null /* activityOptions */)
|
mFragmentToken, activity.token, new Intent(), null /* activityOptions */)
|
||||||
.setErrorCallbackToken(mErrorToken);
|
.setErrorCallbackToken(mErrorToken);
|
||||||
mWindowOrganizerController.applyTransaction(mTransaction);
|
assertApplyTransactionAllowed(mTransaction);
|
||||||
|
|
||||||
verify(mAtm.getActivityStartController(), never()).startActivityInTaskFragment(any(), any(),
|
verify(mAtm.getActivityStartController(), never()).startActivityInTaskFragment(any(), any(),
|
||||||
any(), any(), anyInt(), anyInt(), any());
|
any(), any(), anyInt(), anyInt(), any());
|
||||||
verify(mAtm.mWindowOrganizerController).sendTaskFragmentOperationFailure(eq(mIOrganizer),
|
verify(mWindowOrganizerController).sendTaskFragmentOperationFailure(eq(mIOrganizer),
|
||||||
eq(mErrorToken), eq(mTaskFragment),
|
eq(mErrorToken), eq(mTaskFragment),
|
||||||
eq(HIERARCHY_OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT),
|
eq(HIERARCHY_OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT),
|
||||||
any(IllegalArgumentException.class));
|
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.
|
// Not allow to reparent activity to a TaskFragment that is in a PIP Task.
|
||||||
mTransaction.reparentActivityToTaskFragment(mFragmentToken, activity.token)
|
mTransaction.reparentActivityToTaskFragment(mFragmentToken, activity.token)
|
||||||
.setErrorCallbackToken(mErrorToken);
|
.setErrorCallbackToken(mErrorToken);
|
||||||
mWindowOrganizerController.applyTransaction(mTransaction);
|
assertApplyTransactionAllowed(mTransaction);
|
||||||
|
|
||||||
verify(mWindowOrganizerController).sendTaskFragmentOperationFailure(eq(mIOrganizer),
|
verify(mWindowOrganizerController).sendTaskFragmentOperationFailure(eq(mIOrganizer),
|
||||||
eq(mErrorToken), eq(mTaskFragment),
|
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.
|
// Not allow to set adjacent on a TaskFragment that is in a PIP Task.
|
||||||
mTransaction.setAdjacentTaskFragments(mFragmentToken, null /* fragmentToken2 */,
|
mTransaction.setAdjacentTaskFragments(mFragmentToken, null /* fragmentToken2 */,
|
||||||
null /* options */)
|
null /* options */)
|
||||||
.setErrorCallbackToken(mErrorToken);
|
.setErrorCallbackToken(mErrorToken);
|
||||||
mWindowOrganizerController.applyTransaction(mTransaction);
|
assertApplyTransactionAllowed(mTransaction);
|
||||||
|
|
||||||
verify(mWindowOrganizerController).sendTaskFragmentOperationFailure(eq(mIOrganizer),
|
verify(mWindowOrganizerController).sendTaskFragmentOperationFailure(eq(mIOrganizer),
|
||||||
eq(mErrorToken), eq(mTaskFragment),
|
eq(mErrorToken), eq(mTaskFragment),
|
||||||
@@ -849,7 +805,6 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testTaskFragmentInPip_createTaskFragment() {
|
public void testTaskFragmentInPip_createTaskFragment() {
|
||||||
mController.registerOrganizer(mIOrganizer);
|
|
||||||
final Task pipTask = createTask(mDisplayContent, WINDOWING_MODE_PINNED,
|
final Task pipTask = createTask(mDisplayContent, WINDOWING_MODE_PINNED,
|
||||||
ACTIVITY_TYPE_STANDARD);
|
ACTIVITY_TYPE_STANDARD);
|
||||||
final ActivityRecord activity = createActivityRecord(pipTask);
|
final ActivityRecord activity = createActivityRecord(pipTask);
|
||||||
@@ -859,7 +814,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
|
|||||||
// Not allow to create TaskFragment in a PIP Task.
|
// Not allow to create TaskFragment in a PIP Task.
|
||||||
createTaskFragmentFromOrganizer(mTransaction, activity, fragmentToken);
|
createTaskFragmentFromOrganizer(mTransaction, activity, fragmentToken);
|
||||||
mTransaction.setErrorCallbackToken(mErrorToken);
|
mTransaction.setErrorCallbackToken(mErrorToken);
|
||||||
mWindowOrganizerController.applyTransaction(mTransaction);
|
assertApplyTransactionAllowed(mTransaction);
|
||||||
|
|
||||||
verify(mWindowOrganizerController).sendTaskFragmentOperationFailure(eq(mIOrganizer),
|
verify(mWindowOrganizerController).sendTaskFragmentOperationFailure(eq(mIOrganizer),
|
||||||
eq(mErrorToken), eq(null), eq(HIERARCHY_OP_TYPE_CREATE_TASK_FRAGMENT),
|
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.
|
// Not allow to delete a TaskFragment that is in a PIP Task.
|
||||||
mTransaction.deleteTaskFragment(mFragmentWindowToken)
|
mTransaction.deleteTaskFragment(mFragmentWindowToken)
|
||||||
.setErrorCallbackToken(mErrorToken);
|
.setErrorCallbackToken(mErrorToken);
|
||||||
mWindowOrganizerController.applyTransaction(mTransaction);
|
assertApplyTransactionAllowed(mTransaction);
|
||||||
|
|
||||||
verify(mWindowOrganizerController).sendTaskFragmentOperationFailure(eq(mIOrganizer),
|
verify(mWindowOrganizerController).sendTaskFragmentOperationFailure(eq(mIOrganizer),
|
||||||
eq(mErrorToken), eq(mTaskFragment), eq(HIERARCHY_OP_TYPE_DELETE_TASK_FRAGMENT),
|
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.
|
// Allow organizer to delete empty TaskFragment for cleanup.
|
||||||
final Task task = mTaskFragment.getTask();
|
final Task task = mTaskFragment.getTask();
|
||||||
mTaskFragment.removeChild(mTaskFragment.getTopMostActivity());
|
mTaskFragment.removeChild(mTaskFragment.getTopMostActivity());
|
||||||
mWindowOrganizerController.applyTransaction(mTransaction);
|
assertApplyTransactionAllowed(mTransaction);
|
||||||
|
|
||||||
assertNull(mWindowOrganizerController.getTaskFragment(mFragmentToken));
|
assertNull(mWindowOrganizerController.getTaskFragment(mFragmentToken));
|
||||||
assertNull(task.getTopChild());
|
assertNull(task.getTopChild());
|
||||||
@@ -916,7 +871,6 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
|
|||||||
doReturn(false).when(task).shouldBeVisible(any());
|
doReturn(false).when(task).shouldBeVisible(any());
|
||||||
|
|
||||||
// Sending events
|
// Sending events
|
||||||
mController.registerOrganizer(mIOrganizer);
|
|
||||||
taskFragment.mTaskFragmentAppearedSent = true;
|
taskFragment.mTaskFragmentAppearedSent = true;
|
||||||
mController.onTaskFragmentInfoChanged(mIOrganizer, taskFragment);
|
mController.onTaskFragmentInfoChanged(mIOrganizer, taskFragment);
|
||||||
mController.dispatchPendingEvents();
|
mController.dispatchPendingEvents();
|
||||||
@@ -942,7 +896,6 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
|
|||||||
taskFragment.setResumedActivity(null, "test");
|
taskFragment.setResumedActivity(null, "test");
|
||||||
|
|
||||||
// Sending events
|
// Sending events
|
||||||
mController.registerOrganizer(mIOrganizer);
|
|
||||||
taskFragment.mTaskFragmentAppearedSent = true;
|
taskFragment.mTaskFragmentAppearedSent = true;
|
||||||
mController.onTaskFragmentInfoChanged(mIOrganizer, taskFragment);
|
mController.onTaskFragmentInfoChanged(mIOrganizer, taskFragment);
|
||||||
mController.dispatchPendingEvents();
|
mController.dispatchPendingEvents();
|
||||||
@@ -977,7 +930,6 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
|
|||||||
assertTrue(parentTask.shouldBeVisible(null));
|
assertTrue(parentTask.shouldBeVisible(null));
|
||||||
|
|
||||||
// Dispatch pending info changed event from creating the activity
|
// Dispatch pending info changed event from creating the activity
|
||||||
mController.registerOrganizer(mIOrganizer);
|
|
||||||
taskFragment.mTaskFragmentAppearedSent = true;
|
taskFragment.mTaskFragmentAppearedSent = true;
|
||||||
mController.onTaskFragmentInfoChanged(mIOrganizer, taskFragment);
|
mController.onTaskFragmentInfoChanged(mIOrganizer, taskFragment);
|
||||||
mController.dispatchPendingEvents();
|
mController.dispatchPendingEvents();
|
||||||
@@ -1013,7 +965,6 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
|
|||||||
assertTrue(task.shouldBeVisible(null));
|
assertTrue(task.shouldBeVisible(null));
|
||||||
|
|
||||||
// Dispatch pending info changed event from creating the activity
|
// Dispatch pending info changed event from creating the activity
|
||||||
mController.registerOrganizer(mIOrganizer);
|
|
||||||
taskFragment.mTaskFragmentAppearedSent = true;
|
taskFragment.mTaskFragmentAppearedSent = true;
|
||||||
mController.onTaskFragmentInfoChanged(mIOrganizer, taskFragment);
|
mController.onTaskFragmentInfoChanged(mIOrganizer, taskFragment);
|
||||||
mController.dispatchPendingEvents();
|
mController.dispatchPendingEvents();
|
||||||
@@ -1039,13 +990,11 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
|
|||||||
* {@link WindowOrganizerController}.
|
* {@link WindowOrganizerController}.
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testTaskFragmentRemoved_cleanUpEmbeddedTaskFragment()
|
public void testTaskFragmentRemoved_cleanUpEmbeddedTaskFragment() {
|
||||||
throws RemoteException {
|
|
||||||
mController.registerOrganizer(mIOrganizer);
|
|
||||||
final ActivityRecord ownerActivity = createActivityRecord(mDisplayContent);
|
final ActivityRecord ownerActivity = createActivityRecord(mDisplayContent);
|
||||||
final IBinder fragmentToken = new Binder();
|
final IBinder fragmentToken = new Binder();
|
||||||
createTaskFragmentFromOrganizer(mTransaction, ownerActivity, fragmentToken);
|
createTaskFragmentFromOrganizer(mTransaction, ownerActivity, fragmentToken);
|
||||||
mAtm.getWindowOrganizerController().applyTransaction(mTransaction);
|
assertApplyTransactionAllowed(mTransaction);
|
||||||
final TaskFragment taskFragment = mWindowOrganizerController.getTaskFragment(fragmentToken);
|
final TaskFragment taskFragment = mWindowOrganizerController.getTaskFragment(fragmentToken);
|
||||||
|
|
||||||
assertNotNull(taskFragment);
|
assertNotNull(taskFragment);
|
||||||
@@ -1060,9 +1009,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
|
|||||||
* its parent bounds.
|
* its parent bounds.
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testUntrustedEmbedding_configChange() throws RemoteException {
|
public void testUntrustedEmbedding_configChange() {
|
||||||
mController.registerOrganizer(mIOrganizer);
|
|
||||||
mOrganizer.applyTransaction(mTransaction);
|
|
||||||
mTaskFragment.setTaskFragmentOrganizer(mOrganizerToken, 10 /* uid */,
|
mTaskFragment.setTaskFragmentOrganizer(mOrganizerToken, 10 /* uid */,
|
||||||
"Test:TaskFragmentOrganizer" /* processName */);
|
"Test:TaskFragmentOrganizer" /* processName */);
|
||||||
doReturn(false).when(mTaskFragment).isAllowedToBeEmbeddedInTrustedMode();
|
doReturn(false).when(mTaskFragment).isAllowedToBeEmbeddedInTrustedMode();
|
||||||
@@ -1123,8 +1070,6 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
|
|||||||
// Make minWidth/minHeight exceeds the TaskFragment bounds.
|
// Make minWidth/minHeight exceeds the TaskFragment bounds.
|
||||||
activity.info.windowLayout = new ActivityInfo.WindowLayout(
|
activity.info.windowLayout = new ActivityInfo.WindowLayout(
|
||||||
0, 0, 0, 0, 0, mTaskFragBounds.width() + 10, mTaskFragBounds.height() + 10);
|
0, 0, 0, 0, 0, mTaskFragBounds.width() + 10, mTaskFragBounds.height() + 10);
|
||||||
mOrganizer.applyTransaction(mTransaction);
|
|
||||||
mController.registerOrganizer(mIOrganizer);
|
|
||||||
mTaskFragment = new TaskFragmentBuilder(mAtm)
|
mTaskFragment = new TaskFragmentBuilder(mAtm)
|
||||||
.setParentTask(task)
|
.setParentTask(task)
|
||||||
.setFragmentToken(mFragmentToken)
|
.setFragmentToken(mFragmentToken)
|
||||||
@@ -1137,7 +1082,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
|
|||||||
// minimum dimensions.
|
// minimum dimensions.
|
||||||
mTransaction.reparentActivityToTaskFragment(mFragmentToken, activity.token)
|
mTransaction.reparentActivityToTaskFragment(mFragmentToken, activity.token)
|
||||||
.setErrorCallbackToken(mErrorToken);
|
.setErrorCallbackToken(mErrorToken);
|
||||||
mWindowOrganizerController.applyTransaction(mTransaction);
|
assertApplyTransactionAllowed(mTransaction);
|
||||||
// The pending event will be dispatched on the handler (from requestTraversal).
|
// The pending event will be dispatched on the handler (from requestTraversal).
|
||||||
waitHandlerIdle(mWm.mAnimationHandler);
|
waitHandlerIdle(mWm.mAnimationHandler);
|
||||||
|
|
||||||
@@ -1148,8 +1093,6 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
|
|||||||
@Test
|
@Test
|
||||||
public void testMinDimensionViolation_ReparentChildren() {
|
public void testMinDimensionViolation_ReparentChildren() {
|
||||||
final Task task = createTask(mDisplayContent);
|
final Task task = createTask(mDisplayContent);
|
||||||
mOrganizer.applyTransaction(mTransaction);
|
|
||||||
mController.registerOrganizer(mIOrganizer);
|
|
||||||
final IBinder oldFragToken = new Binder();
|
final IBinder oldFragToken = new Binder();
|
||||||
final TaskFragment oldTaskFrag = new TaskFragmentBuilder(mAtm)
|
final TaskFragment oldTaskFrag = new TaskFragmentBuilder(mAtm)
|
||||||
.setParentTask(task)
|
.setParentTask(task)
|
||||||
@@ -1175,7 +1118,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
|
|||||||
mTransaction.reparentChildren(oldTaskFrag.mRemoteToken.toWindowContainerToken(),
|
mTransaction.reparentChildren(oldTaskFrag.mRemoteToken.toWindowContainerToken(),
|
||||||
mTaskFragment.mRemoteToken.toWindowContainerToken())
|
mTaskFragment.mRemoteToken.toWindowContainerToken())
|
||||||
.setErrorCallbackToken(mErrorToken);
|
.setErrorCallbackToken(mErrorToken);
|
||||||
mWindowOrganizerController.applyTransaction(mTransaction);
|
assertApplyTransactionAllowed(mTransaction);
|
||||||
// The pending event will be dispatched on the handler (from requestTraversal).
|
// The pending event will be dispatched on the handler (from requestTraversal).
|
||||||
waitHandlerIdle(mWm.mAnimationHandler);
|
waitHandlerIdle(mWm.mAnimationHandler);
|
||||||
|
|
||||||
@@ -1186,8 +1129,6 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
|
|||||||
@Test
|
@Test
|
||||||
public void testMinDimensionViolation_SetBounds() {
|
public void testMinDimensionViolation_SetBounds() {
|
||||||
final Task task = createTask(mDisplayContent);
|
final Task task = createTask(mDisplayContent);
|
||||||
mOrganizer.applyTransaction(mTransaction);
|
|
||||||
mController.registerOrganizer(mIOrganizer);
|
|
||||||
mTaskFragment = new TaskFragmentBuilder(mAtm)
|
mTaskFragment = new TaskFragmentBuilder(mAtm)
|
||||||
.setParentTask(task)
|
.setParentTask(task)
|
||||||
.createActivityCount(1)
|
.createActivityCount(1)
|
||||||
@@ -1206,7 +1147,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
|
|||||||
// minimum dimensions.
|
// minimum dimensions.
|
||||||
mTransaction.setBounds(mTaskFragment.mRemoteToken.toWindowContainerToken(), mTaskFragBounds)
|
mTransaction.setBounds(mTaskFragment.mRemoteToken.toWindowContainerToken(), mTaskFragBounds)
|
||||||
.setErrorCallbackToken(mErrorToken);
|
.setErrorCallbackToken(mErrorToken);
|
||||||
mWindowOrganizerController.applyTransaction(mTransaction);
|
assertApplyTransactionAllowed(mTransaction);
|
||||||
|
|
||||||
assertWithMessage("setBounds must not be performed.")
|
assertWithMessage("setBounds must not be performed.")
|
||||||
.that(mTaskFragment.getBounds()).isEqualTo(task.getBounds());
|
.that(mTaskFragment.getBounds()).isEqualTo(task.getBounds());
|
||||||
@@ -1214,18 +1155,17 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testOnTransactionReady_invokeOnTransactionHandled() {
|
public void testOnTransactionReady_invokeOnTransactionHandled() {
|
||||||
mController.registerOrganizer(mIOrganizer);
|
|
||||||
final TaskFragmentTransaction transaction = new TaskFragmentTransaction();
|
final TaskFragmentTransaction transaction = new TaskFragmentTransaction();
|
||||||
mOrganizer.onTransactionReady(transaction);
|
mOrganizer.onTransactionReady(transaction);
|
||||||
|
|
||||||
// Organizer should always trigger #onTransactionHandled when receives #onTransactionReady
|
// Organizer should always trigger #onTransactionHandled when receives #onTransactionReady
|
||||||
verify(mOrganizer).onTransactionHandled(eq(transaction.getTransactionToken()), any());
|
verify(mOrganizer).onTransactionHandled(eq(transaction.getTransactionToken()), any(),
|
||||||
verify(mOrganizer, never()).applyTransaction(any());
|
anyInt(), anyBoolean());
|
||||||
|
verify(mOrganizer, never()).applyTransaction(any(), anyInt(), anyBoolean());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDispatchTransaction_deferTransitionReady() {
|
public void testDispatchTransaction_deferTransitionReady() {
|
||||||
mController.registerOrganizer(mIOrganizer);
|
|
||||||
setupMockParent(mTaskFragment, mTask);
|
setupMockParent(mTaskFragment, mTask);
|
||||||
final ArgumentCaptor<IBinder> tokenCaptor = ArgumentCaptor.forClass(IBinder.class);
|
final ArgumentCaptor<IBinder> tokenCaptor = ArgumentCaptor.forClass(IBinder.class);
|
||||||
final ArgumentCaptor<WindowContainerTransaction> wctCaptor =
|
final ArgumentCaptor<WindowContainerTransaction> wctCaptor =
|
||||||
@@ -1238,12 +1178,15 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
|
|||||||
|
|
||||||
// Defer transition when send TaskFragment transaction during transition collection.
|
// Defer transition when send TaskFragment transaction during transition collection.
|
||||||
verify(mTransitionController).deferTransitionReady();
|
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();
|
verify(mTransitionController).continueTransitionReady();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1258,7 +1201,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
|
|||||||
ownerActivity.getTask().effectiveUid = uid;
|
ownerActivity.getTask().effectiveUid = uid;
|
||||||
final TaskFragmentCreationParams params = new TaskFragmentCreationParams.Builder(
|
final TaskFragmentCreationParams params = new TaskFragmentCreationParams.Builder(
|
||||||
mOrganizerToken, fragmentToken, ownerActivity.token).build();
|
mOrganizerToken, fragmentToken, ownerActivity.token).build();
|
||||||
mOrganizer.applyTransaction(wct);
|
wct.setTaskFragmentOrganizer(mIOrganizer);
|
||||||
|
|
||||||
// Allow organizer to create TaskFragment and start/reparent activity to TaskFragment.
|
// Allow organizer to create TaskFragment and start/reparent activity to TaskFragment.
|
||||||
wct.createTaskFragment(params);
|
wct.createTaskFragment(params);
|
||||||
@@ -1266,22 +1209,14 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
|
|||||||
|
|
||||||
/** Asserts that applying the given transaction will throw a {@link SecurityException}. */
|
/** Asserts that applying the given transaction will throw a {@link SecurityException}. */
|
||||||
private void assertApplyTransactionDisallowed(WindowContainerTransaction t) {
|
private void assertApplyTransactionDisallowed(WindowContainerTransaction t) {
|
||||||
assertThrows(SecurityException.class, () -> {
|
assertThrows(SecurityException.class, () ->
|
||||||
try {
|
mController.applyTransaction(t, getTransitionType(t),
|
||||||
mAtm.getWindowOrganizerController().applyTransaction(t);
|
false /* shouldApplyIndependently */));
|
||||||
} catch (RemoteException e) {
|
|
||||||
fail();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Asserts that applying the given transaction will not throw any exception. */
|
/** Asserts that applying the given transaction will not throw any exception. */
|
||||||
private void assertApplyTransactionAllowed(WindowContainerTransaction t) {
|
private void assertApplyTransactionAllowed(WindowContainerTransaction t) {
|
||||||
try {
|
mController.applyTransaction(t, getTransitionType(t), false /* shouldApplyIndependently */);
|
||||||
mAtm.getWindowOrganizerController().applyTransaction(t);
|
|
||||||
} catch (RemoteException e) {
|
|
||||||
fail();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Asserts that there will be a transaction for TaskFragment appeared. */
|
/** 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. */
|
/** Setups an embedded TaskFragment in a PIP Task. */
|
||||||
private void setupTaskFragmentInPip() {
|
private void setupTaskFragmentInPip() {
|
||||||
mOrganizer.applyTransaction(mTransaction);
|
|
||||||
mController.registerOrganizer(mIOrganizer);
|
|
||||||
mTaskFragment = new TaskFragmentBuilder(mAtm)
|
mTaskFragment = new TaskFragmentBuilder(mAtm)
|
||||||
.setCreateParentTask()
|
.setCreateParentTask()
|
||||||
.setFragmentToken(mFragmentToken)
|
.setFragmentToken(mFragmentToken)
|
||||||
@@ -1376,8 +1309,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
|
|||||||
.createActivityCount(1)
|
.createActivityCount(1)
|
||||||
.build();
|
.build();
|
||||||
mFragmentWindowToken = mTaskFragment.mRemoteToken.toWindowContainerToken();
|
mFragmentWindowToken = mTaskFragment.mRemoteToken.toWindowContainerToken();
|
||||||
mAtm.mWindowOrganizerController.mLaunchTaskFragments
|
mWindowOrganizerController.mLaunchTaskFragments.put(mFragmentToken, mTaskFragment);
|
||||||
.put(mFragmentToken, mTaskFragment);
|
|
||||||
mTaskFragment.getTask().setWindowingMode(WINDOWING_MODE_PINNED);
|
mTaskFragment.getTask().setWindowingMode(WINDOWING_MODE_PINNED);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user