summaryrefslogtreecommitdiff
path: root/libs
diff options
context:
space:
mode:
Diffstat (limited to 'libs')
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizer.java23
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java1
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java5
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationAdapter.java224
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationController.java79
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationRunner.java309
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationSpec.java267
-rw-r--r--libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizerTest.java20
-rw-r--r--libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskFragmentAnimationControllerTest.java88
9 files changed, 0 insertions, 1016 deletions
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizer.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizer.java
index 9ea2943bc6da..1eb95c1efb08 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizer.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizer.java
@@ -70,10 +70,6 @@ class JetpackTaskFragmentOrganizer extends TaskFragmentOrganizer {
@NonNull
private final TaskFragmentCallback mCallback;
- @VisibleForTesting
- @Nullable
- TaskFragmentAnimationController mAnimationController;
-
/**
* Callback that notifies the controller about changes to task fragments.
*/
@@ -91,25 +87,6 @@ class JetpackTaskFragmentOrganizer extends TaskFragmentOrganizer {
mCallback = callback;
}
- @Override
- public void unregisterOrganizer() {
- if (mAnimationController != null) {
- mAnimationController.unregisterRemoteAnimations();
- mAnimationController = null;
- }
- super.unregisterOrganizer();
- }
-
- /**
- * Overrides the animation for transitions of embedded activities organized by this organizer.
- */
- void overrideSplitAnimation() {
- if (mAnimationController == null) {
- mAnimationController = new TaskFragmentAnimationController(this);
- }
- mAnimationController.registerRemoteAnimations();
- }
-
/**
* Starts a new Activity and puts it into split with an existing Activity side-by-side.
* @param launchingFragmentToken token for the launching TaskFragment. If it exists, it will
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
index 7ddda1f98809..3261a370d2ca 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
@@ -114,7 +114,6 @@ import java.util.function.BiConsumer;
public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmentCallback,
ActivityEmbeddingComponent, DividerPresenter.DragEventCallback {
static final String TAG = "SplitController";
- static final boolean ENABLE_SHELL_TRANSITIONS = true;
// TODO(b/243518738): Move to WM Extensions if we have requirement of overlay without
// association. It's not set in WM Extensions nor Wm Jetpack library currently.
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java
index eb1fc23d6b00..ea60b1531a3f 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java
@@ -166,11 +166,6 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer {
mWindowLayoutComponent = windowLayoutComponent;
mController = controller;
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();
- }
}
/**
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationAdapter.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationAdapter.java
deleted file mode 100644
index 33220c44a3b5..000000000000
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationAdapter.java
+++ /dev/null
@@ -1,224 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.window.extensions.embedding;
-
-import static android.graphics.Matrix.MTRANS_X;
-import static android.graphics.Matrix.MTRANS_Y;
-import static android.view.RemoteAnimationTarget.MODE_CLOSING;
-
-import android.graphics.Point;
-import android.graphics.Rect;
-import android.view.Choreographer;
-import android.view.RemoteAnimationTarget;
-import android.view.SurfaceControl;
-import android.view.animation.Animation;
-import android.view.animation.Transformation;
-
-import androidx.annotation.NonNull;
-
-/**
- * Wrapper to handle the TaskFragment animation update in one {@link SurfaceControl.Transaction}.
- *
- * The base adapter can be used for {@link RemoteAnimationTarget} that is simple open/close.
- */
-class TaskFragmentAnimationAdapter {
-
- /**
- * If {@link #mOverrideLayer} is set to this value, we don't want to override the surface layer.
- */
- private static final int LAYER_NO_OVERRIDE = -1;
-
- @NonNull
- final Animation mAnimation;
- @NonNull
- final RemoteAnimationTarget mTarget;
- @NonNull
- final SurfaceControl mLeash;
- /** Area in absolute coordinate that the animation surface shouldn't go beyond. */
- @NonNull
- private final Rect mWholeAnimationBounds = new Rect();
- /**
- * Area in absolute coordinate that should represent all the content to show for this window.
- * This should be the end bounds for opening window, and start bounds for closing window in case
- * the window is resizing during the open/close transition.
- */
- @NonNull
- private final Rect mContentBounds = new Rect();
- /** Offset relative to the window parent surface for {@link #mContentBounds}. */
- @NonNull
- private final Point mContentRelOffset = new Point();
-
- @NonNull
- final Transformation mTransformation = new Transformation();
- @NonNull
- final float[] mMatrix = new float[9];
- @NonNull
- final float[] mVecs = new float[4];
- @NonNull
- final Rect mRect = new Rect();
- private boolean mIsFirstFrame = true;
- private int mOverrideLayer = LAYER_NO_OVERRIDE;
-
- TaskFragmentAnimationAdapter(@NonNull Animation animation,
- @NonNull RemoteAnimationTarget target) {
- this(animation, target, target.leash, target.screenSpaceBounds);
- }
-
- /**
- * @param leash the surface to animate.
- * @param wholeAnimationBounds area in absolute coordinate that the animation surface shouldn't
- * go beyond.
- */
- TaskFragmentAnimationAdapter(@NonNull Animation animation,
- @NonNull RemoteAnimationTarget target, @NonNull SurfaceControl leash,
- @NonNull Rect wholeAnimationBounds) {
- mAnimation = animation;
- mTarget = target;
- mLeash = leash;
- mWholeAnimationBounds.set(wholeAnimationBounds);
- if (target.mode == MODE_CLOSING) {
- // When it is closing, we want to show the content at the start position in case the
- // window is resizing as well. For example, when the activities is changing from split
- // to stack, the bottom TaskFragment will be resized to fullscreen when hiding.
- final Rect startBounds = target.startBounds;
- final Rect endBounds = target.screenSpaceBounds;
- mContentBounds.set(startBounds);
- mContentRelOffset.set(target.localBounds.left, target.localBounds.top);
- mContentRelOffset.offset(
- startBounds.left - endBounds.left,
- startBounds.top - endBounds.top);
- } else {
- mContentBounds.set(target.screenSpaceBounds);
- mContentRelOffset.set(target.localBounds.left, target.localBounds.top);
- }
- }
-
- /**
- * Surface layer to be set at the first frame of the animation. We will not set the layer if it
- * is set to {@link #LAYER_NO_OVERRIDE}.
- */
- final void overrideLayer(int layer) {
- mOverrideLayer = layer;
- }
-
- /** Called on frame update. */
- final void onAnimationUpdate(@NonNull SurfaceControl.Transaction t, long currentPlayTime) {
- if (mIsFirstFrame) {
- t.show(mLeash);
- if (mOverrideLayer != LAYER_NO_OVERRIDE) {
- t.setLayer(mLeash, mOverrideLayer);
- }
- mIsFirstFrame = false;
- }
-
- // Extract the transformation to the current time.
- mAnimation.getTransformation(Math.min(currentPlayTime, mAnimation.getDuration()),
- mTransformation);
- t.setFrameTimelineVsync(Choreographer.getInstance().getVsyncId());
- onAnimationUpdateInner(t);
- }
-
- /** To be overridden by subclasses to adjust the animation surface change. */
- void onAnimationUpdateInner(@NonNull SurfaceControl.Transaction t) {
- // Update the surface position and alpha.
- mTransformation.getMatrix().postTranslate(mContentRelOffset.x, mContentRelOffset.y);
- t.setMatrix(mLeash, mTransformation.getMatrix(), mMatrix);
- t.setAlpha(mLeash, mTransformation.getAlpha());
-
- // Get current surface bounds in absolute coordinate.
- // positionX/Y are in local coordinate, so minus the local offset to get the slide amount.
- final int positionX = Math.round(mMatrix[MTRANS_X]);
- final int positionY = Math.round(mMatrix[MTRANS_Y]);
- final Rect cropRect = new Rect(mContentBounds);
- cropRect.offset(positionX - mContentRelOffset.x, positionY - mContentRelOffset.y);
-
- // Store the current offset of the surface top left from (0,0) in absolute coordinate.
- final int offsetX = cropRect.left;
- final int offsetY = cropRect.top;
-
- // Intersect to make sure the animation happens within the whole animation bounds.
- if (!cropRect.intersect(mWholeAnimationBounds)) {
- // Hide the surface when it is outside of the animation area.
- t.setAlpha(mLeash, 0);
- }
-
- // cropRect is in absolute coordinate, so we need to translate it to surface top left.
- cropRect.offset(-offsetX, -offsetY);
- t.setCrop(mLeash, cropRect);
- }
-
- /** Called after animation finished. */
- final void onAnimationEnd(@NonNull SurfaceControl.Transaction t) {
- onAnimationUpdate(t, mAnimation.getDuration());
- }
-
- final long getDurationHint() {
- return mAnimation.computeDurationHint();
- }
-
- /**
- * Should be used for the animation of the snapshot of a {@link RemoteAnimationTarget} that has
- * size change.
- */
- static class SnapshotAdapter extends TaskFragmentAnimationAdapter {
-
- SnapshotAdapter(@NonNull Animation animation, @NonNull RemoteAnimationTarget target) {
- // Start leash is the snapshot of the starting surface.
- super(animation, target, target.startLeash, target.screenSpaceBounds);
- }
-
- @Override
- void onAnimationUpdateInner(@NonNull SurfaceControl.Transaction t) {
- // Snapshot should always be placed at the top left of the animation leash.
- mTransformation.getMatrix().postTranslate(0, 0);
- t.setMatrix(mLeash, mTransformation.getMatrix(), mMatrix);
- t.setAlpha(mLeash, mTransformation.getAlpha());
- }
- }
-
- /**
- * Should be used for the animation of the {@link RemoteAnimationTarget} that has size change.
- */
- static class BoundsChangeAdapter extends TaskFragmentAnimationAdapter {
-
- BoundsChangeAdapter(@NonNull Animation animation, @NonNull RemoteAnimationTarget target) {
- super(animation, target);
- }
-
- @Override
- void onAnimationUpdateInner(@NonNull SurfaceControl.Transaction t) {
- mTransformation.getMatrix().postTranslate(
- mTarget.localBounds.left, mTarget.localBounds.top);
- t.setMatrix(mLeash, mTransformation.getMatrix(), mMatrix);
- t.setAlpha(mLeash, mTransformation.getAlpha());
-
- // The following applies an inverse scale to the clip-rect so that it crops "after" the
- // scale instead of before.
- mVecs[1] = mVecs[2] = 0;
- mVecs[0] = mVecs[3] = 1;
- mTransformation.getMatrix().mapVectors(mVecs);
- mVecs[0] = 1.f / mVecs[0];
- mVecs[3] = 1.f / mVecs[3];
- final Rect clipRect = mTransformation.getClipRect();
- mRect.left = (int) (clipRect.left * mVecs[0] + 0.5f);
- mRect.right = (int) (clipRect.right * mVecs[0] + 0.5f);
- mRect.top = (int) (clipRect.top * mVecs[3] + 0.5f);
- mRect.bottom = (int) (clipRect.bottom * mVecs[3] + 0.5f);
- t.setWindowCrop(mLeash, mRect);
- }
- }
-}
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationController.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationController.java
deleted file mode 100644
index d7eb9a01f57c..000000000000
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationController.java
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.window.extensions.embedding;
-
-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_TASK_FRAGMENT_CHANGE;
-import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_CLOSE;
-import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_OPEN;
-
-import android.util.Log;
-import android.view.RemoteAnimationAdapter;
-import android.view.RemoteAnimationDefinition;
-import android.window.TaskFragmentOrganizer;
-
-import androidx.annotation.NonNull;
-
-import com.android.internal.annotations.VisibleForTesting;
-
-/** Controls the TaskFragment remote animations. */
-class TaskFragmentAnimationController {
-
- private static final String TAG = "TaskFragAnimationCtrl";
- static final boolean DEBUG = false;
-
- private final TaskFragmentOrganizer mOrganizer;
- private final TaskFragmentAnimationRunner mRemoteRunner = new TaskFragmentAnimationRunner();
- @VisibleForTesting
- final RemoteAnimationDefinition mDefinition;
- private boolean mIsRegistered;
-
- TaskFragmentAnimationController(@NonNull TaskFragmentOrganizer organizer) {
- mOrganizer = organizer;
- mDefinition = new RemoteAnimationDefinition();
- final RemoteAnimationAdapter animationAdapter =
- new RemoteAnimationAdapter(mRemoteRunner, 0, 0, true /* changeNeedsSnapshot */);
- mDefinition.addRemoteAnimation(TRANSIT_OLD_ACTIVITY_OPEN, animationAdapter);
- mDefinition.addRemoteAnimation(TRANSIT_OLD_TASK_FRAGMENT_OPEN, animationAdapter);
- mDefinition.addRemoteAnimation(TRANSIT_OLD_ACTIVITY_CLOSE, animationAdapter);
- mDefinition.addRemoteAnimation(TRANSIT_OLD_TASK_FRAGMENT_CLOSE, animationAdapter);
- mDefinition.addRemoteAnimation(TRANSIT_OLD_TASK_FRAGMENT_CHANGE, animationAdapter);
- }
-
- void registerRemoteAnimations() {
- if (DEBUG) {
- Log.v(TAG, "registerRemoteAnimations");
- }
- if (mIsRegistered) {
- return;
- }
- mOrganizer.registerRemoteAnimations(mDefinition);
- mIsRegistered = true;
- }
-
- void unregisterRemoteAnimations() {
- if (DEBUG) {
- Log.v(TAG, "unregisterRemoteAnimations");
- }
- if (!mIsRegistered) {
- return;
- }
- mOrganizer.unregisterRemoteAnimations();
- mIsRegistered = false;
- }
-}
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationRunner.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationRunner.java
deleted file mode 100644
index d9b73a8290f5..000000000000
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationRunner.java
+++ /dev/null
@@ -1,309 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.window.extensions.embedding;
-
-import static android.os.Process.THREAD_PRIORITY_DISPLAY;
-import static android.view.RemoteAnimationTarget.MODE_CHANGING;
-import static android.view.RemoteAnimationTarget.MODE_CLOSING;
-import static android.view.RemoteAnimationTarget.MODE_OPENING;
-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_TASK_FRAGMENT_CHANGE;
-import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_CLOSE;
-import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_OPEN;
-import static android.view.WindowManagerPolicyConstants.TYPE_LAYER_OFFSET;
-
-import android.animation.Animator;
-import android.animation.ValueAnimator;
-import android.graphics.Rect;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.RemoteException;
-import android.util.Log;
-import android.view.IRemoteAnimationFinishedCallback;
-import android.view.IRemoteAnimationRunner;
-import android.view.RemoteAnimationTarget;
-import android.view.SurfaceControl;
-import android.view.WindowManager;
-import android.view.animation.Animation;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.function.BiFunction;
-
-/** To run the TaskFragment animations. */
-class TaskFragmentAnimationRunner extends IRemoteAnimationRunner.Stub {
-
- private static final String TAG = "TaskFragAnimationRunner";
- private final Handler mHandler;
- private final TaskFragmentAnimationSpec mAnimationSpec;
-
- TaskFragmentAnimationRunner() {
- HandlerThread animationThread = new HandlerThread(
- "androidx.window.extensions.embedding", THREAD_PRIORITY_DISPLAY);
- animationThread.start();
- mHandler = animationThread.getThreadHandler();
- mAnimationSpec = new TaskFragmentAnimationSpec(mHandler);
- }
-
- @Nullable
- private Animator mAnimator;
-
- @Override
- public void onAnimationStart(@WindowManager.TransitionOldType int transit,
- @NonNull RemoteAnimationTarget[] apps,
- @NonNull RemoteAnimationTarget[] wallpapers,
- @NonNull RemoteAnimationTarget[] nonApps,
- @NonNull IRemoteAnimationFinishedCallback finishedCallback) {
- if (wallpapers.length != 0 || nonApps.length != 0) {
- throw new IllegalArgumentException("TaskFragment shouldn't handle animation with"
- + "wallpaper or non-app windows.");
- }
- if (TaskFragmentAnimationController.DEBUG) {
- Log.v(TAG, "onAnimationStart transit=" + transit);
- }
- mHandler.post(() -> startAnimation(transit, apps, finishedCallback));
- }
-
- @Override
- public void onAnimationCancelled() {
- mHandler.post(this::cancelAnimation);
- }
-
- /** Creates and starts animation. */
- private void startAnimation(@WindowManager.TransitionOldType int transit,
- @NonNull RemoteAnimationTarget[] targets,
- @NonNull IRemoteAnimationFinishedCallback finishedCallback) {
- if (mAnimator != null) {
- Log.w(TAG, "start new animation when the previous one is not finished yet.");
- mAnimator.cancel();
- }
- mAnimator = createAnimator(transit, targets, finishedCallback);
- mAnimator.start();
- }
-
- /** Cancels animation. */
- private void cancelAnimation() {
- if (mAnimator == null) {
- return;
- }
- mAnimator.cancel();
- mAnimator = null;
- }
-
- /** Creates the animator given the transition type and windows. */
- @NonNull
- private Animator createAnimator(@WindowManager.TransitionOldType int transit,
- @NonNull RemoteAnimationTarget[] targets,
- @NonNull IRemoteAnimationFinishedCallback finishedCallback) {
- final List<TaskFragmentAnimationAdapter> adapters =
- createAnimationAdapters(transit, targets);
- long duration = 0;
- for (TaskFragmentAnimationAdapter adapter : adapters) {
- duration = Math.max(duration, adapter.getDurationHint());
- }
- final ValueAnimator animator = ValueAnimator.ofFloat(0, 1);
- animator.setDuration(duration);
- animator.addUpdateListener((anim) -> {
- // Update all adapters in the same transaction.
- final SurfaceControl.Transaction t = new SurfaceControl.Transaction();
- for (TaskFragmentAnimationAdapter adapter : adapters) {
- adapter.onAnimationUpdate(t, animator.getCurrentPlayTime());
- }
- t.apply();
- });
- animator.addListener(new Animator.AnimatorListener() {
- @Override
- public void onAnimationStart(Animator animation) {}
-
- @Override
- public void onAnimationEnd(Animator animation) {
- final SurfaceControl.Transaction t = new SurfaceControl.Transaction();
- for (TaskFragmentAnimationAdapter adapter : adapters) {
- adapter.onAnimationEnd(t);
- }
- t.apply();
-
- try {
- finishedCallback.onAnimationFinished();
- } catch (RemoteException e) {
- e.rethrowFromSystemServer();
- }
- mAnimator = null;
- }
-
- @Override
- public void onAnimationCancel(Animator animation) {}
-
- @Override
- public void onAnimationRepeat(Animator animation) {}
- });
- return animator;
- }
-
- /** List of {@link TaskFragmentAnimationAdapter} to handle animations on all window targets. */
- @NonNull
- private List<TaskFragmentAnimationAdapter> createAnimationAdapters(
- @WindowManager.TransitionOldType int transit,
- @NonNull RemoteAnimationTarget[] targets) {
- switch (transit) {
- case TRANSIT_OLD_ACTIVITY_OPEN:
- case TRANSIT_OLD_TASK_FRAGMENT_OPEN:
- return createOpenAnimationAdapters(targets);
- case TRANSIT_OLD_ACTIVITY_CLOSE:
- case TRANSIT_OLD_TASK_FRAGMENT_CLOSE:
- return createCloseAnimationAdapters(targets);
- case TRANSIT_OLD_TASK_FRAGMENT_CHANGE:
- return createChangeAnimationAdapters(targets);
- default:
- throw new IllegalArgumentException("Unhandled transit type=" + transit);
- }
- }
-
- @NonNull
- private List<TaskFragmentAnimationAdapter> createOpenAnimationAdapters(
- @NonNull RemoteAnimationTarget[] targets) {
- return createOpenCloseAnimationAdapters(targets, true /* isOpening */,
- mAnimationSpec::loadOpenAnimation);
- }
-
- @NonNull
- private List<TaskFragmentAnimationAdapter> createCloseAnimationAdapters(
- @NonNull RemoteAnimationTarget[] targets) {
- return createOpenCloseAnimationAdapters(targets, false /* isOpening */,
- mAnimationSpec::loadCloseAnimation);
- }
-
- /**
- * Creates {@link TaskFragmentAnimationAdapter} for OPEN and CLOSE types of transition.
- * @param isOpening {@code true} for OPEN type, {@code false} for CLOSE type.
- */
- @NonNull
- private List<TaskFragmentAnimationAdapter> createOpenCloseAnimationAdapters(
- @NonNull RemoteAnimationTarget[] targets, boolean isOpening,
- @NonNull BiFunction<RemoteAnimationTarget, Rect, Animation> animationProvider) {
- // We need to know if the target window is only a partial of the whole animation screen.
- // If so, we will need to adjust it to make the whole animation screen looks like one.
- final List<RemoteAnimationTarget> openingTargets = new ArrayList<>();
- final List<RemoteAnimationTarget> closingTargets = new ArrayList<>();
- final Rect openingWholeScreenBounds = new Rect();
- final Rect closingWholeScreenBounds = new Rect();
- for (RemoteAnimationTarget target : targets) {
- if (target.mode != MODE_CLOSING) {
- openingTargets.add(target);
- openingWholeScreenBounds.union(target.screenSpaceBounds);
- } else {
- closingTargets.add(target);
- closingWholeScreenBounds.union(target.screenSpaceBounds);
- // Union the start bounds since this may be the ClosingChanging animation.
- closingWholeScreenBounds.union(target.startBounds);
- }
- }
-
- // For OPEN transition, open windows should be above close windows.
- // For CLOSE transition, open windows should be below close windows.
- int offsetLayer = TYPE_LAYER_OFFSET;
- final List<TaskFragmentAnimationAdapter> adapters = new ArrayList<>();
- for (RemoteAnimationTarget target : openingTargets) {
- final TaskFragmentAnimationAdapter adapter = createOpenCloseAnimationAdapter(target,
- animationProvider, openingWholeScreenBounds);
- if (isOpening) {
- adapter.overrideLayer(offsetLayer++);
- }
- adapters.add(adapter);
- }
- for (RemoteAnimationTarget target : closingTargets) {
- final TaskFragmentAnimationAdapter adapter = createOpenCloseAnimationAdapter(target,
- animationProvider, closingWholeScreenBounds);
- if (!isOpening) {
- adapter.overrideLayer(offsetLayer++);
- }
- adapters.add(adapter);
- }
- return adapters;
- }
-
- @NonNull
- private TaskFragmentAnimationAdapter createOpenCloseAnimationAdapter(
- @NonNull RemoteAnimationTarget target,
- @NonNull BiFunction<RemoteAnimationTarget, Rect, Animation> animationProvider,
- @NonNull Rect wholeAnimationBounds) {
- final Animation animation = animationProvider.apply(target, wholeAnimationBounds);
- return new TaskFragmentAnimationAdapter(animation, target, target.leash,
- wholeAnimationBounds);
- }
-
- @NonNull
- private List<TaskFragmentAnimationAdapter> createChangeAnimationAdapters(
- @NonNull RemoteAnimationTarget[] targets) {
- if (shouldUseJumpCutForChangeAnimation(targets)) {
- return new ArrayList<>();
- }
-
- final List<TaskFragmentAnimationAdapter> adapters = new ArrayList<>();
- for (RemoteAnimationTarget target : targets) {
- if (target.mode == MODE_CHANGING) {
- // This is the target with bounds change.
- final Animation[] animations =
- mAnimationSpec.createChangeBoundsChangeAnimations(target);
- // Adapter for the starting snapshot leash.
- adapters.add(new TaskFragmentAnimationAdapter.SnapshotAdapter(
- animations[0], target));
- // Adapter for the ending bounds changed leash.
- adapters.add(new TaskFragmentAnimationAdapter.BoundsChangeAdapter(
- animations[1], target));
- continue;
- }
-
- // These are the other targets that don't have bounds change in the same transition.
- final Animation animation;
- if (target.hasAnimatingParent) {
- // No-op if it will be covered by the changing parent window.
- animation = TaskFragmentAnimationSpec.createNoopAnimation(target);
- } else if (target.mode == MODE_CLOSING) {
- animation = mAnimationSpec.createChangeBoundsCloseAnimation(target);
- } else {
- animation = mAnimationSpec.createChangeBoundsOpenAnimation(target);
- }
- adapters.add(new TaskFragmentAnimationAdapter(animation, target));
- }
- return adapters;
- }
-
- /**
- * Whether we should use jump cut for the change transition.
- * This normally happens when opening a new secondary with the existing primary using a
- * different split layout. This can be complicated, like from horizontal to vertical split with
- * new split pairs.
- * Uses a jump cut animation to simplify.
- */
- private boolean shouldUseJumpCutForChangeAnimation(@NonNull RemoteAnimationTarget[] targets) {
- boolean hasOpeningWindow = false;
- boolean hasClosingWindow = false;
- for (RemoteAnimationTarget target : targets) {
- if (target.hasAnimatingParent) {
- continue;
- }
- hasOpeningWindow |= target.mode == MODE_OPENING;
- hasClosingWindow |= target.mode == MODE_CLOSING;
- }
- return hasOpeningWindow && hasClosingWindow;
- }
-}
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationSpec.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationSpec.java
deleted file mode 100644
index 1f866c3b99c9..000000000000
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationSpec.java
+++ /dev/null
@@ -1,267 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.window.extensions.embedding;
-
-import static android.view.RemoteAnimationTarget.MODE_CLOSING;
-
-import android.app.ActivityThread;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.database.ContentObserver;
-import android.graphics.Rect;
-import android.os.Handler;
-import android.provider.Settings;
-import android.view.RemoteAnimationTarget;
-import android.view.WindowManager;
-import android.view.animation.AlphaAnimation;
-import android.view.animation.Animation;
-import android.view.animation.AnimationSet;
-import android.view.animation.AnimationUtils;
-import android.view.animation.ClipRectAnimation;
-import android.view.animation.Interpolator;
-import android.view.animation.LinearInterpolator;
-import android.view.animation.ScaleAnimation;
-import android.view.animation.TranslateAnimation;
-
-import androidx.annotation.NonNull;
-
-import com.android.internal.R;
-import com.android.internal.policy.AttributeCache;
-import com.android.internal.policy.TransitionAnimation;
-
-/** Animation spec for TaskFragment transition. */
-// TODO(b/206557124): provide an easier way to customize animation
-class TaskFragmentAnimationSpec {
-
- private static final String TAG = "TaskFragAnimationSpec";
- private static final int CHANGE_ANIMATION_DURATION = 517;
- private static final int CHANGE_ANIMATION_FADE_DURATION = 80;
- private static final int CHANGE_ANIMATION_FADE_OFFSET = 30;
-
- private final Context mContext;
- private final TransitionAnimation mTransitionAnimation;
- private final Interpolator mFastOutExtraSlowInInterpolator;
- private final LinearInterpolator mLinearInterpolator;
- private float mTransitionAnimationScaleSetting;
-
- TaskFragmentAnimationSpec(@NonNull Handler handler) {
- mContext = ActivityThread.currentActivityThread().getApplication();
- mTransitionAnimation = new TransitionAnimation(mContext, false /* debug */, TAG);
- // Initialize the AttributeCache for the TransitionAnimation.
- AttributeCache.init(mContext);
- mFastOutExtraSlowInInterpolator = AnimationUtils.loadInterpolator(
- mContext, android.R.interpolator.fast_out_extra_slow_in);
- mLinearInterpolator = new LinearInterpolator();
-
- // The transition animation should be adjusted based on the developer option.
- final ContentResolver resolver = mContext.getContentResolver();
- mTransitionAnimationScaleSetting = getTransitionAnimationScaleSetting();
- resolver.registerContentObserver(
- Settings.Global.getUriFor(Settings.Global.TRANSITION_ANIMATION_SCALE), false,
- new SettingsObserver(handler));
- }
-
- /** For target that doesn't need to be animated. */
- @NonNull
- static Animation createNoopAnimation(@NonNull RemoteAnimationTarget target) {
- // Noop but just keep the target showing/hiding.
- final float alpha = target.mode == MODE_CLOSING ? 0f : 1f;
- return new AlphaAnimation(alpha, alpha);
- }
-
- /** Animation for target that is opening in a change transition. */
- @NonNull
- Animation createChangeBoundsOpenAnimation(@NonNull RemoteAnimationTarget target) {
- final Rect parentBounds = target.taskInfo.configuration.windowConfiguration.getBounds();
- final Rect bounds = target.screenSpaceBounds;
- final int startLeft;
- final int startTop;
- if (parentBounds.top == bounds.top && parentBounds.bottom == bounds.bottom) {
- // The window will be animated in from left or right depending on its position.
- startTop = 0;
- startLeft = parentBounds.left == bounds.left ? -bounds.width() : bounds.width();
- } else {
- // The window will be animated in from top or bottom depending on its position.
- startTop = parentBounds.top == bounds.top ? -bounds.height() : bounds.height();
- startLeft = 0;
- }
-
- // The position should be 0-based as we will post translate in
- // TaskFragmentAnimationAdapter#onAnimationUpdate
- final Animation animation = new TranslateAnimation(startLeft, 0, startTop, 0);
- animation.setInterpolator(mFastOutExtraSlowInInterpolator);
- animation.setDuration(CHANGE_ANIMATION_DURATION);
- animation.initialize(bounds.width(), bounds.height(), bounds.width(), bounds.height());
- animation.scaleCurrentDuration(mTransitionAnimationScaleSetting);
- return animation;
- }
-
- /** Animation for target that is closing in a change transition. */
- @NonNull
- Animation createChangeBoundsCloseAnimation(@NonNull RemoteAnimationTarget target) {
- final Rect parentBounds = target.taskInfo.configuration.windowConfiguration.getBounds();
- // Use startBounds if the window is closing in case it may also resize.
- final Rect bounds = target.startBounds;
- final int endTop;
- final int endLeft;
- if (parentBounds.top == bounds.top && parentBounds.bottom == bounds.bottom) {
- // The window will be animated out to left or right depending on its position.
- endTop = 0;
- endLeft = parentBounds.left == bounds.left ? -bounds.width() : bounds.width();
- } else {
- // The window will be animated out to top or bottom depending on its position.
- endTop = parentBounds.top == bounds.top ? -bounds.height() : bounds.height();
- endLeft = 0;
- }
-
- // The position should be 0-based as we will post translate in
- // TaskFragmentAnimationAdapter#onAnimationUpdate
- final Animation animation = new TranslateAnimation(0, endLeft, 0, endTop);
- animation.setInterpolator(mFastOutExtraSlowInInterpolator);
- animation.setDuration(CHANGE_ANIMATION_DURATION);
- animation.initialize(bounds.width(), bounds.height(), bounds.width(), bounds.height());
- animation.scaleCurrentDuration(mTransitionAnimationScaleSetting);
- return animation;
- }
-
- /**
- * Animation for target that is changing (bounds change) in a change transition.
- * @return the return array always has two elements. The first one is for the start leash, and
- * the second one is for the end leash.
- */
- @NonNull
- Animation[] createChangeBoundsChangeAnimations(@NonNull RemoteAnimationTarget target) {
- // Both start bounds and end bounds are in screen coordinates. We will post translate
- // to the local coordinates in TaskFragmentAnimationAdapter#onAnimationUpdate
- final Rect startBounds = target.startBounds;
- final Rect parentBounds = target.taskInfo.configuration.windowConfiguration.getBounds();
- final Rect endBounds = target.screenSpaceBounds;
- float scaleX = ((float) startBounds.width()) / endBounds.width();
- float scaleY = ((float) startBounds.height()) / endBounds.height();
- // Start leash is a child of the end leash. Reverse the scale so that the start leash won't
- // be scaled up with its parent.
- float startScaleX = 1.f / scaleX;
- float startScaleY = 1.f / scaleY;
-
- // The start leash will be fade out.
- final AnimationSet startSet = new AnimationSet(false /* shareInterpolator */);
- final Animation startAlpha = new AlphaAnimation(1f, 0f);
- startAlpha.setInterpolator(mLinearInterpolator);
- startAlpha.setDuration(CHANGE_ANIMATION_FADE_DURATION);
- startAlpha.setStartOffset(CHANGE_ANIMATION_FADE_OFFSET);
- startSet.addAnimation(startAlpha);
- final Animation startScale = new ScaleAnimation(startScaleX, startScaleX, startScaleY,
- startScaleY);
- startScale.setInterpolator(mFastOutExtraSlowInInterpolator);
- startScale.setDuration(CHANGE_ANIMATION_DURATION);
- startSet.addAnimation(startScale);
- startSet.initialize(startBounds.width(), startBounds.height(), endBounds.width(),
- endBounds.height());
- startSet.scaleCurrentDuration(mTransitionAnimationScaleSetting);
-
- // The end leash will be moved into the end position while scaling.
- final AnimationSet endSet = new AnimationSet(true /* shareInterpolator */);
- endSet.setInterpolator(mFastOutExtraSlowInInterpolator);
- final Animation endScale = new ScaleAnimation(scaleX, 1, scaleY, 1);
- endScale.setDuration(CHANGE_ANIMATION_DURATION);
- endSet.addAnimation(endScale);
- // The position should be 0-based as we will post translate in
- // TaskFragmentAnimationAdapter#onAnimationUpdate
- final Animation endTranslate = new TranslateAnimation(startBounds.left - endBounds.left, 0,
- startBounds.top - endBounds.top, 0);
- endTranslate.setDuration(CHANGE_ANIMATION_DURATION);
- endSet.addAnimation(endTranslate);
- // The end leash is resizing, we should update the window crop based on the clip rect.
- final Rect startClip = new Rect(startBounds);
- final Rect endClip = new Rect(endBounds);
- startClip.offsetTo(0, 0);
- endClip.offsetTo(0, 0);
- final Animation clipAnim = new ClipRectAnimation(startClip, endClip);
- clipAnim.setDuration(CHANGE_ANIMATION_DURATION);
- endSet.addAnimation(clipAnim);
- endSet.initialize(startBounds.width(), startBounds.height(), parentBounds.width(),
- parentBounds.height());
- endSet.scaleCurrentDuration(mTransitionAnimationScaleSetting);
-
- return new Animation[]{startSet, endSet};
- }
-
- @NonNull
- Animation loadOpenAnimation(@NonNull RemoteAnimationTarget target,
- @NonNull Rect wholeAnimationBounds) {
- final boolean isEnter = target.mode != MODE_CLOSING;
- final Animation animation;
- // Background color on TaskDisplayArea has already been set earlier in
- // WindowContainer#getAnimationAdapter.
- if (target.showBackdrop) {
- animation = mTransitionAnimation.loadDefaultAnimationRes(isEnter
- ? com.android.internal.R.anim.task_fragment_clear_top_open_enter
- : com.android.internal.R.anim.task_fragment_clear_top_open_exit);
- } else {
- animation = mTransitionAnimation.loadDefaultAnimationRes(isEnter
- ? com.android.internal.R.anim.task_fragment_open_enter
- : com.android.internal.R.anim.task_fragment_open_exit);
- }
- // Use the whole animation bounds instead of the change bounds, so that when multiple change
- // targets are opening at the same time, the animation applied to each will be the same.
- // Otherwise, we may see gap between the activities that are launching together.
- animation.initialize(wholeAnimationBounds.width(), wholeAnimationBounds.height(),
- wholeAnimationBounds.width(), wholeAnimationBounds.height());
- animation.scaleCurrentDuration(mTransitionAnimationScaleSetting);
- return animation;
- }
-
- @NonNull
- Animation loadCloseAnimation(@NonNull RemoteAnimationTarget target,
- @NonNull Rect wholeAnimationBounds) {
- final boolean isEnter = target.mode != MODE_CLOSING;
- final Animation animation;
- if (target.showBackdrop) {
- animation = mTransitionAnimation.loadDefaultAnimationRes(isEnter
- ? com.android.internal.R.anim.task_fragment_clear_top_close_enter
- : com.android.internal.R.anim.task_fragment_clear_top_close_exit);
- } else {
- animation = mTransitionAnimation.loadDefaultAnimationRes(isEnter
- ? com.android.internal.R.anim.task_fragment_close_enter
- : com.android.internal.R.anim.task_fragment_close_exit);
- }
- // Use the whole animation bounds instead of the change bounds, so that when multiple change
- // targets are closing at the same time, the animation applied to each will be the same.
- // Otherwise, we may see gap between the activities that are finishing together.
- animation.initialize(wholeAnimationBounds.width(), wholeAnimationBounds.height(),
- wholeAnimationBounds.width(), wholeAnimationBounds.height());
- animation.scaleCurrentDuration(mTransitionAnimationScaleSetting);
- return animation;
- }
-
- private float getTransitionAnimationScaleSetting() {
- return WindowManager.fixScale(Settings.Global.getFloat(mContext.getContentResolver(),
- Settings.Global.TRANSITION_ANIMATION_SCALE, mContext.getResources().getFloat(
- R.dimen.config_appTransitionAnimationDurationScaleDefault)));
- }
-
- private class SettingsObserver extends ContentObserver {
- SettingsObserver(@NonNull Handler handler) {
- super(handler);
- }
-
- @Override
- public void onChange(boolean selfChange) {
- mTransitionAnimationScaleSetting = getTransitionAnimationScaleSetting();
- }
- }
-}
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizerTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizerTest.java
index 7b473b04548c..ad41b18dcbc6 100644
--- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizerTest.java
+++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizerTest.java
@@ -23,8 +23,6 @@ import static androidx.window.extensions.embedding.EmbeddingTestUtils.createTest
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
@@ -86,24 +84,6 @@ public class JetpackTaskFragmentOrganizerTest {
}
@Test
- public void testUnregisterOrganizer() {
- mOrganizer.overrideSplitAnimation();
- mOrganizer.unregisterOrganizer();
-
- verify(mOrganizer).unregisterRemoteAnimations();
- }
-
- @Test
- public void testOverrideSplitAnimation() {
- assertNull(mOrganizer.mAnimationController);
-
- mOrganizer.overrideSplitAnimation();
-
- assertNotNull(mOrganizer.mAnimationController);
- verify(mOrganizer).registerRemoteAnimations(mOrganizer.mAnimationController.mDefinition);
- }
-
- @Test
public void testExpandTaskFragment() {
final TaskContainer taskContainer = createTestTaskContainer();
doReturn(taskContainer).when(mSplitController).getTaskContainer(anyInt());
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskFragmentAnimationControllerTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskFragmentAnimationControllerTest.java
deleted file mode 100644
index a1e9f08585f6..000000000000
--- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskFragmentAnimationControllerTest.java
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.window.extensions.embedding;
-
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
-
-import static org.mockito.Mockito.never;
-
-import android.platform.test.annotations.Presubmit;
-import android.window.TaskFragmentOrganizer;
-
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import androidx.test.filters.SmallTest;
-
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.junit.MockitoJUnit;
-import org.mockito.junit.MockitoRule;
-
-/**
- * Test class for {@link TaskFragmentAnimationController}.
- *
- * Build/Install/Run:
- * atest WMJetpackUnitTests:TaskFragmentAnimationControllerTest
- */
-@Presubmit
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class TaskFragmentAnimationControllerTest {
- @Rule
- public MockitoRule rule = MockitoJUnit.rule();
-
- @Mock
- private TaskFragmentOrganizer mOrganizer;
- private TaskFragmentAnimationController mAnimationController;
-
- @Before
- public void setup() {
- mAnimationController = new TaskFragmentAnimationController(mOrganizer);
- }
-
- @Test
- public void testRegisterRemoteAnimations() {
- mAnimationController.registerRemoteAnimations();
-
- verify(mOrganizer).registerRemoteAnimations(mAnimationController.mDefinition);
-
- mAnimationController.registerRemoteAnimations();
-
- // No extra call if it has been registered.
- verify(mOrganizer).registerRemoteAnimations(mAnimationController.mDefinition);
- }
-
- @Test
- public void testUnregisterRemoteAnimations() {
- mAnimationController.unregisterRemoteAnimations();
-
- // No call if it is not registered.
- verify(mOrganizer, never()).unregisterRemoteAnimations();
-
- mAnimationController.registerRemoteAnimations();
- mAnimationController.unregisterRemoteAnimations();
-
- verify(mOrganizer).unregisterRemoteAnimations();
-
- mAnimationController.unregisterRemoteAnimations();
-
- // No extra call if it has been unregistered.
- verify(mOrganizer).unregisterRemoteAnimations();
- }
-}