diff options
| author | 2022-11-15 03:41:49 +0000 | |
|---|---|---|
| committer | 2022-11-15 03:41:49 +0000 | |
| commit | f90440ea43f5bd464c20e57974d4a1de4b758b98 (patch) | |
| tree | 1ad7498e1148f35789862903d8c73b60efd94367 | |
| parent | 02e36f349a14b0c3647a5234b68266992e1fb04b (diff) | |
| parent | 57e7d839cd18212f6187730165d453a61e2827fd (diff) | |
Merge "Fix ActivityEmbedding animation flicker" into tm-qpr-dev am: 4715d968c3 am: 57e7d839cd
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/20448947
Change-Id: I67a1ecc410dbdbed24ce0b6628b51f98c42be051
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
5 files changed, 126 insertions, 42 deletions
| diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java index 872542af0075..dfcad48046b0 100644 --- a/services/core/java/com/android/server/wm/TaskFragment.java +++ b/services/core/java/com/android/server/wm/TaskFragment.java @@ -291,6 +291,12 @@ class TaskFragment extends WindowContainer<WindowContainer> {      private final IBinder mFragmentToken;      /** +     * Whether to delay the call to {@link #updateOrganizedTaskFragmentSurface()} when there is a +     * configuration change. +     */ +    private boolean mDelayOrganizedTaskFragmentSurfaceUpdate; + +    /**       * Whether to delay the last activity of TaskFragment being immediately removed while finishing.       * This should only be set on a embedded TaskFragment, where the organizer can have the       * opportunity to perform animations and finishing the adjacent TaskFragment. @@ -2264,35 +2270,41 @@ class TaskFragment extends WindowContainer<WindowContainer> {      @Override      public void onConfigurationChanged(Configuration newParentConfig) { -        // Task will animate differently. -        if (mTaskFragmentOrganizer != null) { -            mTmpPrevBounds.set(getBounds()); -        } -          super.onConfigurationChanged(newParentConfig); -        final boolean shouldStartChangeTransition = shouldStartChangeTransition(mTmpPrevBounds); -        if (shouldStartChangeTransition) { -            initializeChangeTransition(mTmpPrevBounds); -        }          if (mTaskFragmentOrganizer != null) { -            if (mTransitionController.isShellTransitionsEnabled() -                    && !mTransitionController.isCollecting(this)) { -                // TaskFragmentOrganizer doesn't have access to the surface for security reasons, so -                // update the surface here if it is not collected by Shell transition. -                updateOrganizedTaskFragmentSurface(); -            } else if (!mTransitionController.isShellTransitionsEnabled() -                    && !shouldStartChangeTransition) { -                // Update the surface here instead of in the organizer so that we can make sure -                // it can be synced with the surface freezer for legacy app transition. -                updateOrganizedTaskFragmentSurface(); -            } +            updateOrganizedTaskFragmentSurface();          }          sendTaskFragmentInfoChanged();      } +    void deferOrganizedTaskFragmentSurfaceUpdate() { +        mDelayOrganizedTaskFragmentSurfaceUpdate = true; +    } + +    void continueOrganizedTaskFragmentSurfaceUpdate() { +        mDelayOrganizedTaskFragmentSurfaceUpdate = false; +        updateOrganizedTaskFragmentSurface(); +    } +      private void updateOrganizedTaskFragmentSurface() { +        if (mDelayOrganizedTaskFragmentSurfaceUpdate) { +            return; +        } +        if (mTransitionController.isShellTransitionsEnabled() +                && !mTransitionController.isCollecting(this)) { +            // TaskFragmentOrganizer doesn't have access to the surface for security reasons, so +            // update the surface here if it is not collected by Shell transition. +            updateOrganizedTaskFragmentSurfaceUnchecked(); +        } else if (!mTransitionController.isShellTransitionsEnabled() && !isAnimating()) { +            // Update the surface here instead of in the organizer so that we can make sure +            // it can be synced with the surface freezer for legacy app transition. +            updateOrganizedTaskFragmentSurfaceUnchecked(); +        } +    } + +    private void updateOrganizedTaskFragmentSurfaceUnchecked() {          final SurfaceControl.Transaction t = getSyncTransaction();          updateSurfacePosition(t);          updateOrganizedTaskFragmentSurfaceSize(t, false /* forceUpdate */); @@ -2346,7 +2358,7 @@ class TaskFragment extends WindowContainer<WindowContainer> {      }      /** Whether we should prepare a transition for this {@link TaskFragment} bounds change. */ -    private boolean shouldStartChangeTransition(Rect startBounds) { +    boolean shouldStartChangeTransition(Rect startBounds) {          if (mTaskFragmentOrganizer == null || !canStartChangeTransition()) {              return false;          } @@ -2366,7 +2378,7 @@ class TaskFragment extends WindowContainer<WindowContainer> {      void setSurfaceControl(SurfaceControl sc) {          super.setSurfaceControl(sc);          if (mTaskFragmentOrganizer != null) { -            updateOrganizedTaskFragmentSurface(); +            updateOrganizedTaskFragmentSurfaceUnchecked();              // If the TaskFragmentOrganizer was set before we created the SurfaceControl, we need to              // emit the callbacks now.              sendTaskFragmentAppeared(); diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java index 5760b77a0be4..de12a4ef7739 100644 --- a/services/core/java/com/android/server/wm/WindowOrganizerController.java +++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java @@ -145,6 +145,8 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub      @VisibleForTesting      final ArrayMap<IBinder, TaskFragment> mLaunchTaskFragments = new ArrayMap<>(); +    private final Rect mTmpBounds = new Rect(); +      WindowOrganizerController(ActivityTaskManagerService atm) {          mService = atm;          mGlobalLock = atm.mGlobalLock; @@ -703,7 +705,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub      }      private int applyTaskChanges(Task tr, WindowContainerTransaction.Change c) { -        int effects = 0; +        int effects = applyChanges(tr, c, null /* errorCallbackToken */);          final SurfaceControl.Transaction t = c.getBoundsChangeTransaction();          if ((c.getChangeMask() & WindowContainerTransaction.Change.CHANGE_HIDDEN) != 0) { @@ -764,6 +766,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub      private int applyDisplayAreaChanges(DisplayArea displayArea,              WindowContainerTransaction.Change c) {          final int[] effects = new int[1]; +        effects[0] = applyChanges(displayArea, c, null /* errorCallbackToken */);          if ((c.getChangeMask()                  & WindowContainerTransaction.Change.CHANGE_IGNORE_ORIENTATION_REQUEST) != 0) { @@ -784,6 +787,27 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub          return effects[0];      } +    private int applyTaskFragmentChanges(@NonNull TaskFragment taskFragment, +            @NonNull WindowContainerTransaction.Change c, @Nullable IBinder errorCallbackToken) { +        if (taskFragment.isEmbeddedTaskFragmentInPip()) { +            // No override from organizer for embedded TaskFragment in a PIP Task. +            return 0; +        } + +        // When the TaskFragment is resized, we may want to create a change transition for it, for +        // which we want to defer the surface update until we determine whether or not to start +        // change transition. +        mTmpBounds.set(taskFragment.getBounds()); +        taskFragment.deferOrganizedTaskFragmentSurfaceUpdate(); +        final int effects = applyChanges(taskFragment, c, errorCallbackToken); +        if (taskFragment.shouldStartChangeTransition(mTmpBounds)) { +            taskFragment.initializeChangeTransition(mTmpBounds); +        } +        taskFragment.continueOrganizedTaskFragmentSurfaceUpdate(); +        mTmpBounds.set(0, 0, 0, 0); +        return effects; +    } +      private int applyHierarchyOp(WindowContainerTransaction.HierarchyOp hop, int effects,              int syncId, @Nullable Transition transition, boolean isInLockTaskMode,              @NonNull CallerInfo caller, @Nullable IBinder errorCallbackToken, @@ -1449,20 +1473,15 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub      private int applyWindowContainerChange(WindowContainer wc,              WindowContainerTransaction.Change c, @Nullable IBinder errorCallbackToken) {          sanitizeWindowContainer(wc); -        if (wc.asTaskFragment() != null && wc.asTaskFragment().isEmbeddedTaskFragmentInPip()) { -            // No override from organizer for embedded TaskFragment in a PIP Task. -            return 0; -        } - -        int effects = applyChanges(wc, c, errorCallbackToken); - -        if (wc instanceof DisplayArea) { -            effects |= applyDisplayAreaChanges(wc.asDisplayArea(), c); -        } else if (wc instanceof Task) { -            effects |= applyTaskChanges(wc.asTask(), c); +        if (wc.asDisplayArea() != null) { +            return applyDisplayAreaChanges(wc.asDisplayArea(), c); +        } else if (wc.asTask() != null) { +            return applyTaskChanges(wc.asTask(), c); +        } else if (wc.asTaskFragment() != null) { +            return applyTaskFragmentChanges(wc.asTaskFragment(), c, errorCallbackToken); +        } else { +            return applyChanges(wc, c, errorCallbackToken);          } - -        return effects;      }      @Override diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index 5c5c70334e65..86dd0b5452b5 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -1540,10 +1540,11 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP              mWmService.makeWindowFreezingScreenIfNeededLocked(this);              // If the orientation is changing, or we're starting or ending a drag resizing action, -            // then we need to hold off on unfreezing the display until this window has been -            // redrawn; to do that, we need to go through the process of getting informed by the -            // application when it has finished drawing. -            if (getOrientationChanging() || dragResizingChanged) { +            // or we're resizing an embedded Activity, then we need to hold off on unfreezing the +            // display until this window has been redrawn; to do that, we need to go through the +            // process of getting informed by the application when it has finished drawing. +            if (getOrientationChanging() || dragResizingChanged +                    || isEmbeddedActivityResizeChanged()) {                  if (dragResizingChanged) {                      ProtoLog.v(WM_DEBUG_RESIZE,                              "Resize start waiting for draw, " @@ -4160,6 +4161,20 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP          return mActivityRecord == null || mActivityRecord.isFullyTransparentBarAllowed(frame);      } +    /** +     * Whether this window belongs to a resizing embedded activity. +     */ +    private boolean isEmbeddedActivityResizeChanged() { +        if (mActivityRecord == null || !isVisibleRequested()) { +            // No need to update if the window is in the background. +            return false; +        } + +        final TaskFragment embeddedTaskFragment = mActivityRecord.getOrganizedTaskFragment(); +        return embeddedTaskFragment != null +                && mDisplayContent.mChangingContainers.contains(embeddedTaskFragment); +    } +      boolean isDragResizeChanged() {          return mDragResizing != computeDragResizing();      } diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java index 83f17897eb62..3ff2c0e0d024 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java @@ -118,10 +118,13 @@ public class TaskFragmentTest extends WindowTestsBase {          doReturn(true).when(mTaskFragment).isVisibleRequested();          clearInvocations(mTransaction); +        mTaskFragment.deferOrganizedTaskFragmentSurfaceUpdate();          mTaskFragment.setBounds(endBounds); +        assertTrue(mTaskFragment.shouldStartChangeTransition(startBounds)); +        mTaskFragment.initializeChangeTransition(startBounds); +        mTaskFragment.continueOrganizedTaskFragmentSurfaceUpdate();          // Surface reset when prepare transition. -        verify(mTaskFragment).initializeChangeTransition(startBounds);          verify(mTransaction).setPosition(mLeash, 0, 0);          verify(mTransaction).setWindowCrop(mLeash, 0, 0); @@ -166,7 +169,7 @@ public class TaskFragmentTest extends WindowTestsBase {          mTaskFragment.setBounds(endBounds); -        verify(mTaskFragment, never()).initializeChangeTransition(any()); +        assertFalse(mTaskFragment.shouldStartChangeTransition(startBounds));      }      /** diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java index 6bd341210cad..1b888f629251 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java @@ -95,6 +95,8 @@ import android.view.InsetsSource;  import android.view.InsetsState;  import android.view.SurfaceControl;  import android.view.WindowManager; +import android.window.ITaskFragmentOrganizer; +import android.window.TaskFragmentOrganizer;  import androidx.test.filters.SmallTest; @@ -800,6 +802,39 @@ public class WindowStateTests extends WindowTestsBase {      }      @Test +    public void testEmbeddedActivityResizing_clearAllDrawn() { +        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 WindowState win = createWindow(null /* parent */, TYPE_APPLICATION, embeddedActivity, +                "App window"); +        doReturn(true).when(embeddedActivity).isVisible(); +        embeddedActivity.mVisibleRequested = true; +        makeWindowVisible(win); +        win.mLayoutSeq = win.getDisplayContent().mLayoutSeq; +        // Set the bounds twice: +        // 1. To make sure there is no orientation change after #reportResized, which can also cause +        // #clearAllDrawn. +        // 2. Make #isLastConfigReportedToClient to be false after #reportResized, so it can process +        // to check if we need redraw. +        embeddedTf.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW); +        embeddedTf.setBounds(0, 0, 1000, 2000); +        win.reportResized(); +        embeddedTf.setBounds(500, 0, 1000, 2000); + +        // Clear all drawn when the embedded TaskFragment is in mDisplayContent.mChangingContainers. +        win.updateResizingWindowIfNeeded(); +        verify(embeddedActivity, never()).clearAllDrawn(); + +        mDisplayContent.mChangingContainers.add(embeddedTf); +        win.updateResizingWindowIfNeeded(); +        verify(embeddedActivity).clearAllDrawn(); +    } + +    @Test      public void testCantReceiveTouchWhenAppTokenHiddenRequested() {          final WindowState win0 = createWindow(null, TYPE_APPLICATION, "win0");          win0.mActivityRecord.mVisibleRequested = false; |