Merge "Only override ActivityEmbedding animation for embedded activities" into tm-qpr-dev am: c9b69ab91d

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/20475428

Change-Id: I86e5258bb672c0aa1bc25ebcc45b3d5069eaa528
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
Chris Li
2022-11-19 03:51:37 +00:00
committed by Automerger Merge Worker
14 changed files with 194 additions and 191 deletions

View File

@@ -39,13 +39,13 @@ interface ITaskFragmentOrganizerController {
* animations if the transition only contains windows that belong to the organized * animations if the transition only contains windows that belong to the organized
* TaskFragments in the given Task. * TaskFragments in the given Task.
*/ */
void registerRemoteAnimations(in ITaskFragmentOrganizer organizer, int taskId, void registerRemoteAnimations(in ITaskFragmentOrganizer organizer,
in RemoteAnimationDefinition definition); in RemoteAnimationDefinition definition);
/** /**
* Unregisters remote animations per transition type for the organizer. * Unregisters remote animations per transition type for the organizer.
*/ */
void unregisterRemoteAnimations(in ITaskFragmentOrganizer organizer, int taskId); void unregisterRemoteAnimations(in ITaskFragmentOrganizer organizer);
/** /**
* Checks if an activity organized by a {@link android.window.TaskFragmentOrganizer} and * Checks if an activity organized by a {@link android.window.TaskFragmentOrganizer} and

View File

@@ -140,16 +140,13 @@ public class TaskFragmentOrganizer extends WindowOrganizer {
/** /**
* Registers remote animations per transition type for the organizer. It will override the * Registers remote animations per transition type for the organizer. It will override the
* animations if the transition only contains windows that belong to the organized * animations if the transition only contains windows that belong to the organized
* TaskFragments in the given Task. * TaskFragments, and at least one of the transition window is embedded (not filling the Task).
*
* @param taskId overrides if the transition only contains windows belonging to this Task.
* @hide * @hide
*/ */
@CallSuper @CallSuper
public void registerRemoteAnimations(int taskId, public void registerRemoteAnimations(@NonNull RemoteAnimationDefinition definition) {
@NonNull RemoteAnimationDefinition definition) {
try { try {
getController().registerRemoteAnimations(mInterface, taskId, definition); getController().registerRemoteAnimations(mInterface, definition);
} catch (RemoteException e) { } catch (RemoteException e) {
throw e.rethrowFromSystemServer(); throw e.rethrowFromSystemServer();
} }
@@ -160,9 +157,9 @@ public class TaskFragmentOrganizer extends WindowOrganizer {
* @hide * @hide
*/ */
@CallSuper @CallSuper
public void unregisterRemoteAnimations(int taskId) { public void unregisterRemoteAnimations() {
try { try {
getController().unregisterRemoteAnimations(mInterface, taskId); getController().unregisterRemoteAnimations(mInterface);
} catch (RemoteException e) { } catch (RemoteException e) {
throw e.rethrowFromSystemServer(); throw e.rethrowFromSystemServer();
} }

View File

@@ -37,7 +37,6 @@ import android.window.TaskFragmentOrganizer;
import android.window.TaskFragmentTransaction; import android.window.TaskFragmentTransaction;
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;
@@ -85,26 +84,20 @@ class JetpackTaskFragmentOrganizer extends TaskFragmentOrganizer {
@Override @Override
public void unregisterOrganizer() { public void unregisterOrganizer() {
if (mAnimationController != null) { if (mAnimationController != null) {
mAnimationController.unregisterAllRemoteAnimations(); mAnimationController.unregisterRemoteAnimations();
mAnimationController = null; mAnimationController = null;
} }
super.unregisterOrganizer(); super.unregisterOrganizer();
} }
/** Overrides the animation if the transition is on the given Task. */ /**
void startOverrideSplitAnimation(int taskId) { * Overrides the animation for transitions of embedded activities organized by this organizer.
*/
void overrideSplitAnimation() {
if (mAnimationController == null) { if (mAnimationController == null) {
mAnimationController = new TaskFragmentAnimationController(this); mAnimationController = new TaskFragmentAnimationController(this);
} }
mAnimationController.registerRemoteAnimations(taskId); mAnimationController.registerRemoteAnimations();
}
/** No longer overrides the animation if the transition is on the given Task. */
@GuardedBy("mLock")
void stopOverrideSplitAnimation(int taskId) {
if (mAnimationController != null) {
mAnimationController.unregisterRemoteAnimations(taskId);
}
} }
/** /**

View File

@@ -193,7 +193,6 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
continue; continue;
} }
updateContainersInTask(wct, taskContainer); updateContainersInTask(wct, taskContainer);
updateAnimationOverride(taskContainer);
} }
// The WCT should be applied and merged to the device state change transition if // The WCT should be applied and merged to the device state change transition if
// there is one. // there is one.
@@ -208,9 +207,6 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
synchronized (mLock) { synchronized (mLock) {
mSplitRules.clear(); mSplitRules.clear();
mSplitRules.addAll(rules); mSplitRules.addAll(rules);
for (int i = mTaskContainers.size() - 1; i >= 0; i--) {
updateAnimationOverride(mTaskContainers.valueAt(i));
}
} }
} }
@@ -612,7 +608,6 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
} }
if (taskContainer.isEmpty()) { if (taskContainer.isEmpty()) {
// Cleanup the TaskContainer if it becomes empty. // Cleanup the TaskContainer if it becomes empty.
mPresenter.stopOverrideSplitAnimation(taskContainer.getTaskId());
mTaskContainers.remove(taskContainer.getTaskId()); mTaskContainers.remove(taskContainer.getTaskId());
} }
return; return;
@@ -622,43 +617,7 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
@GuardedBy("mLock") @GuardedBy("mLock")
private void onTaskContainerInfoChanged(@NonNull TaskContainer taskContainer, private void onTaskContainerInfoChanged(@NonNull TaskContainer taskContainer,
@NonNull Configuration config) { @NonNull Configuration config) {
final boolean wasInPip = taskContainer.isInPictureInPicture(); taskContainer.setTaskBounds(config.windowConfiguration.getBounds());
final boolean isInPIp = isInPictureInPicture(config);
// We need to check the animation override when enter/exit PIP or has bounds changed.
boolean shouldUpdateAnimationOverride = wasInPip != isInPIp;
if (taskContainer.setTaskBounds(config.windowConfiguration.getBounds())
&& !isInPIp) {
// We don't care the bounds change when it has already entered PIP.
shouldUpdateAnimationOverride = true;
}
if (shouldUpdateAnimationOverride) {
updateAnimationOverride(taskContainer);
}
}
/**
* Updates if we should override transition animation. We only want to override if the Task
* bounds is large enough for at least one split rule.
*/
@GuardedBy("mLock")
private void updateAnimationOverride(@NonNull TaskContainer taskContainer) {
if (ENABLE_SHELL_TRANSITIONS) {
// TODO(b/207070762): cleanup with legacy app transition
// Animation will be handled by WM Shell with Shell transition enabled.
return;
}
if (!taskContainer.isTaskBoundsInitialized()) {
// We don't know about the Task bounds/windowingMode yet.
return;
}
// We only want to override if the TaskContainer may show split.
if (mayShowSplit(taskContainer)) {
mPresenter.startOverrideSplitAnimation(taskContainer.getTaskId());
} else {
mPresenter.stopOverrideSplitAnimation(taskContainer.getTaskId());
}
} }
/** Returns whether the given {@link TaskContainer} may show in split. */ /** Returns whether the given {@link TaskContainer} may show in split. */
@@ -1283,7 +1242,6 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
Log.w(TAG, "Can't find bounds from activity=" + activityInTask); Log.w(TAG, "Can't find bounds from activity=" + activityInTask);
} }
} }
updateAnimationOverride(taskContainer);
return container; return container;
} }

View File

@@ -139,6 +139,11 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer {
super(executor, controller); super(executor, controller);
mController = controller; mController = controller;
registerOrganizer(); registerOrganizer();
if (!SplitController.ENABLE_SHELL_TRANSITIONS) {
// TODO(b/207070762): cleanup with legacy app transition
// Animation will be handled by WM Shell when Shell transition is enabled.
overrideSplitAnimation();
}
} }
/** /**

View File

@@ -18,13 +18,10 @@ package androidx.window.extensions.embedding;
import static android.view.WindowManager.TRANSIT_OLD_ACTIVITY_CLOSE; import static android.view.WindowManager.TRANSIT_OLD_ACTIVITY_CLOSE;
import static android.view.WindowManager.TRANSIT_OLD_ACTIVITY_OPEN; import static android.view.WindowManager.TRANSIT_OLD_ACTIVITY_OPEN;
import static android.view.WindowManager.TRANSIT_OLD_TASK_CLOSE;
import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_CHANGE; import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_CHANGE;
import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_CLOSE; import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_CLOSE;
import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_OPEN; import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_OPEN;
import static android.view.WindowManager.TRANSIT_OLD_TASK_OPEN;
import android.util.ArraySet;
import android.util.Log; import android.util.Log;
import android.view.RemoteAnimationAdapter; import android.view.RemoteAnimationAdapter;
import android.view.RemoteAnimationDefinition; import android.view.RemoteAnimationDefinition;
@@ -44,8 +41,7 @@ class TaskFragmentAnimationController {
private final TaskFragmentAnimationRunner mRemoteRunner = new TaskFragmentAnimationRunner(); private final TaskFragmentAnimationRunner mRemoteRunner = new TaskFragmentAnimationRunner();
@VisibleForTesting @VisibleForTesting
final RemoteAnimationDefinition mDefinition; final RemoteAnimationDefinition mDefinition;
/** Task Ids that we have registered for remote animation. */ private boolean mIsRegistered;
private final ArraySet<Integer> mRegisterTasks = new ArraySet<>();
TaskFragmentAnimationController(@NonNull TaskFragmentOrganizer organizer) { TaskFragmentAnimationController(@NonNull TaskFragmentOrganizer organizer) {
mOrganizer = organizer; mOrganizer = organizer;
@@ -54,39 +50,30 @@ class TaskFragmentAnimationController {
new RemoteAnimationAdapter(mRemoteRunner, 0, 0, true /* changeNeedsSnapshot */); new RemoteAnimationAdapter(mRemoteRunner, 0, 0, true /* changeNeedsSnapshot */);
mDefinition.addRemoteAnimation(TRANSIT_OLD_ACTIVITY_OPEN, animationAdapter); mDefinition.addRemoteAnimation(TRANSIT_OLD_ACTIVITY_OPEN, animationAdapter);
mDefinition.addRemoteAnimation(TRANSIT_OLD_TASK_FRAGMENT_OPEN, animationAdapter); mDefinition.addRemoteAnimation(TRANSIT_OLD_TASK_FRAGMENT_OPEN, animationAdapter);
mDefinition.addRemoteAnimation(TRANSIT_OLD_TASK_OPEN, animationAdapter);
mDefinition.addRemoteAnimation(TRANSIT_OLD_ACTIVITY_CLOSE, animationAdapter); mDefinition.addRemoteAnimation(TRANSIT_OLD_ACTIVITY_CLOSE, animationAdapter);
mDefinition.addRemoteAnimation(TRANSIT_OLD_TASK_FRAGMENT_CLOSE, animationAdapter); mDefinition.addRemoteAnimation(TRANSIT_OLD_TASK_FRAGMENT_CLOSE, animationAdapter);
mDefinition.addRemoteAnimation(TRANSIT_OLD_TASK_CLOSE, animationAdapter);
mDefinition.addRemoteAnimation(TRANSIT_OLD_TASK_FRAGMENT_CHANGE, animationAdapter); mDefinition.addRemoteAnimation(TRANSIT_OLD_TASK_FRAGMENT_CHANGE, animationAdapter);
} }
void registerRemoteAnimations(int taskId) { void registerRemoteAnimations() {
if (DEBUG) { if (DEBUG) {
Log.v(TAG, "registerRemoteAnimations"); Log.v(TAG, "registerRemoteAnimations");
} }
if (mRegisterTasks.contains(taskId)) { if (mIsRegistered) {
return; return;
} }
mOrganizer.registerRemoteAnimations(taskId, mDefinition); mOrganizer.registerRemoteAnimations(mDefinition);
mRegisterTasks.add(taskId); mIsRegistered = true;
} }
void unregisterRemoteAnimations(int taskId) { void unregisterRemoteAnimations() {
if (DEBUG) { if (DEBUG) {
Log.v(TAG, "unregisterRemoteAnimations"); Log.v(TAG, "unregisterRemoteAnimations");
} }
if (!mRegisterTasks.contains(taskId)) { if (!mIsRegistered) {
return; return;
} }
mOrganizer.unregisterRemoteAnimations(taskId); mOrganizer.unregisterRemoteAnimations();
mRegisterTasks.remove(taskId); mIsRegistered = false;
}
void unregisterAllRemoteAnimations() {
final ArraySet<Integer> tasks = new ArraySet<>(mRegisterTasks);
for (int taskId : tasks) {
unregisterRemoteAnimations(taskId);
}
} }
} }

View File

@@ -20,11 +20,9 @@ import static android.os.Process.THREAD_PRIORITY_DISPLAY;
import static android.view.RemoteAnimationTarget.MODE_CLOSING; import static android.view.RemoteAnimationTarget.MODE_CLOSING;
import static android.view.WindowManager.TRANSIT_OLD_ACTIVITY_CLOSE; import static android.view.WindowManager.TRANSIT_OLD_ACTIVITY_CLOSE;
import static android.view.WindowManager.TRANSIT_OLD_ACTIVITY_OPEN; import static android.view.WindowManager.TRANSIT_OLD_ACTIVITY_OPEN;
import static android.view.WindowManager.TRANSIT_OLD_TASK_CLOSE;
import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_CHANGE; import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_CHANGE;
import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_CLOSE; import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_CLOSE;
import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_OPEN; import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_OPEN;
import static android.view.WindowManager.TRANSIT_OLD_TASK_OPEN;
import static android.view.WindowManagerPolicyConstants.TYPE_LAYER_OFFSET; import static android.view.WindowManagerPolicyConstants.TYPE_LAYER_OFFSET;
import android.animation.Animator; import android.animation.Animator;
@@ -169,11 +167,9 @@ class TaskFragmentAnimationRunner extends IRemoteAnimationRunner.Stub {
switch (transit) { switch (transit) {
case TRANSIT_OLD_ACTIVITY_OPEN: case TRANSIT_OLD_ACTIVITY_OPEN:
case TRANSIT_OLD_TASK_FRAGMENT_OPEN: case TRANSIT_OLD_TASK_FRAGMENT_OPEN:
case TRANSIT_OLD_TASK_OPEN:
return createOpenAnimationAdapters(targets); return createOpenAnimationAdapters(targets);
case TRANSIT_OLD_ACTIVITY_CLOSE: case TRANSIT_OLD_ACTIVITY_CLOSE:
case TRANSIT_OLD_TASK_FRAGMENT_CLOSE: case TRANSIT_OLD_TASK_FRAGMENT_CLOSE:
case TRANSIT_OLD_TASK_CLOSE:
return createCloseAnimationAdapters(targets); return createCloseAnimationAdapters(targets);
case TRANSIT_OLD_TASK_FRAGMENT_CHANGE: case TRANSIT_OLD_TASK_FRAGMENT_CHANGE:
return createChangeAnimationAdapters(targets); return createChangeAnimationAdapters(targets);

View File

@@ -18,7 +18,6 @@ package androidx.window.extensions.embedding;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static androidx.window.extensions.embedding.EmbeddingTestUtils.TASK_ID;
import static androidx.window.extensions.embedding.EmbeddingTestUtils.createTestTaskContainer; import static androidx.window.extensions.embedding.EmbeddingTestUtils.createTestTaskContainer;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
@@ -26,10 +25,8 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
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.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import android.content.Intent; import android.content.Intent;
import android.content.res.Configuration; import android.content.res.Configuration;
@@ -85,35 +82,20 @@ public class JetpackTaskFragmentOrganizerTest {
@Test @Test
public void testUnregisterOrganizer() { public void testUnregisterOrganizer() {
mOrganizer.startOverrideSplitAnimation(TASK_ID); mOrganizer.overrideSplitAnimation();
mOrganizer.startOverrideSplitAnimation(TASK_ID + 1);
mOrganizer.unregisterOrganizer(); mOrganizer.unregisterOrganizer();
verify(mOrganizer).unregisterRemoteAnimations(TASK_ID); verify(mOrganizer).unregisterRemoteAnimations();
verify(mOrganizer).unregisterRemoteAnimations(TASK_ID + 1);
} }
@Test @Test
public void testStartOverrideSplitAnimation() { public void testOverrideSplitAnimation() {
assertNull(mOrganizer.mAnimationController); assertNull(mOrganizer.mAnimationController);
mOrganizer.startOverrideSplitAnimation(TASK_ID); mOrganizer.overrideSplitAnimation();
assertNotNull(mOrganizer.mAnimationController); assertNotNull(mOrganizer.mAnimationController);
verify(mOrganizer).registerRemoteAnimations(TASK_ID, verify(mOrganizer).registerRemoteAnimations(mOrganizer.mAnimationController.mDefinition);
mOrganizer.mAnimationController.mDefinition);
}
@Test
public void testStopOverrideSplitAnimation() {
mOrganizer.stopOverrideSplitAnimation(TASK_ID);
verify(mOrganizer, never()).unregisterRemoteAnimations(anyInt());
mOrganizer.startOverrideSplitAnimation(TASK_ID);
mOrganizer.stopOverrideSplitAnimation(TASK_ID);
verify(mOrganizer).unregisterRemoteAnimations(TASK_ID);
} }
@Test @Test

View File

@@ -16,11 +16,8 @@
package androidx.window.extensions.embedding; package androidx.window.extensions.embedding;
import static androidx.window.extensions.embedding.EmbeddingTestUtils.TASK_ID;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.never; import static org.mockito.Mockito.never;
import android.platform.test.annotations.Presubmit; import android.platform.test.annotations.Presubmit;
@@ -57,41 +54,31 @@ public class TaskFragmentAnimationControllerTest {
@Test @Test
public void testRegisterRemoteAnimations() { public void testRegisterRemoteAnimations() {
mAnimationController.registerRemoteAnimations(TASK_ID); mAnimationController.registerRemoteAnimations();
verify(mOrganizer).registerRemoteAnimations(TASK_ID, mAnimationController.mDefinition); verify(mOrganizer).registerRemoteAnimations(mAnimationController.mDefinition);
mAnimationController.registerRemoteAnimations(TASK_ID); mAnimationController.registerRemoteAnimations();
// No extra call if it has been registered. // No extra call if it has been registered.
verify(mOrganizer).registerRemoteAnimations(TASK_ID, mAnimationController.mDefinition); verify(mOrganizer).registerRemoteAnimations(mAnimationController.mDefinition);
} }
@Test @Test
public void testUnregisterRemoteAnimations() { public void testUnregisterRemoteAnimations() {
mAnimationController.unregisterRemoteAnimations(TASK_ID); mAnimationController.unregisterRemoteAnimations();
// No call if it is not registered. // No call if it is not registered.
verify(mOrganizer, never()).unregisterRemoteAnimations(anyInt()); verify(mOrganizer, never()).unregisterRemoteAnimations();
mAnimationController.registerRemoteAnimations(TASK_ID); mAnimationController.registerRemoteAnimations();
mAnimationController.unregisterRemoteAnimations(TASK_ID); mAnimationController.unregisterRemoteAnimations();
verify(mOrganizer).unregisterRemoteAnimations(TASK_ID); verify(mOrganizer).unregisterRemoteAnimations();
mAnimationController.unregisterRemoteAnimations(TASK_ID); mAnimationController.unregisterRemoteAnimations();
// No extra call if it has been unregistered. // No extra call if it has been unregistered.
verify(mOrganizer).unregisterRemoteAnimations(TASK_ID); verify(mOrganizer).unregisterRemoteAnimations();
}
@Test
public void testUnregisterAllRemoteAnimations() {
mAnimationController.registerRemoteAnimations(TASK_ID);
mAnimationController.registerRemoteAnimations(TASK_ID + 1);
mAnimationController.unregisterAllRemoteAnimations();
verify(mOrganizer).unregisterRemoteAnimations(TASK_ID);
verify(mOrganizer).unregisterRemoteAnimations(TASK_ID + 1);
} }
} }

View File

@@ -561,6 +561,34 @@ public class AppTransitionController {
|| shouldStartWallpaperAnimation(mDisplayContent); || shouldStartWallpaperAnimation(mDisplayContent);
} }
/**
* Whether the transition contains any embedded {@link TaskFragment} that does not fill the
* parent {@link Task} before or after the transition.
*/
private boolean transitionContainsTaskFragmentWithBoundsOverride() {
for (int i = mDisplayContent.mChangingContainers.size() - 1; i >= 0; i--) {
final WindowContainer wc = mDisplayContent.mChangingContainers.valueAt(i);
if (wc.isEmbedded()) {
// Contains embedded TaskFragment with bounds changed.
return true;
}
}
mTempTransitionWindows.clear();
mTempTransitionWindows.addAll(mDisplayContent.mClosingApps);
mTempTransitionWindows.addAll(mDisplayContent.mOpeningApps);
boolean containsTaskFragmentWithBoundsOverride = false;
for (int i = mTempTransitionWindows.size() - 1; i >= 0; i--) {
final ActivityRecord r = mTempTransitionWindows.get(i).asActivityRecord();
final TaskFragment tf = r.getTaskFragment();
if (tf != null && tf.isEmbeddedWithBoundsOverride()) {
containsTaskFragmentWithBoundsOverride = true;
break;
}
}
mTempTransitionWindows.clear();
return containsTaskFragmentWithBoundsOverride;
}
/** /**
* Finds the common parent {@link Task} that is parent of all embedded app windows in the * Finds the common parent {@link Task} that is parent of all embedded app windows in the
* current transition. * current transition.
@@ -664,12 +692,17 @@ public class AppTransitionController {
if (transitionMayContainNonAppWindows(transit)) { if (transitionMayContainNonAppWindows(transit)) {
return false; return false;
} }
if (!transitionContainsTaskFragmentWithBoundsOverride()) {
// No need to play TaskFragment remote animation if all embedded TaskFragment in the
// transition fill the Task.
return false;
}
final Task task = findParentTaskForAllEmbeddedWindows(); final Task task = findParentTaskForAllEmbeddedWindows();
final ITaskFragmentOrganizer organizer = findTaskFragmentOrganizer(task); final ITaskFragmentOrganizer organizer = findTaskFragmentOrganizer(task);
final RemoteAnimationDefinition definition = organizer != null final RemoteAnimationDefinition definition = organizer != null
? mDisplayContent.mAtmService.mTaskFragmentOrganizerController ? mDisplayContent.mAtmService.mTaskFragmentOrganizerController
.getRemoteAnimationDefinition(organizer, task.mTaskId) .getRemoteAnimationDefinition(organizer)
: null; : null;
final RemoteAnimationAdapter adapter = definition != null final RemoteAnimationAdapter adapter = definition != null
? definition.getAdapter(transit, activityTypes) ? definition.getAdapter(transit, activityTypes)

View File

@@ -581,15 +581,7 @@ class TaskFragment extends WindowContainer<WindowContainer> {
@Override @Override
boolean isEmbedded() { boolean isEmbedded() {
if (mIsEmbedded) { return mIsEmbedded;
return true;
}
final WindowContainer<?> parent = getParent();
if (parent != null) {
final TaskFragment taskFragment = parent.asTaskFragment();
return taskFragment != null && taskFragment.isEmbedded();
}
return false;
} }
@EmbeddingCheckResult @EmbeddingCheckResult
@@ -2519,6 +2511,22 @@ class TaskFragment extends WindowContainer<WindowContainer> {
return mTaskFragmentOrganizer != null; return mTaskFragmentOrganizer != null;
} }
/**
* Whether this is an embedded {@link TaskFragment} that does not fill the parent {@link Task}.
*/
boolean isEmbeddedWithBoundsOverride() {
if (!mIsEmbedded) {
return false;
}
final Task task = getTask();
if (task == null) {
return false;
}
final Rect taskBounds = task.getBounds();
final Rect taskFragBounds = getBounds();
return !taskBounds.equals(taskFragBounds) && taskBounds.contains(taskFragBounds);
}
/** Whether the Task should be visible. */ /** Whether the Task should be visible. */
boolean isTaskVisibleRequested() { boolean isTaskVisibleRequested() {
final Task task = getTask(); final Task task = getTask();

View File

@@ -36,7 +36,6 @@ import android.annotation.NonNull;
import android.annotation.Nullable; import android.annotation.Nullable;
import android.content.Intent; import android.content.Intent;
import android.content.res.Configuration; import android.content.res.Configuration;
import android.graphics.Rect;
import android.os.Binder; import android.os.Binder;
import android.os.Bundle; import android.os.Bundle;
import android.os.IBinder; import android.os.IBinder;
@@ -133,12 +132,11 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
new WeakHashMap<>(); new WeakHashMap<>();
/** /**
* Map from Task Id to {@link RemoteAnimationDefinition}. * {@link RemoteAnimationDefinition} for embedded activities transition animation that is
* @see android.window.TaskFragmentOrganizer#registerRemoteAnimations(int, * organized by this organizer.
* RemoteAnimationDefinition) )
*/ */
private final SparseArray<RemoteAnimationDefinition> mRemoteAnimationDefinitions = @Nullable
new SparseArray<>(); private RemoteAnimationDefinition mRemoteAnimationDefinition;
/** /**
* Map from {@link TaskFragmentTransaction#getTransactionToken()} to the * Map from {@link TaskFragmentTransaction#getTransactionToken()} to the
@@ -455,7 +453,7 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
} }
@Override @Override
public void registerRemoteAnimations(@NonNull ITaskFragmentOrganizer organizer, int taskId, public void registerRemoteAnimations(@NonNull ITaskFragmentOrganizer organizer,
@NonNull RemoteAnimationDefinition definition) { @NonNull RemoteAnimationDefinition definition) {
final int pid = Binder.getCallingPid(); final int pid = Binder.getCallingPid();
final int uid = Binder.getCallingUid(); final int uid = Binder.getCallingUid();
@@ -468,20 +466,19 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
if (organizerState == null) { if (organizerState == null) {
throw new IllegalStateException("The organizer hasn't been registered."); throw new IllegalStateException("The organizer hasn't been registered.");
} }
if (organizerState.mRemoteAnimationDefinitions.contains(taskId)) { if (organizerState.mRemoteAnimationDefinition != null) {
throw new IllegalStateException( throw new IllegalStateException(
"The organizer has already registered remote animations=" "The organizer has already registered remote animations="
+ organizerState.mRemoteAnimationDefinitions.get(taskId) + organizerState.mRemoteAnimationDefinition);
+ " for TaskId=" + taskId);
} }
definition.setCallingPidUid(pid, uid); definition.setCallingPidUid(pid, uid);
organizerState.mRemoteAnimationDefinitions.put(taskId, definition); organizerState.mRemoteAnimationDefinition = definition;
} }
} }
@Override @Override
public void unregisterRemoteAnimations(@NonNull ITaskFragmentOrganizer organizer, int taskId) { public void unregisterRemoteAnimations(@NonNull ITaskFragmentOrganizer organizer) {
final int pid = Binder.getCallingPid(); final int pid = Binder.getCallingPid();
final long uid = Binder.getCallingUid(); final long uid = Binder.getCallingUid();
synchronized (mGlobalLock) { synchronized (mGlobalLock) {
@@ -495,7 +492,7 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
return; return;
} }
organizerState.mRemoteAnimationDefinitions.remove(taskId); organizerState.mRemoteAnimationDefinition = null;
} }
} }
@@ -527,16 +524,16 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
/** /**
* 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.
*/ */
@Nullable @Nullable
public RemoteAnimationDefinition getRemoteAnimationDefinition( public RemoteAnimationDefinition getRemoteAnimationDefinition(
@NonNull ITaskFragmentOrganizer organizer, int taskId) { @NonNull ITaskFragmentOrganizer organizer) {
synchronized (mGlobalLock) { synchronized (mGlobalLock) {
final TaskFragmentOrganizerState organizerState = final TaskFragmentOrganizerState organizerState =
mTaskFragmentOrganizerState.get(organizer.asBinder()); mTaskFragmentOrganizerState.get(organizer.asBinder());
return organizerState != null return organizerState != null
? organizerState.mRemoteAnimationDefinitions.get(taskId) ? organizerState.mRemoteAnimationDefinition
: null; : null;
} }
} }
@@ -1085,16 +1082,7 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
return false; return false;
} }
final TaskFragment taskFragment = activity.getOrganizedTaskFragment(); final TaskFragment taskFragment = activity.getOrganizedTaskFragment();
if (taskFragment == null) { return taskFragment != null && taskFragment.isEmbeddedWithBoundsOverride();
return false;
}
final Task parentTask = taskFragment.getTask();
if (parentTask != null) {
final Rect taskBounds = parentTask.getBounds();
final Rect taskFragBounds = taskFragment.getBounds();
return !taskBounds.equals(taskFragBounds) && taskBounds.contains(taskFragBounds);
}
return false;
} }
} }

View File

@@ -25,6 +25,7 @@ import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION; import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
import static android.view.WindowManager.TRANSIT_CHANGE; import static android.view.WindowManager.TRANSIT_CHANGE;
import static android.view.WindowManager.TRANSIT_CLOSE; import static android.view.WindowManager.TRANSIT_CLOSE;
import static android.view.WindowManager.TRANSIT_OLD_ACTIVITY_CLOSE;
import static android.view.WindowManager.TRANSIT_OLD_ACTIVITY_OPEN; import static android.view.WindowManager.TRANSIT_OLD_ACTIVITY_OPEN;
import static android.view.WindowManager.TRANSIT_OLD_DREAM_ACTIVITY_CLOSE; import static android.view.WindowManager.TRANSIT_OLD_DREAM_ACTIVITY_CLOSE;
import static android.view.WindowManager.TRANSIT_OLD_DREAM_ACTIVITY_OPEN; import static android.view.WindowManager.TRANSIT_OLD_DREAM_ACTIVITY_OPEN;
@@ -56,6 +57,7 @@ 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.graphics.Rect;
import android.gui.DropInputMode; import android.gui.DropInputMode;
import android.os.Binder; import android.os.Binder;
import android.os.IBinder; import android.os.IBinder;
@@ -918,7 +920,7 @@ public class AppTransitionControllerTest extends WindowTestsBase {
final Task task = createTask(mDisplayContent); final Task task = createTask(mDisplayContent);
final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run); final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run);
final TestRemoteAnimationRunner remoteAnimationRunner = new TestRemoteAnimationRunner(); final TestRemoteAnimationRunner remoteAnimationRunner = new TestRemoteAnimationRunner();
setupTaskFragmentRemoteAnimation(organizer, task.mTaskId, remoteAnimationRunner); setupTaskFragmentRemoteAnimation(organizer, remoteAnimationRunner);
// Create a TaskFragment with embedded activity. // Create a TaskFragment with embedded activity.
final TaskFragment taskFragment = createTaskFragmentWithEmbeddedActivity(task, organizer); final TaskFragment taskFragment = createTaskFragmentWithEmbeddedActivity(task, organizer);
@@ -934,12 +936,78 @@ public class AppTransitionControllerTest extends WindowTestsBase {
assertTrue(remoteAnimationRunner.isAnimationStarted()); assertTrue(remoteAnimationRunner.isAnimationStarted());
} }
@Test
public void testOverrideTaskFragmentAdapter_noOverrideWithOnlyTaskFragmentFillingTask() {
final Task task = createTask(mDisplayContent);
final ActivityRecord closingActivity = createActivityRecord(task);
final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run);
final TestRemoteAnimationRunner remoteAnimationRunner = new TestRemoteAnimationRunner();
setupTaskFragmentRemoteAnimation(organizer, remoteAnimationRunner);
// Create a TaskFragment with embedded activity.
final TaskFragment taskFragment = createTaskFragmentWithEmbeddedActivity(task, organizer);
// Make sure the TaskFragment is not embedded.
assertFalse(taskFragment.isEmbeddedWithBoundsOverride());
final ActivityRecord openingActivity = taskFragment.getTopMostActivity();
prepareActivityForAppTransition(closingActivity);
prepareActivityForAppTransition(openingActivity);
final int uid = 12345;
closingActivity.info.applicationInfo.uid = uid;
openingActivity.info.applicationInfo.uid = uid;
task.effectiveUid = uid;
spyOn(mDisplayContent.mAppTransition);
// Prepare and start transition.
prepareAndTriggerAppTransition(openingActivity, closingActivity,
null /* changingTaskFragment */);
mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
// Animation is not run by the remote handler because the activity is filling the Task.
assertFalse(remoteAnimationRunner.isAnimationStarted());
}
@Test
public void testOverrideTaskFragmentAdapter_overrideWithTaskFragmentNotFillingTask() {
final Task task = createTask(mDisplayContent);
final ActivityRecord closingActivity = createActivityRecord(task);
final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run);
final TestRemoteAnimationRunner remoteAnimationRunner = new TestRemoteAnimationRunner();
setupTaskFragmentRemoteAnimation(organizer, remoteAnimationRunner);
// Create a TaskFragment with embedded activity.
final TaskFragment taskFragment = createTaskFragmentWithEmbeddedActivity(task, organizer);
// Make sure the TaskFragment is embedded.
taskFragment.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
final Rect embeddedBounds = new Rect(task.getBounds());
embeddedBounds.right = embeddedBounds.left + embeddedBounds.width() / 2;
taskFragment.setBounds(embeddedBounds);
assertTrue(taskFragment.isEmbeddedWithBoundsOverride());
final ActivityRecord openingActivity = taskFragment.getTopMostActivity();
prepareActivityForAppTransition(closingActivity);
prepareActivityForAppTransition(openingActivity);
final int uid = 12345;
closingActivity.info.applicationInfo.uid = uid;
openingActivity.info.applicationInfo.uid = uid;
task.effectiveUid = uid;
spyOn(mDisplayContent.mAppTransition);
// Prepare and start transition.
prepareAndTriggerAppTransition(openingActivity, closingActivity,
null /* changingTaskFragment */);
mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
// Animation run by the remote handler.
assertTrue(remoteAnimationRunner.isAnimationStarted());
}
@Test @Test
public void testOverrideTaskFragmentAdapter_overrideWithNonEmbeddedActivity() { public void testOverrideTaskFragmentAdapter_overrideWithNonEmbeddedActivity() {
final Task task = createTask(mDisplayContent); final Task task = createTask(mDisplayContent);
final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run); final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run);
final TestRemoteAnimationRunner remoteAnimationRunner = new TestRemoteAnimationRunner(); final TestRemoteAnimationRunner remoteAnimationRunner = new TestRemoteAnimationRunner();
setupTaskFragmentRemoteAnimation(organizer, task.mTaskId, remoteAnimationRunner); setupTaskFragmentRemoteAnimation(organizer, remoteAnimationRunner);
// Closing non-embedded activity. // Closing non-embedded activity.
final ActivityRecord closingActivity = createActivityRecord(task); final ActivityRecord closingActivity = createActivityRecord(task);
@@ -964,7 +1032,7 @@ public class AppTransitionControllerTest extends WindowTestsBase {
final Task task = createTask(mDisplayContent); final Task task = createTask(mDisplayContent);
final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run); final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run);
final TestRemoteAnimationRunner remoteAnimationRunner = new TestRemoteAnimationRunner(); final TestRemoteAnimationRunner remoteAnimationRunner = new TestRemoteAnimationRunner();
setupTaskFragmentRemoteAnimation(organizer, task.mTaskId, remoteAnimationRunner); setupTaskFragmentRemoteAnimation(organizer, remoteAnimationRunner);
// Closing TaskFragment with embedded activity. // Closing TaskFragment with embedded activity.
final TaskFragment taskFragment1 = createTaskFragmentWithEmbeddedActivity(task, organizer); final TaskFragment taskFragment1 = createTaskFragmentWithEmbeddedActivity(task, organizer);
@@ -991,7 +1059,7 @@ public class AppTransitionControllerTest extends WindowTestsBase {
final Task task = createTask(mDisplayContent); final Task task = createTask(mDisplayContent);
final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run); final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run);
final TestRemoteAnimationRunner remoteAnimationRunner = new TestRemoteAnimationRunner(); final TestRemoteAnimationRunner remoteAnimationRunner = new TestRemoteAnimationRunner();
setupTaskFragmentRemoteAnimation(organizer, task.mTaskId, remoteAnimationRunner); setupTaskFragmentRemoteAnimation(organizer, remoteAnimationRunner);
// Closing activity in Task1. // Closing activity in Task1.
final ActivityRecord closingActivity = createActivityRecord(mDisplayContent); final ActivityRecord closingActivity = createActivityRecord(mDisplayContent);
@@ -1015,7 +1083,7 @@ public class AppTransitionControllerTest extends WindowTestsBase {
final Task task = createTask(mDisplayContent); final Task task = createTask(mDisplayContent);
final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run); final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run);
final TestRemoteAnimationRunner remoteAnimationRunner = new TestRemoteAnimationRunner(); final TestRemoteAnimationRunner remoteAnimationRunner = new TestRemoteAnimationRunner();
setupTaskFragmentRemoteAnimation(organizer, task.mTaskId, remoteAnimationRunner); setupTaskFragmentRemoteAnimation(organizer, remoteAnimationRunner);
// Closing TaskFragment with embedded activity. // Closing TaskFragment with embedded activity.
final TaskFragment taskFragment = createTaskFragmentWithEmbeddedActivity(task, organizer); final TaskFragment taskFragment = createTaskFragmentWithEmbeddedActivity(task, organizer);
@@ -1043,7 +1111,7 @@ public class AppTransitionControllerTest extends WindowTestsBase {
final Task task = createTask(mDisplayContent); final Task task = createTask(mDisplayContent);
final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run); final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run);
final TestRemoteAnimationRunner remoteAnimationRunner = new TestRemoteAnimationRunner(); final TestRemoteAnimationRunner remoteAnimationRunner = new TestRemoteAnimationRunner();
setupTaskFragmentRemoteAnimation(organizer, task.mTaskId, remoteAnimationRunner); setupTaskFragmentRemoteAnimation(organizer, remoteAnimationRunner);
// Create a TaskFragment with embedded activity. // Create a TaskFragment with embedded activity.
final TaskFragment taskFragment = createTaskFragmentWithEmbeddedActivity(task, organizer); final TaskFragment taskFragment = createTaskFragmentWithEmbeddedActivity(task, organizer);
@@ -1069,7 +1137,7 @@ public class AppTransitionControllerTest extends WindowTestsBase {
final Task task = createTask(mDisplayContent); final Task task = createTask(mDisplayContent);
final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run); final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run);
final TestRemoteAnimationRunner remoteAnimationRunner = new TestRemoteAnimationRunner(); final TestRemoteAnimationRunner remoteAnimationRunner = new TestRemoteAnimationRunner();
setupTaskFragmentRemoteAnimation(organizer, task.mTaskId, remoteAnimationRunner); setupTaskFragmentRemoteAnimation(organizer, remoteAnimationRunner);
// Create a TaskFragment with embedded activities, one is trusted embedded, and the other // Create a TaskFragment with embedded activities, one is trusted embedded, and the other
// one is untrusted embedded. // one is untrusted embedded.
@@ -1128,7 +1196,7 @@ public class AppTransitionControllerTest extends WindowTestsBase {
final Task task = createTask(mDisplayContent); final Task task = createTask(mDisplayContent);
final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run); final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run);
final TestRemoteAnimationRunner remoteAnimationRunner = new TestRemoteAnimationRunner(); final TestRemoteAnimationRunner remoteAnimationRunner = new TestRemoteAnimationRunner();
setupTaskFragmentRemoteAnimation(organizer, task.mTaskId, remoteAnimationRunner); setupTaskFragmentRemoteAnimation(organizer, remoteAnimationRunner);
// Create a TaskFragment with only trusted embedded activity // Create a TaskFragment with only trusted embedded activity
final TaskFragment taskFragment = new TaskFragmentBuilder(mAtm) final TaskFragment taskFragment = new TaskFragmentBuilder(mAtm)
@@ -1168,7 +1236,7 @@ public class AppTransitionControllerTest extends WindowTestsBase {
final Task task = createTask(mDisplayContent); final Task task = createTask(mDisplayContent);
final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run); final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run);
final TestRemoteAnimationRunner remoteAnimationRunner = new TestRemoteAnimationRunner(); final TestRemoteAnimationRunner remoteAnimationRunner = new TestRemoteAnimationRunner();
setupTaskFragmentRemoteAnimation(organizer, task.mTaskId, remoteAnimationRunner); setupTaskFragmentRemoteAnimation(organizer, remoteAnimationRunner);
// Create a TaskFragment with only trusted embedded activity // Create a TaskFragment with only trusted embedded activity
final TaskFragment taskFragment = new TaskFragmentBuilder(mAtm) final TaskFragment taskFragment = new TaskFragmentBuilder(mAtm)
@@ -1259,7 +1327,7 @@ public class AppTransitionControllerTest extends WindowTestsBase {
} }
/** Registers remote animation for the organizer. */ /** Registers remote animation for the organizer. */
private void setupTaskFragmentRemoteAnimation(TaskFragmentOrganizer organizer, int taskId, private void setupTaskFragmentRemoteAnimation(TaskFragmentOrganizer organizer,
TestRemoteAnimationRunner remoteAnimationRunner) { TestRemoteAnimationRunner remoteAnimationRunner) {
final RemoteAnimationAdapter adapter = new RemoteAnimationAdapter( final RemoteAnimationAdapter adapter = new RemoteAnimationAdapter(
remoteAnimationRunner, 10, 1); remoteAnimationRunner, 10, 1);
@@ -1268,9 +1336,10 @@ public class AppTransitionControllerTest extends WindowTestsBase {
definition.addRemoteAnimation(TRANSIT_OLD_TASK_FRAGMENT_CHANGE, adapter); definition.addRemoteAnimation(TRANSIT_OLD_TASK_FRAGMENT_CHANGE, adapter);
definition.addRemoteAnimation(TRANSIT_OLD_TASK_FRAGMENT_OPEN, adapter); definition.addRemoteAnimation(TRANSIT_OLD_TASK_FRAGMENT_OPEN, adapter);
definition.addRemoteAnimation(TRANSIT_OLD_TASK_FRAGMENT_CLOSE, adapter); definition.addRemoteAnimation(TRANSIT_OLD_TASK_FRAGMENT_CLOSE, adapter);
definition.addRemoteAnimation(TRANSIT_OLD_ACTIVITY_OPEN, adapter);
definition.addRemoteAnimation(TRANSIT_OLD_ACTIVITY_CLOSE, adapter);
mAtm.mTaskFragmentOrganizerController.registerOrganizer(iOrganizer); mAtm.mTaskFragmentOrganizerController.registerOrganizer(iOrganizer);
mAtm.mTaskFragmentOrganizerController.registerRemoteAnimations(iOrganizer, taskId, mAtm.mTaskFragmentOrganizerController.registerRemoteAnimations(iOrganizer, definition);
definition);
} }
private static ITaskFragmentOrganizer getITaskFragmentOrganizer( private static ITaskFragmentOrganizer getITaskFragmentOrganizer(

View File

@@ -474,13 +474,13 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
@Test @Test
public void testRegisterRemoteAnimations() { public void testRegisterRemoteAnimations() {
mController.registerRemoteAnimations(mIOrganizer, TASK_ID, mDefinition); mController.registerRemoteAnimations(mIOrganizer, mDefinition);
assertEquals(mDefinition, mController.getRemoteAnimationDefinition(mIOrganizer, TASK_ID)); assertEquals(mDefinition, mController.getRemoteAnimationDefinition(mIOrganizer));
mController.unregisterRemoteAnimations(mIOrganizer, TASK_ID); mController.unregisterRemoteAnimations(mIOrganizer);
assertNull(mController.getRemoteAnimationDefinition(mIOrganizer, TASK_ID)); assertNull(mController.getRemoteAnimationDefinition(mIOrganizer));
} }
@Test @Test