Log appear animation's scale factor

Test: Grabbed a bug report b/291974797
Flag: N/A
Bug: 290320302
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:2303acd7d4272b063352598d4ec65c5b92e0f0f7)
Merged-In: Ic33dc94806b838a03a2203bdd5701a1eeaeeb7bf
Change-Id: Ic33dc94806b838a03a2203bdd5701a1eeaeeb7bf
diff --git a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
index ca9c577..3966ca4 100644
--- a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
+++ b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
@@ -158,6 +158,7 @@
 import com.android.systemui.shared.system.RemoteAnimationRunnerCompat;
 import com.android.wm.shell.startingsurface.IStartingWindowListener;
 
+import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.LinkedHashMap;
 import java.util.List;
@@ -477,6 +478,9 @@
         });
     }
 
+    /** Dump debug logs to bug report. */
+    public void dump(@NonNull String prefix, @NonNull PrintWriter printWriter) {}
+
     /**
      * Content is everything on screen except the background and the floating view (if any).
      *
diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
index 3139e4d..b621a28 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
@@ -204,6 +204,8 @@
 
     public static final boolean GO_LOW_RAM_RECENTS_ENABLED = false;
 
+    protected static final String RING_APPEAR_ANIMATION_PREFIX = "RingAppearAnimation\t";
+
     private FixedContainerItems mAllAppsPredictions;
     private HotseatPredictionController mHotseatPredictionController;
     private DepthController mDepthController;
@@ -1336,5 +1338,8 @@
         if (recentsView != null) {
             recentsView.getSplitSelectController().dump(prefix, writer);
         }
+        if (mAppTransitionManager != null) {
+            mAppTransitionManager.dump(prefix + "\t" + RING_APPEAR_ANIMATION_PREFIX, writer);
+        }
     }
 }
diff --git a/src/com/android/launcher3/util/EventLogArray.kt b/src/com/android/launcher3/util/EventLogArray.kt
new file mode 100644
index 0000000..a17d650
--- /dev/null
+++ b/src/com/android/launcher3/util/EventLogArray.kt
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.launcher3.util
+
+import java.io.PrintWriter
+import java.text.SimpleDateFormat
+import java.util.Date
+import java.util.Locale
+
+/**
+ * A utility class to record and log events. Events are stored in a fixed size array and old logs
+ * are purged as new events come.
+ */
+class EventLogArray(private val name: String, size: Int) {
+
+    companion object {
+        private const val TYPE_ONE_OFF = 0
+        private const val TYPE_FLOAT = 1
+        private const val TYPE_INTEGER = 2
+        private const val TYPE_BOOL_TRUE = 3
+        private const val TYPE_BOOL_FALSE = 4
+        private fun isEntrySame(entry: EventEntry?, type: Int, event: String): Boolean {
+            return entry != null && entry.type == type && entry.event == event
+        }
+    }
+
+    private val logs: Array<EventEntry?>
+    private var nextIndex = 0
+
+    init {
+        logs = arrayOfNulls(size)
+    }
+
+    fun addLog(event: String) {
+        addLog(TYPE_ONE_OFF, event, 0f)
+    }
+
+    fun addLog(event: String, extras: Int) {
+        addLog(TYPE_INTEGER, event, extras.toFloat())
+    }
+
+    fun addLog(event: String, extras: Float) {
+        addLog(TYPE_FLOAT, event, extras)
+    }
+
+    fun addLog(event: String, extras: Boolean) {
+        addLog(if (extras) TYPE_BOOL_TRUE else TYPE_BOOL_FALSE, event, 0f)
+    }
+
+    private fun addLog(type: Int, event: String, extras: Float) {
+        // Merge the logs if it's a duplicate
+        val last = (nextIndex + logs.size - 1) % logs.size
+        val secondLast = (nextIndex + logs.size - 2) % logs.size
+        if (isEntrySame(logs[last], type, event) && isEntrySame(logs[secondLast], type, event)) {
+            logs[last]!!.update(type, event, extras)
+            logs[secondLast]!!.duplicateCount++
+            return
+        }
+        if (logs[nextIndex] == null) {
+            logs[nextIndex] = EventEntry()
+        }
+        logs[nextIndex]!!.update(type, event, extras)
+        nextIndex = (nextIndex + 1) % logs.size
+    }
+
+    fun dump(prefix: String, writer: PrintWriter) {
+        writer.println("$prefix$name event history:")
+        val sdf = SimpleDateFormat("  HH:mm:ss.SSSZ  ", Locale.US)
+        val date = Date()
+        for (i in logs.indices) {
+            val log = logs[(nextIndex + logs.size - i - 1) % logs.size] ?: continue
+            date.time = log.time
+            val msg = StringBuilder(prefix).append(sdf.format(date)).append(log.event)
+            when (log.type) {
+                TYPE_BOOL_FALSE -> msg.append(": false")
+                TYPE_BOOL_TRUE -> msg.append(": true")
+                TYPE_FLOAT -> msg.append(": ").append(log.extras)
+                TYPE_INTEGER -> msg.append(": ").append(log.extras.toInt())
+                else -> {}
+            }
+            if (log.duplicateCount > 0) {
+                msg.append(" & ").append(log.duplicateCount).append(" similar events")
+            }
+            writer.println(msg)
+        }
+    }
+
+    /** A single event entry. */
+    private class EventEntry {
+        var type = 0
+        var event: String? = null
+        var extras = 0f
+        var time: Long = 0
+        var duplicateCount = 0
+        fun update(type: Int, event: String, extras: Float) {
+            this.type = type
+            this.event = event
+            this.extras = extras
+            time = System.currentTimeMillis()
+            duplicateCount = 0
+        }
+    }
+}