Merge "Reduce log buffer waste." into tm-qpr-dev
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
index 817de79..642c9f7 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
@@ -62,6 +62,15 @@
         return factory.create("NotifLog", maxSize, false /* systrace */);
     }
 
+    /** Provides a logging buffer for all logs related to notifications on the lockscreen. */
+    @Provides
+    @SysUISingleton
+    @NotificationLockscreenLog
+    public static LogBuffer provideNotificationLockScreenLogBuffer(
+            LogBufferFactory factory) {
+        return factory.create("NotifLockscreenLog", 50, false /* systrace */);
+    }
+
     /** Provides a logging buffer for logs related to heads up presentation of notifications. */
     @Provides
     @SysUISingleton
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/NotificationLockscreenLog.java b/packages/SystemUI/src/com/android/systemui/log/dagger/NotificationLockscreenLog.java
new file mode 100644
index 0000000..a2d381e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/NotificationLockscreenLog.java
@@ -0,0 +1,33 @@
+/*
+ * 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.systemui.log.dagger;
+
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import com.android.systemui.plugins.log.LogBuffer;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+
+import javax.inject.Qualifier;
+
+/** A {@link LogBuffer} for notification & lockscreen related messages. */
+@Qualifier
+@Documented
+@Retention(RUNTIME)
+public @interface NotificationLockscreenLog {
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorLogger.kt
index 4464531..88d9ffc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorLogger.kt
@@ -13,7 +13,7 @@
 
 package com.android.systemui.statusbar.notification
 
-import com.android.systemui.log.dagger.NotificationLog
+import com.android.systemui.log.dagger.NotificationLockscreenLog
 import com.android.systemui.plugins.log.LogBuffer
 import com.android.systemui.plugins.log.LogLevel.DEBUG
 import com.android.systemui.statusbar.StatusBarState
@@ -21,7 +21,12 @@
 
 class NotificationWakeUpCoordinatorLogger
 @Inject
-constructor(@NotificationLog private val buffer: LogBuffer) {
+constructor(@NotificationLockscreenLog private val buffer: LogBuffer) {
+    private var lastSetDozeAmountLogWasFractional = false
+    private var lastSetDozeAmountLogState = -1
+    private var lastSetDozeAmountLogSource = "undefined"
+    private var lastOnDozeAmountChangedLogWasFractional = false
+
     fun logSetDozeAmount(
         linear: Float,
         eased: Float,
@@ -29,6 +34,20 @@
         state: Int,
         changed: Boolean,
     ) {
+        // Avoid logging on every frame of the animation if important values are not changing
+        val isFractional = linear != 1f && linear != 0f
+        if (
+            lastSetDozeAmountLogWasFractional &&
+                isFractional &&
+                lastSetDozeAmountLogState == state &&
+                lastSetDozeAmountLogSource == source
+        ) {
+            return
+        }
+        lastSetDozeAmountLogWasFractional = isFractional
+        lastSetDozeAmountLogState = state
+        lastSetDozeAmountLogSource = source
+
         buffer.log(
             TAG,
             DEBUG,
@@ -66,6 +85,10 @@
     }
 
     fun logOnDozeAmountChanged(linear: Float, eased: Float) {
+        // Avoid logging on every frame of the animation when values are fractional
+        val isFractional = linear != 1f && linear != 0f
+        if (lastOnDozeAmountChangedLogWasFractional && isFractional) return
+        lastOnDozeAmountChangedLogWasFractional = isFractional
         buffer.log(
             TAG,
             DEBUG,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorLoggerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorLoggerTest.kt
new file mode 100644
index 0000000..7a67796
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorLoggerTest.kt
@@ -0,0 +1,111 @@
+/*
+ * 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.systemui.statusbar.notification
+
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.plugins.log.LogBuffer
+import com.android.systemui.plugins.log.LogLevel
+import com.android.systemui.plugins.log.LogcatEchoTracker
+import com.android.systemui.statusbar.StatusBarState
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidTestingRunner::class)
+@SmallTest
+class NotificationWakeUpCoordinatorLoggerTest : SysuiTestCase() {
+
+    private val logBufferCounter = LogBufferCounter()
+    private lateinit var logger: NotificationWakeUpCoordinatorLogger
+
+    private fun verifyDidLog(times: Int) {
+        logBufferCounter.verifyDidLog(times)
+    }
+
+    @Before
+    fun setup() {
+        logger = NotificationWakeUpCoordinatorLogger(logBufferCounter.logBuffer)
+    }
+
+    @Test
+    fun setDozeAmountWillThrottleFractionalUpdates() {
+        logger.logSetDozeAmount(0f, 0f, "source1", StatusBarState.SHADE, changed = false)
+        verifyDidLog(1)
+        logger.logSetDozeAmount(0.1f, 0.1f, "source1", StatusBarState.SHADE, changed = true)
+        verifyDidLog(1)
+        logger.logSetDozeAmount(0.2f, 0.2f, "source1", StatusBarState.SHADE, changed = true)
+        logger.logSetDozeAmount(0.3f, 0.3f, "source1", StatusBarState.SHADE, changed = true)
+        logger.logSetDozeAmount(0.4f, 0.4f, "source1", StatusBarState.SHADE, changed = true)
+        logger.logSetDozeAmount(0.5f, 0.5f, "source1", StatusBarState.SHADE, changed = true)
+        verifyDidLog(0)
+        logger.logSetDozeAmount(1f, 1f, "source1", StatusBarState.SHADE, changed = true)
+        verifyDidLog(1)
+    }
+
+    @Test
+    fun setDozeAmountWillIncludeFractionalUpdatesWhenStateChanges() {
+        logger.logSetDozeAmount(0f, 0f, "source1", StatusBarState.SHADE, changed = false)
+        verifyDidLog(1)
+        logger.logSetDozeAmount(0.1f, 0.1f, "source1", StatusBarState.SHADE, changed = true)
+        verifyDidLog(1)
+        logger.logSetDozeAmount(0.2f, 0.2f, "source1", StatusBarState.SHADE, changed = true)
+        logger.logSetDozeAmount(0.3f, 0.3f, "source1", StatusBarState.SHADE, changed = true)
+        logger.logSetDozeAmount(0.4f, 0.4f, "source1", StatusBarState.SHADE, changed = true)
+        logger.logSetDozeAmount(0.5f, 0.5f, "source1", StatusBarState.SHADE, changed = true)
+        verifyDidLog(0)
+        logger.logSetDozeAmount(0.5f, 0.5f, "source1", StatusBarState.KEYGUARD, changed = false)
+        verifyDidLog(1)
+    }
+
+    @Test
+    fun setDozeAmountWillIncludeFractionalUpdatesWhenSourceChanges() {
+        logger.logSetDozeAmount(0f, 0f, "source1", StatusBarState.SHADE, changed = false)
+        verifyDidLog(1)
+        logger.logSetDozeAmount(0.1f, 0.1f, "source1", StatusBarState.SHADE, changed = true)
+        verifyDidLog(1)
+        logger.logSetDozeAmount(0.2f, 0.2f, "source1", StatusBarState.SHADE, changed = true)
+        logger.logSetDozeAmount(0.3f, 0.3f, "source1", StatusBarState.SHADE, changed = true)
+        logger.logSetDozeAmount(0.4f, 0.4f, "source1", StatusBarState.SHADE, changed = true)
+        logger.logSetDozeAmount(0.5f, 0.5f, "source1", StatusBarState.SHADE, changed = true)
+        verifyDidLog(0)
+        logger.logSetDozeAmount(0.5f, 0.5f, "source2", StatusBarState.SHADE, changed = false)
+        verifyDidLog(1)
+    }
+
+    class LogBufferCounter {
+        val recentLogs = mutableListOf<Pair<String, LogLevel>>()
+        val tracker =
+            object : LogcatEchoTracker {
+                override val logInBackgroundThread: Boolean = false
+                override fun isBufferLoggable(bufferName: String, level: LogLevel): Boolean = false
+                override fun isTagLoggable(tagName: String, level: LogLevel): Boolean {
+                    recentLogs.add(tagName to level)
+                    return true
+                }
+            }
+        val logBuffer =
+            LogBuffer(name = "test", maxSize = 1, logcatEchoTracker = tracker, systrace = false)
+
+        fun verifyDidLog(times: Int) {
+            assertThat(recentLogs).hasSize(times)
+            recentLogs.clear()
+        }
+    }
+}