Set client invisible immediately for trampoline with window

Since shell transition moves "commit invisible" from transition
ready to transition finish. The relayout from a invisible-requested
client may still enter WindowState#relayoutVisibleWindow because
it is still client-visible.

If the client is a trampoline activity, then it will draw an
unnecessary frame because the client considers it needs to report
draw complete for the first traversal.

The flow:
1. Start activity A
   - Assume there is a starting window for it
2. A's onCreate starts activity B
   - Starting window is transferred from A to B
   - Schedule A to pause
3. A continues to resume and add its window, receive pause request
4. A completes paused
   - Resume B, set visibility to false for B
   - Assume starting window was drawn so trigger transition ready
5. A performs traversal by previous resume.
   - Relayout returns RELAYOUT_RES_FIRST_TIME if the
     client visibility ActivityRecord is true
   - ViewRootImpl executes reportNextDraw("first_relayout")

Note that it has no such problem if the trampoline activity finishes
itself right after starting next activity, because client will skip
adding window by the finishing state.

Bug: 277303796
Test: Launch an activity which starts another activity in
      its onCreate.
Change-Id: I4196056b7f6b6161b431cb80444c9d86fef9492a
This commit is contained in:
Riddle Hsu
2023-04-14 23:35:36 +08:00
parent b4a8a82fa9
commit 6fe7b0757a

View File

@@ -5311,6 +5311,13 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
if (finishing || isState(STOPPED)) {
displayContent.mUnknownAppVisibilityController.appRemovedOrHidden(this);
}
// Because starting window was transferred, this activity may be a trampoline which has
// been occluded by next activity. If it has added windows, set client visibility
// immediately to avoid the client getting RELAYOUT_RES_FIRST_TIME from relayout and
// drawing an unnecessary frame.
if (startingMoved && !firstWindowDrawn && hasChild()) {
setClientVisible(false);
}
} else {
if (!appTransition.isTransitionSet()
&& appTransition.isReady()) {