Merge "Disable all input on ActivityRecord during untrusted animation" into tm-dev am: a3e1134c46
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/17258046 Change-Id: I59e222a005f6ce8e39dc89a88af393737fe4b818
This commit is contained in:
@@ -384,6 +384,7 @@ message ActivityRecordProto {
|
|||||||
optional float min_aspect_ratio = 33;
|
optional float min_aspect_ratio = 33;
|
||||||
optional bool provides_max_bounds = 34;
|
optional bool provides_max_bounds = 34;
|
||||||
optional bool enable_recents_screenshot = 35;
|
optional bool enable_recents_screenshot = 35;
|
||||||
|
optional int32 last_drop_input_mode = 36;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* represents WindowToken */
|
/* represents WindowToken */
|
||||||
|
|||||||
@@ -613,6 +613,12 @@
|
|||||||
"group": "WM_DEBUG_CONFIGURATION",
|
"group": "WM_DEBUG_CONFIGURATION",
|
||||||
"at": "com\/android\/server\/wm\/ActivityStarter.java"
|
"at": "com\/android\/server\/wm\/ActivityStarter.java"
|
||||||
},
|
},
|
||||||
|
"-1488852351": {
|
||||||
|
"message": "Task=%d contains embedded TaskFragment in untrusted mode. Disabled all input during TaskFragment remote animation.",
|
||||||
|
"level": "DEBUG",
|
||||||
|
"group": "WM_DEBUG_APP_TRANSITIONS",
|
||||||
|
"at": "com\/android\/server\/wm\/AppTransitionController.java"
|
||||||
|
},
|
||||||
"-1483435730": {
|
"-1483435730": {
|
||||||
"message": "InsetsSource setWin %s for type %s",
|
"message": "InsetsSource setWin %s for type %s",
|
||||||
"level": "DEBUG",
|
"level": "DEBUG",
|
||||||
|
|||||||
@@ -156,6 +156,7 @@ import static com.android.server.wm.ActivityRecordProto.IN_SIZE_COMPAT_MODE;
|
|||||||
import static com.android.server.wm.ActivityRecordProto.IS_ANIMATING;
|
import static com.android.server.wm.ActivityRecordProto.IS_ANIMATING;
|
||||||
import static com.android.server.wm.ActivityRecordProto.IS_WAITING_FOR_TRANSITION_START;
|
import static com.android.server.wm.ActivityRecordProto.IS_WAITING_FOR_TRANSITION_START;
|
||||||
import static com.android.server.wm.ActivityRecordProto.LAST_ALL_DRAWN;
|
import static com.android.server.wm.ActivityRecordProto.LAST_ALL_DRAWN;
|
||||||
|
import static com.android.server.wm.ActivityRecordProto.LAST_DROP_INPUT_MODE;
|
||||||
import static com.android.server.wm.ActivityRecordProto.LAST_SURFACE_SHOWING;
|
import static com.android.server.wm.ActivityRecordProto.LAST_SURFACE_SHOWING;
|
||||||
import static com.android.server.wm.ActivityRecordProto.MIN_ASPECT_RATIO;
|
import static com.android.server.wm.ActivityRecordProto.MIN_ASPECT_RATIO;
|
||||||
import static com.android.server.wm.ActivityRecordProto.NAME;
|
import static com.android.server.wm.ActivityRecordProto.NAME;
|
||||||
@@ -786,6 +787,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
|
|||||||
/** The last set {@link DropInputMode} for this activity surface. */
|
/** The last set {@link DropInputMode} for this activity surface. */
|
||||||
@DropInputMode
|
@DropInputMode
|
||||||
private int mLastDropInputMode = DropInputMode.NONE;
|
private int mLastDropInputMode = DropInputMode.NONE;
|
||||||
|
/** Whether the input to this activity will be dropped during the current playing animation. */
|
||||||
|
private boolean mIsInputDroppedForAnimation;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If it is non-null, it requires all activities who have the same starting data to be drawn
|
* If it is non-null, it requires all activities who have the same starting data to be drawn
|
||||||
@@ -1567,6 +1570,15 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Sets if all input will be dropped as a protection during the client-driven animation. */
|
||||||
|
void setDropInputForAnimation(boolean isInputDroppedForAnimation) {
|
||||||
|
if (mIsInputDroppedForAnimation == isInputDroppedForAnimation) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mIsInputDroppedForAnimation = isInputDroppedForAnimation;
|
||||||
|
updateUntrustedEmbeddingInputProtection();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets to drop input when obscured to activity if it is embedded in untrusted mode.
|
* Sets to drop input when obscured to activity if it is embedded in untrusted mode.
|
||||||
*
|
*
|
||||||
@@ -1576,11 +1588,13 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
|
|||||||
* all untrusted activities.
|
* all untrusted activities.
|
||||||
*/
|
*/
|
||||||
private void updateUntrustedEmbeddingInputProtection() {
|
private void updateUntrustedEmbeddingInputProtection() {
|
||||||
final SurfaceControl sc = getSurfaceControl();
|
if (getSurfaceControl() == null) {
|
||||||
if (sc == null) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (isEmbeddedInUntrustedMode()) {
|
if (mIsInputDroppedForAnimation) {
|
||||||
|
// Disable all input during the animation.
|
||||||
|
setDropInputMode(DropInputMode.ALL);
|
||||||
|
} else if (isEmbeddedInUntrustedMode()) {
|
||||||
// Set drop input to OBSCURED when untrusted embedded.
|
// Set drop input to OBSCURED when untrusted embedded.
|
||||||
setDropInputMode(DropInputMode.OBSCURED);
|
setDropInputMode(DropInputMode.OBSCURED);
|
||||||
} else {
|
} else {
|
||||||
@@ -1591,7 +1605,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
|
|||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
void setDropInputMode(@DropInputMode int mode) {
|
void setDropInputMode(@DropInputMode int mode) {
|
||||||
if (mLastDropInputMode != mode && getSurfaceControl() != null) {
|
if (mLastDropInputMode != mode) {
|
||||||
mLastDropInputMode = mode;
|
mLastDropInputMode = mode;
|
||||||
mWmService.mTransactionFactory.get()
|
mWmService.mTransactionFactory.get()
|
||||||
.setDropInputMode(getSurfaceControl(), mode)
|
.setDropInputMode(getSurfaceControl(), mode)
|
||||||
@@ -9299,6 +9313,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
|
|||||||
// permission to access the device configs.
|
// permission to access the device configs.
|
||||||
proto.write(PROVIDES_MAX_BOUNDS, providesMaxBounds());
|
proto.write(PROVIDES_MAX_BOUNDS, providesMaxBounds());
|
||||||
proto.write(ENABLE_RECENTS_SCREENSHOT, mEnableRecentsScreenshot);
|
proto.write(ENABLE_RECENTS_SCREENSHOT, mEnableRecentsScreenshot);
|
||||||
|
proto.write(LAST_DROP_INPUT_MODE, mLastDropInputMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -98,6 +98,7 @@ import java.lang.annotation.Retention;
|
|||||||
import java.lang.annotation.RetentionPolicy;
|
import java.lang.annotation.RetentionPolicy;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
|
import java.util.function.Consumer;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -541,12 +542,13 @@ public class AppTransitionController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Finds the common {@link android.window.TaskFragmentOrganizer} that organizes all app windows
|
* Finds the common parent {@link Task} that is parent of all embedded app windows in the
|
||||||
* in the current transition.
|
* current transition.
|
||||||
* @return {@code null} if there is no such organizer, or if there are more than one.
|
* @return {@code null} if app windows in the transition are not children of the same Task, or
|
||||||
|
* if none of the app windows is embedded.
|
||||||
*/
|
*/
|
||||||
@Nullable
|
@Nullable
|
||||||
private ITaskFragmentOrganizer findTaskFragmentOrganizerForAllWindows() {
|
private Task findParentTaskForAllEmbeddedWindows() {
|
||||||
mTempTransitionWindows.clear();
|
mTempTransitionWindows.clear();
|
||||||
mTempTransitionWindows.addAll(mDisplayContent.mClosingApps);
|
mTempTransitionWindows.addAll(mDisplayContent.mClosingApps);
|
||||||
mTempTransitionWindows.addAll(mDisplayContent.mOpeningApps);
|
mTempTransitionWindows.addAll(mDisplayContent.mOpeningApps);
|
||||||
@@ -600,13 +602,22 @@ public class AppTransitionController {
|
|||||||
leafTask = task;
|
leafTask = task;
|
||||||
}
|
}
|
||||||
mTempTransitionWindows.clear();
|
mTempTransitionWindows.clear();
|
||||||
if (leafTask == null) {
|
return leafTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds the common {@link android.window.TaskFragmentOrganizer} that organizes all embedded
|
||||||
|
* {@link TaskFragment} belong to the given {@link Task}.
|
||||||
|
* @return {@code null} if there is no such organizer, or if there are more than one.
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
private ITaskFragmentOrganizer findTaskFragmentOrganizer(@Nullable Task task) {
|
||||||
|
if (task == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// We don't support remote animation for Task with multiple TaskFragmentOrganizers.
|
// We don't support remote animation for Task with multiple TaskFragmentOrganizers.
|
||||||
final ITaskFragmentOrganizer[] organizer = new ITaskFragmentOrganizer[1];
|
final ITaskFragmentOrganizer[] organizer = new ITaskFragmentOrganizer[1];
|
||||||
final boolean hasMultipleOrganizers = leafTask.forAllLeafTaskFragments(taskFragment -> {
|
final boolean hasMultipleOrganizers = task.forAllLeafTaskFragments(taskFragment -> {
|
||||||
final ITaskFragmentOrganizer tfOrganizer = taskFragment.getTaskFragmentOrganizer();
|
final ITaskFragmentOrganizer tfOrganizer = taskFragment.getTaskFragmentOrganizer();
|
||||||
if (tfOrganizer == null) {
|
if (tfOrganizer == null) {
|
||||||
return false;
|
return false;
|
||||||
@@ -638,7 +649,8 @@ public class AppTransitionController {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
final ITaskFragmentOrganizer organizer = findTaskFragmentOrganizerForAllWindows();
|
final Task task = findParentTaskForAllEmbeddedWindows();
|
||||||
|
final ITaskFragmentOrganizer organizer = findTaskFragmentOrganizer(task);
|
||||||
final RemoteAnimationDefinition definition = organizer != null
|
final RemoteAnimationDefinition definition = organizer != null
|
||||||
? mDisplayContent.mAtmService.mTaskFragmentOrganizerController
|
? mDisplayContent.mAtmService.mTaskFragmentOrganizerController
|
||||||
.getRemoteAnimationDefinition(organizer)
|
.getRemoteAnimationDefinition(organizer)
|
||||||
@@ -653,6 +665,24 @@ public class AppTransitionController {
|
|||||||
ProtoLog.v(WM_DEBUG_APP_TRANSITIONS,
|
ProtoLog.v(WM_DEBUG_APP_TRANSITIONS,
|
||||||
"Override with TaskFragment remote animation for transit=%s",
|
"Override with TaskFragment remote animation for transit=%s",
|
||||||
AppTransition.appTransitionOldToString(transit));
|
AppTransition.appTransitionOldToString(transit));
|
||||||
|
|
||||||
|
final boolean hasUntrustedEmbedding = task.forAllLeafTasks(
|
||||||
|
taskFragment -> !taskFragment.isAllowedToBeEmbeddedInTrustedMode());
|
||||||
|
final RemoteAnimationController remoteAnimationController =
|
||||||
|
mDisplayContent.mAppTransition.getRemoteAnimationController();
|
||||||
|
if (hasUntrustedEmbedding && remoteAnimationController != null) {
|
||||||
|
// We are going to use client-driven animation, but the Task is in untrusted embedded
|
||||||
|
// mode. We need to disable all input on activity windows during the animation to
|
||||||
|
// ensure it is safe. This is needed for all activity windows in the animation Task.
|
||||||
|
remoteAnimationController.setOnRemoteAnimationReady(() -> {
|
||||||
|
final Consumer<ActivityRecord> updateActivities =
|
||||||
|
activity -> activity.setDropInputForAnimation(true);
|
||||||
|
task.forAllActivities(updateActivities);
|
||||||
|
});
|
||||||
|
ProtoLog.d(WM_DEBUG_APP_TRANSITIONS, "Task=%d contains embedded TaskFragment in"
|
||||||
|
+ " untrusted mode. Disabled all input during TaskFragment remote animation.",
|
||||||
|
task.mTaskId);
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME
|
|||||||
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
|
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
|
||||||
|
|
||||||
import android.annotation.NonNull;
|
import android.annotation.NonNull;
|
||||||
|
import android.annotation.Nullable;
|
||||||
import android.graphics.Point;
|
import android.graphics.Point;
|
||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
import android.os.Binder;
|
import android.os.Binder;
|
||||||
@@ -49,6 +50,7 @@ import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback;
|
|||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
import java.io.StringWriter;
|
import java.io.StringWriter;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper class to run app animations in a remote process.
|
* Helper class to run app animations in a remote process.
|
||||||
@@ -72,6 +74,8 @@ class RemoteAnimationController implements DeathRecipient {
|
|||||||
private FinishedCallback mFinishedCallback;
|
private FinishedCallback mFinishedCallback;
|
||||||
private boolean mCanceled;
|
private boolean mCanceled;
|
||||||
private boolean mLinkedToDeathOfRunner;
|
private boolean mLinkedToDeathOfRunner;
|
||||||
|
@Nullable
|
||||||
|
private Runnable mOnRemoteAnimationReady;
|
||||||
|
|
||||||
RemoteAnimationController(WindowManagerService service, DisplayContent displayContent,
|
RemoteAnimationController(WindowManagerService service, DisplayContent displayContent,
|
||||||
RemoteAnimationAdapter remoteAnimationAdapter, Handler handler) {
|
RemoteAnimationAdapter remoteAnimationAdapter, Handler handler) {
|
||||||
@@ -101,6 +105,11 @@ class RemoteAnimationController implements DeathRecipient {
|
|||||||
return adapters;
|
return adapters;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Sets callback to run before starting remote animation. */
|
||||||
|
void setOnRemoteAnimationReady(@Nullable Runnable onRemoteAnimationReady) {
|
||||||
|
mOnRemoteAnimationReady = onRemoteAnimationReady;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when the transition is ready to be started, and all leashes have been set up.
|
* Called when the transition is ready to be started, and all leashes have been set up.
|
||||||
*/
|
*/
|
||||||
@@ -133,6 +142,11 @@ class RemoteAnimationController implements DeathRecipient {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mOnRemoteAnimationReady != null) {
|
||||||
|
mOnRemoteAnimationReady.run();
|
||||||
|
mOnRemoteAnimationReady = null;
|
||||||
|
}
|
||||||
|
|
||||||
// Create the remote wallpaper animation targets (if any)
|
// Create the remote wallpaper animation targets (if any)
|
||||||
final RemoteAnimationTarget[] wallpaperTargets = createWallpaperAnimations();
|
final RemoteAnimationTarget[] wallpaperTargets = createWallpaperAnimations();
|
||||||
|
|
||||||
@@ -292,6 +306,10 @@ class RemoteAnimationController implements DeathRecipient {
|
|||||||
mService.closeSurfaceTransaction("RemoteAnimationController#finished");
|
mService.closeSurfaceTransaction("RemoteAnimationController#finished");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Reset input for all activities when the remote animation is finished.
|
||||||
|
final Consumer<ActivityRecord> updateActivities =
|
||||||
|
activity -> activity.setDropInputForAnimation(false);
|
||||||
|
mDisplayContent.forAllActivities(updateActivities);
|
||||||
setRunningRemoteAnimation(false);
|
setRunningRemoteAnimation(false);
|
||||||
ProtoLog.i(WM_DEBUG_REMOTE_ANIMATIONS, "Finishing remote animation");
|
ProtoLog.i(WM_DEBUG_REMOTE_ANIMATIONS, "Finishing remote animation");
|
||||||
}
|
}
|
||||||
@@ -303,6 +321,7 @@ class RemoteAnimationController implements DeathRecipient {
|
|||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
Slog.e(TAG, "Failed to notify cancel", e);
|
Slog.e(TAG, "Failed to notify cancel", e);
|
||||||
}
|
}
|
||||||
|
mOnRemoteAnimationReady = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void releaseFinishedCallback() {
|
private void releaseFinishedCallback() {
|
||||||
|
|||||||
@@ -304,18 +304,7 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
|
|||||||
synchronized (mGlobalLock) {
|
synchronized (mGlobalLock) {
|
||||||
final TaskFragmentOrganizerState organizerState =
|
final TaskFragmentOrganizerState organizerState =
|
||||||
mTaskFragmentOrganizerState.get(organizer.asBinder());
|
mTaskFragmentOrganizerState.get(organizer.asBinder());
|
||||||
if (organizerState == null) {
|
return organizerState != null ? organizerState.mRemoteAnimationDefinition : null;
|
||||||
return null;
|
|
||||||
}
|
|
||||||
for (TaskFragment tf : organizerState.mOrganizedTaskFragments) {
|
|
||||||
if (!tf.isAllowedToBeEmbeddedInTrustedMode()) {
|
|
||||||
// Disable client-driven animations for organizer if at least one of the
|
|
||||||
// embedded task fragments is not embedding in trusted mode.
|
|
||||||
// TODO(b/197364677): replace with a stub or Shell-driven one instead of skip?
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return organizerState.mRemoteAnimationDefinition;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -33,21 +33,26 @@ import static android.view.WindowManager.TRANSIT_OLD_TASK_OPEN;
|
|||||||
import static android.view.WindowManager.TRANSIT_OPEN;
|
import static android.view.WindowManager.TRANSIT_OPEN;
|
||||||
import static android.view.WindowManager.TRANSIT_TO_FRONT;
|
import static android.view.WindowManager.TRANSIT_TO_FRONT;
|
||||||
|
|
||||||
|
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
|
||||||
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
|
import static com.android.dx.mockito.inline.extended.ExtendedMockito.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.server.wm.WindowContainer.POSITION_BOTTOM;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertFalse;
|
import static org.junit.Assert.assertFalse;
|
||||||
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.anyInt;
|
import static org.mockito.ArgumentMatchers.anyInt;
|
||||||
|
import static org.mockito.Mockito.clearInvocations;
|
||||||
import static org.mockito.Mockito.doCallRealMethod;
|
import static org.mockito.Mockito.doCallRealMethod;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
import static org.mockito.Mockito.never;
|
import static org.mockito.Mockito.never;
|
||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
|
|
||||||
import android.annotation.Nullable;
|
import android.annotation.Nullable;
|
||||||
|
import android.gui.DropInputMode;
|
||||||
import android.os.Binder;
|
import android.os.Binder;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
import android.os.RemoteException;
|
import android.os.RemoteException;
|
||||||
@@ -739,20 +744,36 @@ public class AppTransitionControllerTest extends WindowTestsBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static class TestRemoteAnimationRunner implements IRemoteAnimationRunner {
|
static class TestRemoteAnimationRunner implements IRemoteAnimationRunner {
|
||||||
|
private IRemoteAnimationFinishedCallback mFinishedCallback;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onAnimationStart(int transit, RemoteAnimationTarget[] apps,
|
public void onAnimationStart(int transit, RemoteAnimationTarget[] apps,
|
||||||
RemoteAnimationTarget[] wallpapers, RemoteAnimationTarget[] nonApps,
|
RemoteAnimationTarget[] wallpapers, RemoteAnimationTarget[] nonApps,
|
||||||
IRemoteAnimationFinishedCallback finishedCallback) throws RemoteException {
|
IRemoteAnimationFinishedCallback finishedCallback) throws RemoteException {
|
||||||
|
mFinishedCallback = finishedCallback;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onAnimationCancelled() throws RemoteException {
|
public void onAnimationCancelled() throws RemoteException {
|
||||||
|
mFinishedCallback = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IBinder asBinder() {
|
public IBinder asBinder() {
|
||||||
return new Binder();
|
return new Binder();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean isAnimationStarted() {
|
||||||
|
return mFinishedCallback != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
void finishAnimation() {
|
||||||
|
try {
|
||||||
|
mFinishedCallback.onAnimationFinished();
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
fail();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -841,144 +862,139 @@ public class AppTransitionControllerTest extends WindowTestsBase {
|
|||||||
@Test
|
@Test
|
||||||
public void testOverrideTaskFragmentAdapter_overrideWithEmbeddedActivity() {
|
public void testOverrideTaskFragmentAdapter_overrideWithEmbeddedActivity() {
|
||||||
final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run);
|
final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run);
|
||||||
final RemoteAnimationAdapter adapter = new RemoteAnimationAdapter(
|
final TestRemoteAnimationRunner remoteAnimationRunner = new TestRemoteAnimationRunner();
|
||||||
new TestRemoteAnimationRunner(), 10, 1);
|
setupTaskFragmentRemoteAnimation(organizer, remoteAnimationRunner);
|
||||||
setupTaskFragmentRemoteAnimation(organizer, adapter);
|
|
||||||
|
|
||||||
// Create a TaskFragment with embedded activity.
|
// Create a TaskFragment with embedded activity.
|
||||||
final TaskFragment taskFragment = createTaskFragmentWithEmbeddedActivity(
|
final TaskFragment taskFragment = createTaskFragmentWithEmbeddedActivity(
|
||||||
createTask(mDisplayContent), organizer);
|
createTask(mDisplayContent), organizer);
|
||||||
final ActivityRecord activity = taskFragment.getTopMostActivity();
|
final ActivityRecord activity = taskFragment.getTopMostActivity();
|
||||||
activity.allDrawn = true;
|
prepareActivityForAppTransition(activity);
|
||||||
spyOn(mDisplayContent.mAppTransition);
|
spyOn(mDisplayContent.mAppTransition);
|
||||||
|
|
||||||
// Prepare a transition.
|
// Prepare and start transition.
|
||||||
prepareAndTriggerAppTransition(activity, null /* closingActivity */, taskFragment);
|
prepareAndTriggerAppTransition(activity, null /* closingActivity */, taskFragment);
|
||||||
|
mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
|
||||||
|
|
||||||
// Should be overridden.
|
// Animation run by the remote handler.
|
||||||
verify(mDisplayContent.mAppTransition)
|
assertTrue(remoteAnimationRunner.isAnimationStarted());
|
||||||
.overridePendingAppTransitionRemote(adapter, false /* sync */);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testOverrideTaskFragmentAdapter_overrideWithNonEmbeddedActivity() {
|
public void testOverrideTaskFragmentAdapter_overrideWithNonEmbeddedActivity() {
|
||||||
final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run);
|
final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run);
|
||||||
final RemoteAnimationAdapter adapter = new RemoteAnimationAdapter(
|
final TestRemoteAnimationRunner remoteAnimationRunner = new TestRemoteAnimationRunner();
|
||||||
new TestRemoteAnimationRunner(), 10, 1);
|
setupTaskFragmentRemoteAnimation(organizer, remoteAnimationRunner);
|
||||||
setupTaskFragmentRemoteAnimation(organizer, adapter);
|
|
||||||
|
|
||||||
final Task task = createTask(mDisplayContent);
|
final Task task = createTask(mDisplayContent);
|
||||||
// Closing non-embedded activity.
|
// Closing non-embedded activity.
|
||||||
final ActivityRecord closingActivity = createActivityRecord(task);
|
final ActivityRecord closingActivity = createActivityRecord(task);
|
||||||
closingActivity.allDrawn = true;
|
prepareActivityForAppTransition(closingActivity);
|
||||||
// Opening TaskFragment with embedded activity.
|
// Opening TaskFragment with embedded activity.
|
||||||
final TaskFragment taskFragment = createTaskFragmentWithEmbeddedActivity(task, organizer);
|
final TaskFragment taskFragment = createTaskFragmentWithEmbeddedActivity(task, organizer);
|
||||||
final ActivityRecord openingActivity = taskFragment.getTopMostActivity();
|
final ActivityRecord openingActivity = taskFragment.getTopMostActivity();
|
||||||
openingActivity.allDrawn = true;
|
prepareActivityForAppTransition(openingActivity);
|
||||||
task.effectiveUid = openingActivity.getUid();
|
task.effectiveUid = openingActivity.getUid();
|
||||||
spyOn(mDisplayContent.mAppTransition);
|
spyOn(mDisplayContent.mAppTransition);
|
||||||
|
|
||||||
// Prepare a transition.
|
// Prepare and start transition.
|
||||||
prepareAndTriggerAppTransition(openingActivity, closingActivity, taskFragment);
|
prepareAndTriggerAppTransition(openingActivity, closingActivity, taskFragment);
|
||||||
|
mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
|
||||||
|
|
||||||
// Should be overridden.
|
// Animation run by the remote handler.
|
||||||
verify(mDisplayContent.mAppTransition)
|
assertTrue(remoteAnimationRunner.isAnimationStarted());
|
||||||
.overridePendingAppTransitionRemote(adapter, false /* sync */);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testOverrideTaskFragmentAdapter_overrideEmbeddedActivityWithDiffUid() {
|
public void testOverrideTaskFragmentAdapter_overrideEmbeddedActivityWithDiffUid() {
|
||||||
final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run);
|
final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run);
|
||||||
final RemoteAnimationAdapter adapter = new RemoteAnimationAdapter(
|
final TestRemoteAnimationRunner remoteAnimationRunner = new TestRemoteAnimationRunner();
|
||||||
new TestRemoteAnimationRunner(), 10, 1);
|
setupTaskFragmentRemoteAnimation(organizer, remoteAnimationRunner);
|
||||||
setupTaskFragmentRemoteAnimation(organizer, adapter);
|
|
||||||
|
|
||||||
final Task task = createTask(mDisplayContent);
|
final Task task = createTask(mDisplayContent);
|
||||||
// Closing TaskFragment with embedded activity.
|
// Closing TaskFragment with embedded activity.
|
||||||
final TaskFragment taskFragment1 = createTaskFragmentWithEmbeddedActivity(task, organizer);
|
final TaskFragment taskFragment1 = createTaskFragmentWithEmbeddedActivity(task, organizer);
|
||||||
final ActivityRecord closingActivity = taskFragment1.getTopMostActivity();
|
final ActivityRecord closingActivity = taskFragment1.getTopMostActivity();
|
||||||
closingActivity.allDrawn = true;
|
prepareActivityForAppTransition(closingActivity);
|
||||||
closingActivity.info.applicationInfo.uid = 12345;
|
closingActivity.info.applicationInfo.uid = 12345;
|
||||||
// Opening TaskFragment with embedded activity with different UID.
|
// Opening TaskFragment with embedded activity with different UID.
|
||||||
final TaskFragment taskFragment2 = createTaskFragmentWithEmbeddedActivity(task, organizer);
|
final TaskFragment taskFragment2 = createTaskFragmentWithEmbeddedActivity(task, organizer);
|
||||||
final ActivityRecord openingActivity = taskFragment2.getTopMostActivity();
|
final ActivityRecord openingActivity = taskFragment2.getTopMostActivity();
|
||||||
|
prepareActivityForAppTransition(openingActivity);
|
||||||
openingActivity.info.applicationInfo.uid = 54321;
|
openingActivity.info.applicationInfo.uid = 54321;
|
||||||
openingActivity.allDrawn = true;
|
|
||||||
spyOn(mDisplayContent.mAppTransition);
|
spyOn(mDisplayContent.mAppTransition);
|
||||||
|
|
||||||
// Prepare a transition.
|
// Prepare and start transition.
|
||||||
prepareAndTriggerAppTransition(openingActivity, closingActivity, taskFragment1);
|
prepareAndTriggerAppTransition(openingActivity, closingActivity, taskFragment1);
|
||||||
|
mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
|
||||||
|
|
||||||
// Should be overridden.
|
// Animation run by the remote handler.
|
||||||
verify(mDisplayContent.mAppTransition)
|
assertTrue(remoteAnimationRunner.isAnimationStarted());
|
||||||
.overridePendingAppTransitionRemote(adapter, false /* sync */);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testOverrideTaskFragmentAdapter_noOverrideWithTwoApps() {
|
public void testOverrideTaskFragmentAdapter_noOverrideWithTwoApps() {
|
||||||
final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run);
|
final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run);
|
||||||
final RemoteAnimationAdapter adapter = new RemoteAnimationAdapter(
|
final TestRemoteAnimationRunner remoteAnimationRunner = new TestRemoteAnimationRunner();
|
||||||
new TestRemoteAnimationRunner(), 10, 1);
|
setupTaskFragmentRemoteAnimation(organizer, remoteAnimationRunner);
|
||||||
setupTaskFragmentRemoteAnimation(organizer, adapter);
|
|
||||||
|
|
||||||
// Closing activity in Task1.
|
// Closing activity in Task1.
|
||||||
final ActivityRecord closingActivity = createActivityRecord(mDisplayContent);
|
final ActivityRecord closingActivity = createActivityRecord(mDisplayContent);
|
||||||
closingActivity.allDrawn = true;
|
prepareActivityForAppTransition(closingActivity);
|
||||||
// Opening TaskFragment with embedded activity in Task2.
|
// Opening TaskFragment with embedded activity in Task2.
|
||||||
final TaskFragment taskFragment = createTaskFragmentWithEmbeddedActivity(
|
final TaskFragment taskFragment = createTaskFragmentWithEmbeddedActivity(
|
||||||
createTask(mDisplayContent), organizer);
|
createTask(mDisplayContent), organizer);
|
||||||
final ActivityRecord openingActivity = taskFragment.getTopMostActivity();
|
final ActivityRecord openingActivity = taskFragment.getTopMostActivity();
|
||||||
openingActivity.allDrawn = true;
|
prepareActivityForAppTransition(openingActivity);
|
||||||
spyOn(mDisplayContent.mAppTransition);
|
spyOn(mDisplayContent.mAppTransition);
|
||||||
|
|
||||||
// Prepare a transition for TaskFragment.
|
// Prepare and start transition.
|
||||||
prepareAndTriggerAppTransition(openingActivity, closingActivity, taskFragment);
|
prepareAndTriggerAppTransition(openingActivity, closingActivity, taskFragment);
|
||||||
|
mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
|
||||||
|
|
||||||
// Should not be overridden.
|
// Animation not run by the remote handler.
|
||||||
verify(mDisplayContent.mAppTransition, never())
|
assertFalse(remoteAnimationRunner.isAnimationStarted());
|
||||||
.overridePendingAppTransitionRemote(adapter, false /* sync */);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testOverrideTaskFragmentAdapter_noOverrideNonEmbeddedActivityWithDiffUid() {
|
public void testOverrideTaskFragmentAdapter_noOverrideNonEmbeddedActivityWithDiffUid() {
|
||||||
final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run);
|
final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run);
|
||||||
final RemoteAnimationAdapter adapter = new RemoteAnimationAdapter(
|
final TestRemoteAnimationRunner remoteAnimationRunner = new TestRemoteAnimationRunner();
|
||||||
new TestRemoteAnimationRunner(), 10, 1);
|
setupTaskFragmentRemoteAnimation(organizer, remoteAnimationRunner);
|
||||||
setupTaskFragmentRemoteAnimation(organizer, adapter);
|
|
||||||
|
|
||||||
final Task task = createTask(mDisplayContent);
|
final Task task = createTask(mDisplayContent);
|
||||||
// Closing TaskFragment with embedded activity.
|
// Closing TaskFragment with embedded activity.
|
||||||
final TaskFragment taskFragment = createTaskFragmentWithEmbeddedActivity(task, organizer);
|
final TaskFragment taskFragment = createTaskFragmentWithEmbeddedActivity(task, organizer);
|
||||||
final ActivityRecord closingActivity = taskFragment.getTopMostActivity();
|
final ActivityRecord closingActivity = taskFragment.getTopMostActivity();
|
||||||
closingActivity.allDrawn = true;
|
prepareActivityForAppTransition(closingActivity);
|
||||||
closingActivity.info.applicationInfo.uid = 12345;
|
closingActivity.info.applicationInfo.uid = 12345;
|
||||||
task.effectiveUid = closingActivity.getUid();
|
task.effectiveUid = closingActivity.getUid();
|
||||||
// Opening non-embedded activity with different UID.
|
// Opening non-embedded activity with different UID.
|
||||||
final ActivityRecord openingActivity = createActivityRecord(task);
|
final ActivityRecord openingActivity = createActivityRecord(task);
|
||||||
|
prepareActivityForAppTransition(openingActivity);
|
||||||
openingActivity.info.applicationInfo.uid = 54321;
|
openingActivity.info.applicationInfo.uid = 54321;
|
||||||
openingActivity.allDrawn = true;
|
|
||||||
spyOn(mDisplayContent.mAppTransition);
|
spyOn(mDisplayContent.mAppTransition);
|
||||||
|
|
||||||
// Prepare a transition.
|
// Prepare and start transition.
|
||||||
prepareAndTriggerAppTransition(openingActivity, closingActivity, taskFragment);
|
prepareAndTriggerAppTransition(openingActivity, closingActivity, taskFragment);
|
||||||
|
mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
|
||||||
|
|
||||||
// Should not be overridden
|
// Animation should not run by the remote handler when there are non-embedded activities of
|
||||||
verify(mDisplayContent.mAppTransition, never())
|
// different UID.
|
||||||
.overridePendingAppTransitionRemote(adapter, false /* sync */);
|
assertFalse(remoteAnimationRunner.isAnimationStarted());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testOverrideTaskFragmentAdapter_noOverrideWithWallpaper() {
|
public void testOverrideTaskFragmentAdapter_noOverrideWithWallpaper() {
|
||||||
final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run);
|
final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run);
|
||||||
final RemoteAnimationAdapter adapter = new RemoteAnimationAdapter(
|
final TestRemoteAnimationRunner remoteAnimationRunner = new TestRemoteAnimationRunner();
|
||||||
new TestRemoteAnimationRunner(), 10, 1);
|
setupTaskFragmentRemoteAnimation(organizer, remoteAnimationRunner);
|
||||||
setupTaskFragmentRemoteAnimation(organizer, adapter);
|
|
||||||
|
|
||||||
// Create a TaskFragment with embedded activity.
|
// Create a TaskFragment with embedded activity.
|
||||||
final TaskFragment taskFragment = createTaskFragmentWithEmbeddedActivity(
|
final TaskFragment taskFragment = createTaskFragmentWithEmbeddedActivity(
|
||||||
createTask(mDisplayContent), organizer);
|
createTask(mDisplayContent), organizer);
|
||||||
final ActivityRecord activity = taskFragment.getTopMostActivity();
|
final ActivityRecord activity = taskFragment.getTopMostActivity();
|
||||||
activity.allDrawn = true;
|
prepareActivityForAppTransition(activity);
|
||||||
// Set wallpaper as visible.
|
// Set wallpaper as visible.
|
||||||
final WallpaperWindowToken wallpaperWindowToken = new WallpaperWindowToken(mWm,
|
final WallpaperWindowToken wallpaperWindowToken = new WallpaperWindowToken(mWm,
|
||||||
mock(IBinder.class), true, mDisplayContent, true /* ownerCanManageAppTokens */);
|
mock(IBinder.class), true, mDisplayContent, true /* ownerCanManageAppTokens */);
|
||||||
@@ -986,12 +1002,66 @@ public class AppTransitionControllerTest extends WindowTestsBase {
|
|||||||
doReturn(true).when(mDisplayContent.mWallpaperController).isWallpaperVisible();
|
doReturn(true).when(mDisplayContent.mWallpaperController).isWallpaperVisible();
|
||||||
spyOn(mDisplayContent.mAppTransition);
|
spyOn(mDisplayContent.mAppTransition);
|
||||||
|
|
||||||
// Prepare a transition.
|
// Prepare and start transition.
|
||||||
prepareAndTriggerAppTransition(activity, null /* closingActivity */, taskFragment);
|
prepareAndTriggerAppTransition(activity, null /* closingActivity */, taskFragment);
|
||||||
|
mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
|
||||||
|
|
||||||
// Should not be overridden when there is wallpaper in the transition.
|
// Animation should not run by the remote handler when there is wallpaper in the transition.
|
||||||
verify(mDisplayContent.mAppTransition, never())
|
assertFalse(remoteAnimationRunner.isAnimationStarted());
|
||||||
.overridePendingAppTransitionRemote(adapter, false /* sync */);
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testOverrideTaskFragmentAdapter_inputProtectedForUntrustedAnimation() {
|
||||||
|
final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run);
|
||||||
|
final TestRemoteAnimationRunner remoteAnimationRunner = new TestRemoteAnimationRunner();
|
||||||
|
setupTaskFragmentRemoteAnimation(organizer, remoteAnimationRunner);
|
||||||
|
|
||||||
|
// Create a TaskFragment with embedded activities, one is trusted embedded, and the other
|
||||||
|
// one is untrusted embedded.
|
||||||
|
final Task task = createTask(mDisplayContent);
|
||||||
|
final TaskFragment taskFragment = new TaskFragmentBuilder(mAtm)
|
||||||
|
.setParentTask(task)
|
||||||
|
.createActivityCount(2)
|
||||||
|
.setOrganizer(organizer)
|
||||||
|
.build();
|
||||||
|
final ActivityRecord activity0 = taskFragment.getChildAt(0).asActivityRecord();
|
||||||
|
final ActivityRecord activity1 = taskFragment.getChildAt(1).asActivityRecord();
|
||||||
|
// Also create a non-embedded activity in the Task.
|
||||||
|
final ActivityRecord activity2 = new ActivityBuilder(mAtm).build();
|
||||||
|
task.addChild(activity2, POSITION_BOTTOM);
|
||||||
|
prepareActivityForAppTransition(activity0);
|
||||||
|
prepareActivityForAppTransition(activity1);
|
||||||
|
prepareActivityForAppTransition(activity2);
|
||||||
|
doReturn(false).when(taskFragment).isAllowedToEmbedActivityInTrustedMode(activity0);
|
||||||
|
doReturn(true).when(taskFragment).isAllowedToEmbedActivityInTrustedMode(activity1);
|
||||||
|
spyOn(mDisplayContent.mAppTransition);
|
||||||
|
|
||||||
|
// Prepare and start transition.
|
||||||
|
prepareAndTriggerAppTransition(activity1, null /* closingActivity */, taskFragment);
|
||||||
|
mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
|
||||||
|
|
||||||
|
// The animation will be animated remotely by client and all activities are input disabled
|
||||||
|
// for untrusted animation.
|
||||||
|
assertTrue(remoteAnimationRunner.isAnimationStarted());
|
||||||
|
verify(activity0).setDropInputForAnimation(true);
|
||||||
|
verify(activity1).setDropInputForAnimation(true);
|
||||||
|
verify(activity2).setDropInputForAnimation(true);
|
||||||
|
verify(activity0).setDropInputMode(DropInputMode.ALL);
|
||||||
|
verify(activity1).setDropInputMode(DropInputMode.ALL);
|
||||||
|
verify(activity2).setDropInputMode(DropInputMode.ALL);
|
||||||
|
|
||||||
|
// Reset input after animation is finished.
|
||||||
|
clearInvocations(activity0);
|
||||||
|
clearInvocations(activity1);
|
||||||
|
clearInvocations(activity2);
|
||||||
|
remoteAnimationRunner.finishAnimation();
|
||||||
|
|
||||||
|
verify(activity0).setDropInputForAnimation(false);
|
||||||
|
verify(activity1).setDropInputForAnimation(false);
|
||||||
|
verify(activity2).setDropInputForAnimation(false);
|
||||||
|
verify(activity0).setDropInputMode(DropInputMode.OBSCURED);
|
||||||
|
verify(activity1).setDropInputMode(DropInputMode.NONE);
|
||||||
|
verify(activity2).setDropInputMode(DropInputMode.NONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -1004,7 +1074,7 @@ public class AppTransitionControllerTest extends WindowTestsBase {
|
|||||||
.setParentTask(task)
|
.setParentTask(task)
|
||||||
.setOrganizer(organizer)
|
.setOrganizer(organizer)
|
||||||
.build();
|
.build();
|
||||||
changeTaskFragment.getTopMostActivity().allDrawn = true;
|
prepareActivityForAppTransition(changeTaskFragment.getTopMostActivity());
|
||||||
spyOn(mDisplayContent.mAppTransition);
|
spyOn(mDisplayContent.mAppTransition);
|
||||||
spyOn(emptyTaskFragment);
|
spyOn(emptyTaskFragment);
|
||||||
|
|
||||||
@@ -1034,7 +1104,7 @@ public class AppTransitionControllerTest extends WindowTestsBase {
|
|||||||
.setParentTask(task)
|
.setParentTask(task)
|
||||||
.setOrganizer(organizer)
|
.setOrganizer(organizer)
|
||||||
.build();
|
.build();
|
||||||
changeTaskFragment.getTopMostActivity().allDrawn = true;
|
prepareActivityForAppTransition(changeTaskFragment.getTopMostActivity());
|
||||||
// To make sure that having a detached activity won't cause any issue.
|
// To make sure that having a detached activity won't cause any issue.
|
||||||
final ActivityRecord detachedActivity = createActivityRecord(task);
|
final ActivityRecord detachedActivity = createActivityRecord(task);
|
||||||
detachedActivity.removeImmediately();
|
detachedActivity.removeImmediately();
|
||||||
@@ -1060,7 +1130,9 @@ public class AppTransitionControllerTest extends WindowTestsBase {
|
|||||||
|
|
||||||
/** Registers remote animation for the organizer. */
|
/** Registers remote animation for the organizer. */
|
||||||
private void setupTaskFragmentRemoteAnimation(TaskFragmentOrganizer organizer,
|
private void setupTaskFragmentRemoteAnimation(TaskFragmentOrganizer organizer,
|
||||||
RemoteAnimationAdapter adapter) {
|
TestRemoteAnimationRunner remoteAnimationRunner) {
|
||||||
|
final RemoteAnimationAdapter adapter = new RemoteAnimationAdapter(
|
||||||
|
remoteAnimationRunner, 10, 1);
|
||||||
final ITaskFragmentOrganizer iOrganizer =
|
final ITaskFragmentOrganizer iOrganizer =
|
||||||
ITaskFragmentOrganizer.Stub.asInterface(organizer.getOrganizerToken().asBinder());
|
ITaskFragmentOrganizer.Stub.asInterface(organizer.getOrganizerToken().asBinder());
|
||||||
final RemoteAnimationDefinition definition = new RemoteAnimationDefinition();
|
final RemoteAnimationDefinition definition = new RemoteAnimationDefinition();
|
||||||
@@ -1087,4 +1159,14 @@ public class AppTransitionControllerTest extends WindowTestsBase {
|
|||||||
}
|
}
|
||||||
mDisplayContent.mAppTransitionController.handleAppTransitionReady();
|
mDisplayContent.mAppTransitionController.handleAppTransitionReady();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void prepareActivityForAppTransition(ActivityRecord activity) {
|
||||||
|
// Transition will wait until all participated activities to be drawn.
|
||||||
|
activity.allDrawn = true;
|
||||||
|
// Skip manipulate the SurfaceControl.
|
||||||
|
doNothing().when(activity).setDropInputMode(anyInt());
|
||||||
|
// Make sure activity can create remote animation target.
|
||||||
|
doReturn(mock(RemoteAnimationTarget.class)).when(activity).createRemoteAnimationTarget(
|
||||||
|
any());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user