Merge "Fix ActivityEmbedding animation with new split in different layout" into tm-qpr-dev
This commit is contained in:
@@ -19,6 +19,7 @@ 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;
|
||||
@@ -253,6 +254,10 @@ class TaskFragmentAnimationRunner extends IRemoteAnimationRunner.Stub {
|
||||
@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) {
|
||||
@@ -282,4 +287,24 @@ class TaskFragmentAnimationRunner extends IRemoteAnimationRunner.Stub {
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package com.android.wm.shell.activityembedding;
|
||||
|
||||
import static android.view.WindowManager.TRANSIT_CHANGE;
|
||||
import static android.view.WindowManager.TRANSIT_CLOSE;
|
||||
import static android.view.WindowManagerPolicyConstants.TYPE_LAYER_OFFSET;
|
||||
import static android.window.TransitionInfo.FLAG_IS_BEHIND_STARTING_WINDOW;
|
||||
|
||||
@@ -112,23 +113,30 @@ class ActivityEmbeddingAnimationRunner {
|
||||
@NonNull List<Consumer<SurfaceControl.Transaction>> postStartTransactionCallbacks) {
|
||||
final List<ActivityEmbeddingAnimationAdapter> adapters = createAnimationAdapters(info,
|
||||
startTransaction);
|
||||
addEdgeExtensionIfNeeded(startTransaction, finishTransaction, postStartTransactionCallbacks,
|
||||
adapters);
|
||||
addBackgroundColorIfNeeded(info, startTransaction, finishTransaction, adapters);
|
||||
long duration = 0;
|
||||
for (ActivityEmbeddingAnimationAdapter 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();
|
||||
long duration = 0;
|
||||
if (adapters.isEmpty()) {
|
||||
// Jump cut
|
||||
// No need to modify the animator, but to update the startTransaction with the changes'
|
||||
// ending states.
|
||||
prepareForJumpCut(info, startTransaction);
|
||||
} else {
|
||||
addEdgeExtensionIfNeeded(startTransaction, finishTransaction,
|
||||
postStartTransactionCallbacks, adapters);
|
||||
addBackgroundColorIfNeeded(info, startTransaction, finishTransaction, adapters);
|
||||
for (ActivityEmbeddingAnimationAdapter adapter : adapters) {
|
||||
adapter.onAnimationUpdate(t, animator.getCurrentPlayTime());
|
||||
duration = Math.max(duration, adapter.getDurationHint());
|
||||
}
|
||||
t.apply();
|
||||
});
|
||||
animator.addUpdateListener((anim) -> {
|
||||
// Update all adapters in the same transaction.
|
||||
final SurfaceControl.Transaction t = new SurfaceControl.Transaction();
|
||||
for (ActivityEmbeddingAnimationAdapter adapter : adapters) {
|
||||
adapter.onAnimationUpdate(t, animator.getCurrentPlayTime());
|
||||
}
|
||||
t.apply();
|
||||
});
|
||||
}
|
||||
animator.setDuration(duration);
|
||||
animator.addListener(new Animator.AnimatorListener() {
|
||||
@Override
|
||||
public void onAnimationStart(Animator animation) {}
|
||||
@@ -292,6 +300,10 @@ class ActivityEmbeddingAnimationRunner {
|
||||
@NonNull
|
||||
private List<ActivityEmbeddingAnimationAdapter> createChangeAnimationAdapters(
|
||||
@NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction startTransaction) {
|
||||
if (shouldUseJumpCutForChangeTransition(info)) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
final List<ActivityEmbeddingAnimationAdapter> adapters = new ArrayList<>();
|
||||
final Set<TransitionInfo.Change> handledChanges = new ArraySet<>();
|
||||
|
||||
@@ -374,9 +386,11 @@ class ActivityEmbeddingAnimationRunner {
|
||||
}
|
||||
|
||||
final Animation animation;
|
||||
if (change.getParent() != null
|
||||
&& handledChanges.contains(info.getChange(change.getParent()))) {
|
||||
// No-op if it will be covered by the changing parent window.
|
||||
if ((change.getParent() != null
|
||||
&& handledChanges.contains(info.getChange(change.getParent())))
|
||||
|| change.getMode() == TRANSIT_CHANGE) {
|
||||
// No-op if it will be covered by the changing parent window, or it is a changing
|
||||
// window without bounds change.
|
||||
animation = ActivityEmbeddingAnimationSpec.createNoopAnimation(change);
|
||||
} else if (Transitions.isClosingType(change.getMode())) {
|
||||
animation = mAnimationSpec.createChangeBoundsCloseAnimation(change, parentBounds);
|
||||
@@ -421,6 +435,74 @@ class ActivityEmbeddingAnimationRunner {
|
||||
animationChange.getLeash(), cropBounds, Integer.MAX_VALUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 shouldUseJumpCutForChangeTransition(@NonNull TransitionInfo info) {
|
||||
// There can be reparenting of changing Activity to new open TaskFragment, so we need to
|
||||
// exclude both in the first iteration.
|
||||
final List<TransitionInfo.Change> changingChanges = new ArrayList<>();
|
||||
for (TransitionInfo.Change change : info.getChanges()) {
|
||||
if (change.getMode() != TRANSIT_CHANGE
|
||||
|| change.getStartAbsBounds().equals(change.getEndAbsBounds())) {
|
||||
continue;
|
||||
}
|
||||
changingChanges.add(change);
|
||||
final WindowContainerToken parentToken = change.getParent();
|
||||
if (parentToken != null) {
|
||||
// When the parent window is also included in the transition as an opening window,
|
||||
// we would like to animate the parent window instead.
|
||||
final TransitionInfo.Change parentChange = info.getChange(parentToken);
|
||||
if (parentChange != null && Transitions.isOpeningType(parentChange.getMode())) {
|
||||
changingChanges.add(parentChange);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (changingChanges.isEmpty()) {
|
||||
// No changing target found.
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check if the transition contains both opening and closing windows.
|
||||
boolean hasOpeningWindow = false;
|
||||
boolean hasClosingWindow = false;
|
||||
for (TransitionInfo.Change change : info.getChanges()) {
|
||||
if (changingChanges.contains(change)) {
|
||||
continue;
|
||||
}
|
||||
if (change.getParent() != null
|
||||
&& changingChanges.contains(info.getChange(change.getParent()))) {
|
||||
// No-op if it will be covered by the changing parent window.
|
||||
continue;
|
||||
}
|
||||
hasOpeningWindow |= Transitions.isOpeningType(change.getMode());
|
||||
hasClosingWindow |= Transitions.isClosingType(change.getMode());
|
||||
}
|
||||
return hasOpeningWindow && hasClosingWindow;
|
||||
}
|
||||
|
||||
/** Updates the changes to end states in {@code startTransaction} for jump cut animation. */
|
||||
private void prepareForJumpCut(@NonNull TransitionInfo info,
|
||||
@NonNull SurfaceControl.Transaction startTransaction) {
|
||||
for (TransitionInfo.Change change : info.getChanges()) {
|
||||
final SurfaceControl leash = change.getLeash();
|
||||
startTransaction.setPosition(leash,
|
||||
change.getEndRelOffset().x, change.getEndRelOffset().y);
|
||||
startTransaction.setWindowCrop(leash,
|
||||
change.getEndAbsBounds().width(), change.getEndAbsBounds().height());
|
||||
if (change.getMode() == TRANSIT_CLOSE) {
|
||||
startTransaction.hide(leash);
|
||||
} else {
|
||||
startTransaction.show(leash);
|
||||
startTransaction.setAlpha(leash, 1f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** To provide an {@link Animation} based on the transition infos. */
|
||||
private interface AnimationProvider {
|
||||
Animation get(@NonNull TransitionInfo info, @NonNull TransitionInfo.Change change,
|
||||
|
||||
Reference in New Issue
Block a user