diff options
Diffstat (limited to 'libs')
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(); - } -} |