Report launch time on the last started activity

Assume:
L is "Activity launched".
D is "Window drawn/displayed".
T is a trampoline activity (e.g. a splash screen).
M is the main activity.

An application may be designed as:
L(T) -> L(M) -> D(T) -> D(M)

Originally we will report the launch time on D(T).
Now if L(M) happens before D(T), then it is supposed
to be a continuous launch sequence and report the
launch time on D(M).

Bug: 132736359
Test: atest ActivityMetricsLoggerTests
      atest ActivityMetricsLaunchObserverTests# \
            testOnActivityLaunchFinishedTrampoline

Change-Id: I9ffd3b94d76831572ea961a8dcbf9d760a617430
diff --git a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
index e6c6b12e..6636b16 100644
--- a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
+++ b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
@@ -187,9 +187,24 @@
         private int startingWindowDelayMs = INVALID_DELAY;
         private int bindApplicationDelayMs = INVALID_DELAY;
         private int reason = APP_TRANSITION_TIMEOUT;
-        private boolean loggedWindowsDrawn;
+        private int numUndrawnActivities;
         private boolean loggedStartingWindowDrawn;
         private boolean launchTraceActive;
+
+        /**
+         * Remembers the latest launched activity to represent the final transition. This also
+         * increments the number of activities that should be drawn, so a consecutive launching
+         * sequence can be coalesced as one event.
+         */
+        void setLatestLaunchedActivity(ActivityRecord r) {
+            if (launchedActivity == r) {
+                return;
+            }
+            launchedActivity = r;
+            if (!r.noDisplay) {
+                numUndrawnActivities++;
+            }
+        }
     }
 
     final class WindowingModeTransitionInfoSnapshot {
@@ -400,7 +415,7 @@
             // the other attributes.
 
             // Coalesce multiple (trampoline) activities from a single sequence together.
-            info.launchedActivity = launchedActivity;
+            info.setLatestLaunchedActivity(launchedActivity);
             return;
         }
 
@@ -422,7 +437,7 @@
         // A new launch sequence [with the windowingMode] has begun.
         // Start tracking it.
         final WindowingModeTransitionInfo newInfo = new WindowingModeTransitionInfo();
-        newInfo.launchedActivity = launchedActivity;
+        newInfo.setLatestLaunchedActivity(launchedActivity);
         newInfo.currentTransitionProcessRunning = processRunning;
         newInfo.startResult = resultCode;
         mWindowingModeTransitionInfo.put(windowingMode, newInfo);
@@ -448,11 +463,11 @@
         if (DEBUG_METRICS) Slog.i(TAG, "notifyWindowsDrawn windowingMode=" + windowingMode);
 
         final WindowingModeTransitionInfo info = mWindowingModeTransitionInfo.get(windowingMode);
-        if (info == null || info.loggedWindowsDrawn) {
+        if (info == null || info.numUndrawnActivities == 0) {
             return null;
         }
         info.windowsDrawnDelayMs = calculateDelay(timestampNs);
-        info.loggedWindowsDrawn = true;
+        info.numUndrawnActivities--;
         final WindowingModeTransitionInfoSnapshot infoSnapshot =
                 new WindowingModeTransitionInfoSnapshot(info);
         if (allWindowsDrawn() && mLoggedTransitionStarting) {
@@ -594,9 +609,10 @@
         }
     }
 
-    private boolean allWindowsDrawn() {
+    @VisibleForTesting
+    boolean allWindowsDrawn() {
         for (int index = mWindowingModeTransitionInfo.size() - 1; index >= 0; index--) {
-            if (!mWindowingModeTransitionInfo.valueAt(index).loggedWindowsDrawn) {
+            if (mWindowingModeTransitionInfo.valueAt(index).numUndrawnActivities != 0) {
                 return false;
             }
         }