Merge "Accept occluded closing non-embedded change for embedded transition" into udc-dev

This commit is contained in:
Riddle Hsu
2023-04-13 02:03:27 +00:00
committed by Android (Google) Code Review
3 changed files with 68 additions and 9 deletions

View File

@@ -22,6 +22,7 @@ import static android.window.TransitionInfo.FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY;
import static java.util.Objects.requireNonNull;
import android.content.Context;
import android.graphics.Rect;
import android.os.IBinder;
import android.util.ArrayMap;
import android.view.SurfaceControl;
@@ -35,6 +36,9 @@ import androidx.annotation.Nullable;
import com.android.internal.annotations.VisibleForTesting;
import com.android.wm.shell.sysui.ShellInit;
import com.android.wm.shell.transition.Transitions;
import com.android.wm.shell.util.TransitionUtil;
import java.util.List;
/**
* Responsible for handling ActivityEmbedding related transitions.
@@ -86,12 +90,13 @@ public class ActivityEmbeddingController implements Transitions.TransitionHandle
@NonNull SurfaceControl.Transaction finishTransaction,
@NonNull Transitions.TransitionFinishCallback finishCallback) {
boolean containsEmbeddingSplit = false;
for (TransitionInfo.Change change : info.getChanges()) {
boolean containsNonEmbeddedChange = false;
final List<TransitionInfo.Change> changes = info.getChanges();
for (int i = changes.size() - 1; i >= 0; i--) {
final TransitionInfo.Change change = changes.get(i);
if (!change.hasFlags(FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY)) {
// Only animate the transition if all changes are in a Task with ActivityEmbedding.
return false;
}
if (!containsEmbeddingSplit && !change.hasFlags(FLAG_FILLS_TASK)) {
containsNonEmbeddedChange = true;
} else if (!change.hasFlags(FLAG_FILLS_TASK)) {
// Whether the Task contains any ActivityEmbedding split before or after the
// transition.
containsEmbeddingSplit = true;
@@ -103,6 +108,9 @@ public class ActivityEmbeddingController implements Transitions.TransitionHandle
// such as the device is in a folded state.
return false;
}
if (containsNonEmbeddedChange && !handleNonEmbeddedChanges(changes)) {
return false;
}
// Start ActivityEmbedding animation.
mTransitionCallbacks.put(transition, finishCallback);
@@ -110,6 +118,37 @@ public class ActivityEmbeddingController implements Transitions.TransitionHandle
return true;
}
private boolean handleNonEmbeddedChanges(List<TransitionInfo.Change> changes) {
final Rect nonClosingEmbeddedArea = new Rect();
for (int i = changes.size() - 1; i >= 0; i--) {
final TransitionInfo.Change change = changes.get(i);
if (!TransitionUtil.isClosingType(change.getMode())) {
if (change.hasFlags(FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY)) {
nonClosingEmbeddedArea.union(change.getEndAbsBounds());
continue;
}
// Not able to handle non-embedded container if it is not closing.
return false;
}
}
for (int i = changes.size() - 1; i >= 0; i--) {
final TransitionInfo.Change change = changes.get(i);
if (!change.hasFlags(FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY)
&& !nonClosingEmbeddedArea.contains(change.getEndAbsBounds())) {
// Unknown to animate containers outside the area of embedded activities.
return false;
}
}
// Drop the non-embedded closing change because it is occluded by embedded activities.
for (int i = changes.size() - 1; i >= 0; i--) {
final TransitionInfo.Change change = changes.get(i);
if (!change.hasFlags(FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY)) {
changes.remove(i);
}
}
return true;
}
@Nullable
@Override
public WindowContainerTransaction handleRequest(@NonNull IBinder transition,

View File

@@ -16,6 +16,7 @@
package com.android.wm.shell.activityembedding;
import static android.view.WindowManager.TRANSIT_CLOSE;
import static android.view.WindowManager.TRANSIT_OPEN;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.never;
@@ -82,10 +83,13 @@ public class ActivityEmbeddingControllerTests extends ActivityEmbeddingAnimation
@Test
public void testStartAnimation_containsNonActivityEmbeddingChange() {
final TransitionInfo.Change nonEmbeddedOpen = createChange(0 /* flags */);
final TransitionInfo.Change embeddedOpen = createEmbeddedChange(
EMBEDDED_LEFT_BOUNDS, EMBEDDED_LEFT_BOUNDS, TASK_BOUNDS);
nonEmbeddedOpen.setMode(TRANSIT_OPEN);
final TransitionInfo info = new TransitionInfoBuilder(TRANSIT_OPEN, 0)
.addChange(createEmbeddedChange(
EMBEDDED_LEFT_BOUNDS, EMBEDDED_LEFT_BOUNDS, TASK_BOUNDS))
.addChange(createChange(0 /* flags */))
.addChange(embeddedOpen)
.addChange(nonEmbeddedOpen)
.build();
// No-op because it contains non-embedded change.
@@ -95,6 +99,22 @@ public class ActivityEmbeddingControllerTests extends ActivityEmbeddingAnimation
verifyNoMoreInteractions(mStartTransaction);
verifyNoMoreInteractions(mFinishTransaction);
verifyNoMoreInteractions(mFinishCallback);
final TransitionInfo.Change nonEmbeddedClose = createChange(0 /* flags */);
nonEmbeddedClose.setMode(TRANSIT_CLOSE);
nonEmbeddedClose.setEndAbsBounds(TASK_BOUNDS);
final TransitionInfo.Change embeddedOpen2 = createEmbeddedChange(
EMBEDDED_RIGHT_BOUNDS, EMBEDDED_RIGHT_BOUNDS, TASK_BOUNDS);
final TransitionInfo info2 = new TransitionInfoBuilder(TRANSIT_OPEN, 0)
.addChange(embeddedOpen)
.addChange(embeddedOpen2)
.addChange(nonEmbeddedClose)
.build();
// Ok to animate because nonEmbeddedClose is occluded by embeddedOpen and embeddedOpen2.
assertTrue(mController.startAnimation(mTransition, info2, mStartTransaction,
mFinishTransaction, mFinishCallback));
// The non-embedded change is dropped to avoid affecting embedded animation.
assertFalse(info2.getChanges().contains(nonEmbeddedClose));
}
@Test

View File

@@ -2835,7 +2835,7 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {
final String name = isDisplayRotation ? "RotationLayer" : "transition snapshot: " + wc;
SurfaceControl snapshotSurface = wc.makeAnimationLeash()
.setName(name)
.setOpaque(true)
.setOpaque(wc.fillsParent())
.setParent(wc.getSurfaceControl())
.setSecure(screenshotBuffer.containsSecureLayers())
.setCallsite("Transition.ScreenshotSync")