Fix app transition logging when switching quickly

If an app was set to invisible before the transition started,
which happens when quickly open an app and then closing again
before the animation is starting (only possible if starting
window is slightly delayed), we never receive onWindowsDrawn so we
need to cancel the transition in this case.

Also fixes an issue where the wrong activity was reported as
starting to us in case reusedActivity != null but we'll only reuse
it for the task and not the actual activity.

Test: Open Calendar, press home immediately, open another app, make
sure all logged events and times are correct.
Fixes: 37538546

Change-Id: I5819bd97964ab2dd5cb40b2f4e3bc5a9ac348152
diff --git a/services/core/java/com/android/server/am/ActivityMetricsLogger.java b/services/core/java/com/android/server/am/ActivityMetricsLogger.java
index 2dd3b74..d4de521 100644
--- a/services/core/java/com/android/server/am/ActivityMetricsLogger.java
+++ b/services/core/java/com/android/server/am/ActivityMetricsLogger.java
@@ -11,12 +11,12 @@
 import static android.app.ActivityManagerInternal.APP_TRANSITION_TIMEOUT;
 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION;
 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_CALLING_PACKAGE_NAME;
-import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_CLASS_NAME;
 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_DELAY_MS;
 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_DEVICE_UPTIME_SECONDS;
 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_IS_EPHEMERAL;
 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_STARTING_WINDOW_DELAY_MS;
 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_WINDOWS_DRAWN_DELAY_MS;
+import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_CLASS_NAME;
 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_INSTANT_APP_LAUNCH_TOKEN;
 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_TRANSITION_COLD_LAUNCH;
 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_TRANSITION_HOT_LAUNCH;
@@ -194,6 +194,11 @@
         final int stackId = launchedActivity != null && launchedActivity.getStack() != null
                 ? launchedActivity.getStack().mStackId
                 : INVALID_STACK_ID;
+
+        if (mCurrentTransitionStartTime == INVALID_START_TIME) {
+            return;
+        }
+
         final StackTransitionInfo info = mStackTransitionInfo.get(stackId);
         if (launchedActivity != null && info != null) {
             info.launchedActivity = launchedActivity;
@@ -272,6 +277,25 @@
         }
     }
 
+    /**
+     * Notifies the tracker that the visibility of an app is changing.
+     *
+     * @param activityRecord the app that is changing its visibility
+     * @param visible whether it's going to be visible or not
+     */
+    void notifyVisibilityChanged(ActivityRecord activityRecord, boolean visible) {
+        final StackTransitionInfo info = mStackTransitionInfo.get(activityRecord.getStackId());
+
+        // If we have an active transition that's waiting on a certain activity that will be
+        // invisible now, we'll never get onWindowsDrawn, so abort the transition if necessary.
+        if (info != null && !visible && info.launchedActivity == activityRecord) {
+            mStackTransitionInfo.remove(activityRecord.getStackId());
+            if (mStackTransitionInfo.size() == 0) {
+                reset(true /* abort */);
+            }
+        }
+    }
+
     private boolean allStacksWindowsDrawn() {
         for (int index = mStackTransitionInfo.size() - 1; index >= 0; index--) {
             if (!mStackTransitionInfo.valueAt(index).loggedWindowsDrawn) {