Merge "Show bg color during ActivityEmbedding change anim with Shell transition" into tm-qpr-dev
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunner.java b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunner.java
index 490975c..921861a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunner.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunner.java
@@ -303,6 +303,7 @@
         // 3. Animate the TaskFragment using Activity Change info (start/end bounds).
         // This is because the TaskFragment surface/change won't contain the Activity's before its
         // reparent.
+        Animation changeAnimation = null;
         for (TransitionInfo.Change change : info.getChanges()) {
             if (change.getMode() != TRANSIT_CHANGE
                     || change.getStartAbsBounds().equals(change.getEndAbsBounds())) {
@@ -325,8 +326,14 @@
                 }
             }
 
+            // There are two animations in the array. The first one is for the start leash
+            // (snapshot), and the second one is for the end leash (TaskFragment).
             final Animation[] animations = mAnimationSpec.createChangeBoundsChangeAnimations(change,
                     boundsAnimationChange.getEndAbsBounds());
+            // Keep track as we might need to add background color for the animation.
+            // Although there may be multiple change animation, record one of them is sufficient
+            // because the background color will be added to the root leash for the whole animation.
+            changeAnimation = animations[1];
 
             // Create a screenshot based on change, but attach it to the top of the
             // boundsAnimationChange.
@@ -345,6 +352,9 @@
                     animations[1], boundsAnimationChange));
         }
 
+        // If there is no corresponding open/close window with the change, we should show background
+        // color to cover the empty part of the screen.
+        boolean shouldShouldBackgroundColor = true;
         // Handle the other windows that don't have bounds change in the same transition.
         for (TransitionInfo.Change change : info.getChanges()) {
             if (handledChanges.contains(change)) {
@@ -359,11 +369,20 @@
                 animation = ActivityEmbeddingAnimationSpec.createNoopAnimation(change);
             } else if (Transitions.isClosingType(change.getMode())) {
                 animation = mAnimationSpec.createChangeBoundsCloseAnimation(change);
+                shouldShouldBackgroundColor = false;
             } else {
                 animation = mAnimationSpec.createChangeBoundsOpenAnimation(change);
+                shouldShouldBackgroundColor = false;
             }
             adapters.add(new ActivityEmbeddingAnimationAdapter(animation, change));
         }
+
+        if (shouldShouldBackgroundColor && changeAnimation != null) {
+            // Change animation may leave part of the screen empty. Show background color to cover
+            // that.
+            changeAnimation.setShowBackdrop(true);
+        }
+
         return adapters;
     }
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationSpec.java b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationSpec.java
index 58b2366..2bb7369 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationSpec.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationSpec.java
@@ -158,7 +158,7 @@
         // The position should be 0-based as we will post translate in
         // ActivityEmbeddingAnimationAdapter#onAnimationUpdate
         final Animation endTranslate = new TranslateAnimation(startBounds.left - endBounds.left, 0,
-                0, 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.
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index 46253c1..32f6197 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -1602,7 +1602,11 @@
             change.setMode(info.getTransitMode(target));
             change.setStartAbsBounds(info.mAbsoluteBounds);
             change.setFlags(info.getChangeFlags(target));
+
             final Task task = target.asTask();
+            final TaskFragment taskFragment = target.asTaskFragment();
+            final ActivityRecord activityRecord = target.asActivityRecord();
+
             if (task != null) {
                 final ActivityManager.RunningTaskInfo tinfo = new ActivityManager.RunningTaskInfo();
                 task.fillTaskInfo(tinfo);
@@ -1636,12 +1640,7 @@
             change.setEndRelOffset(bounds.left - parentBounds.left,
                     bounds.top - parentBounds.top);
             int endRotation = target.getWindowConfiguration().getRotation();
-            final ActivityRecord activityRecord = target.asActivityRecord();
             if (activityRecord != null) {
-                final Task arTask = activityRecord.getTask();
-                final int backgroundColor = ColorUtils.setAlphaComponent(
-                        arTask.getTaskDescription().getBackgroundColor(), 255);
-                change.setBackgroundColor(backgroundColor);
                 // TODO(b/227427984): Shell needs to aware letterbox.
                 // Always use parent bounds of activity because letterbox area (e.g. fixed aspect
                 // ratio or size compat mode) should be included in the animation.
@@ -1654,6 +1653,18 @@
             } else {
                 change.setEndAbsBounds(bounds);
             }
+
+            if (activityRecord != null || (taskFragment != null && taskFragment.isEmbedded())) {
+                // Set background color to Task theme color for activity and embedded TaskFragment
+                // in case we want to show background during the animation.
+                final Task parentTask = activityRecord != null
+                        ? activityRecord.getTask()
+                        : taskFragment.getTask();
+                final int backgroundColor = ColorUtils.setAlphaComponent(
+                        parentTask.getTaskDescription().getBackgroundColor(), 255);
+                change.setBackgroundColor(backgroundColor);
+            }
+
             change.setRotation(info.mRotation, endRotation);
             if (info.mSnapshot != null) {
                 change.setSnapshot(info.mSnapshot, info.mSnapshotLuma);
diff --git a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
index 9fd0850..66e46a2 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
@@ -59,7 +59,9 @@
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 
+import android.app.ActivityManager;
 import android.content.res.Configuration;
+import android.graphics.Color;
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.os.IBinder;
@@ -79,6 +81,8 @@
 import androidx.annotation.NonNull;
 import androidx.test.filters.SmallTest;
 
+import com.android.internal.graphics.ColorUtils;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
@@ -1384,6 +1388,50 @@
     }
 
     @Test
+    public void testChangeSetBackgroundColor() {
+        final Transition transition = createTestTransition(TRANSIT_CHANGE);
+        final ArrayMap<WindowContainer, Transition.ChangeInfo> changes = transition.mChanges;
+        final ArraySet<WindowContainer> participants = transition.mParticipants;
+
+        // Test background color for Activity and embedded TaskFragment.
+        final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run);
+        mAtm.mTaskFragmentOrganizerController.registerOrganizer(
+                ITaskFragmentOrganizer.Stub.asInterface(organizer.getOrganizerToken().asBinder()));
+        final Task task = createTask(mDisplayContent);
+        final TaskFragment embeddedTf = createTaskFragmentWithEmbeddedActivity(task, organizer);
+        final ActivityRecord embeddedActivity = embeddedTf.getTopMostActivity();
+        final ActivityRecord nonEmbeddedActivity = createActivityRecord(task);
+        final ActivityManager.TaskDescription taskDescription =
+                new ActivityManager.TaskDescription.Builder()
+                        .setBackgroundColor(Color.YELLOW)
+                        .build();
+        task.setTaskDescription(taskDescription);
+
+        // Start states:
+        embeddedActivity.mVisibleRequested = true;
+        nonEmbeddedActivity.mVisibleRequested = false;
+        changes.put(embeddedTf, new Transition.ChangeInfo(embeddedTf));
+        changes.put(nonEmbeddedActivity, new Transition.ChangeInfo(nonEmbeddedActivity));
+        // End states:
+        embeddedActivity.mVisibleRequested = false;
+        nonEmbeddedActivity.mVisibleRequested = true;
+
+        participants.add(embeddedTf);
+        participants.add(nonEmbeddedActivity);
+        final ArrayList<WindowContainer> targets = Transition.calculateTargets(
+                participants, changes);
+        final TransitionInfo info = Transition.calculateTransitionInfo(transition.mType,
+                0 /* flags */, targets, changes, mMockT);
+
+        // Background color should be set on both Activity and embedded TaskFragment.
+        final int expectedBackgroundColor = ColorUtils.setAlphaComponent(
+                taskDescription.getBackgroundColor(), 255);
+        assertEquals(2, info.getChanges().size());
+        assertEquals(expectedBackgroundColor, info.getChanges().get(0).getBackgroundColor());
+        assertEquals(expectedBackgroundColor, info.getChanges().get(1).getBackgroundColor());
+    }
+
+    @Test
     public void testTransitionVisibleChange() {
         registerTestTransitionPlayer();
         final ActivityRecord app = createActivityRecord(mDisplayContent);