1 /* 2 * Copyright 2023 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.systemui.scene.shared.logger 18 19 import com.android.compose.animation.scene.ContentKey 20 import com.android.compose.animation.scene.ObservableTransitionState 21 import com.android.compose.animation.scene.OverlayKey 22 import com.android.compose.animation.scene.SceneKey 23 import com.android.systemui.log.LogBuffer 24 import com.android.systemui.log.core.LogLevel 25 import com.android.systemui.log.dagger.SceneFrameworkLog 26 import com.android.systemui.scene.data.model.SceneStack 27 import javax.inject.Inject 28 29 class SceneLogger @Inject constructor(@SceneFrameworkLog private val logBuffer: LogBuffer) { 30 logFrameworkEnablednull31 fun logFrameworkEnabled(isEnabled: Boolean, reason: String? = null) { 32 fun asWord(isEnabled: Boolean): String { 33 return if (isEnabled) "enabled" else "disabled" 34 } 35 36 logBuffer.log( 37 tag = TAG, 38 level = if (isEnabled) LogLevel.INFO else LogLevel.WARNING, 39 messageInitializer = { 40 bool1 = isEnabled 41 str1 = reason 42 }, 43 messagePrinter = { 44 "Scene framework is ${asWord(bool1)}${if (str1 != null) " $str1" else ""}" 45 }, 46 ) 47 } 48 logSceneChangednull49 fun logSceneChanged( 50 from: SceneKey, 51 to: SceneKey, 52 sceneState: Any?, 53 reason: String, 54 isInstant: Boolean, 55 ) { 56 logBuffer.log( 57 tag = TAG, 58 level = LogLevel.INFO, 59 messageInitializer = { 60 str1 = "${from.debugName} → ${to.debugName}" 61 str2 = reason 62 str3 = sceneState?.toString() 63 bool1 = isInstant 64 }, 65 messagePrinter = { 66 buildString { 67 append("Scene changed: $str1") 68 str3?.let { append(" (sceneState=$it)") } 69 if (isInstant) { 70 append(" (instant)") 71 } 72 append(", reason: $str2") 73 } 74 }, 75 ) 76 } 77 logSceneChangeCancellationnull78 fun logSceneChangeCancellation(scene: SceneKey, sceneState: Any?) { 79 logBuffer.log( 80 tag = TAG, 81 level = LogLevel.INFO, 82 messageInitializer = { 83 str1 = scene.debugName 84 str2 = sceneState?.toString() 85 }, 86 messagePrinter = { "CANCELED scene change. scene: $str1, sceneState: $str2" }, 87 ) 88 } 89 logSceneChangeRejectionnull90 fun logSceneChangeRejection( 91 from: ContentKey?, 92 to: ContentKey?, 93 originalChangeReason: String?, 94 rejectionReason: String, 95 ) { 96 logBuffer.log( 97 tag = TAG, 98 level = LogLevel.INFO, 99 messageInitializer = { 100 str1 = "${from?.debugName ?: "<none>"} → ${to?.debugName ?: "<none>"}" 101 str2 = rejectionReason 102 str3 = originalChangeReason 103 bool1 = to is OverlayKey 104 }, 105 messagePrinter = { 106 buildString { 107 append("REJECTED ") 108 append( 109 if (bool1) { 110 "overlay " 111 } else { 112 "scene " 113 } 114 ) 115 append("change $str1 because \"$str2\"") 116 if (str3 != null) { 117 append(" (original change reason: \"$str3\")") 118 } 119 } 120 }, 121 ) 122 } 123 logSceneTransitionnull124 fun logSceneTransition(transitionState: ObservableTransitionState) { 125 when (transitionState) { 126 is ObservableTransitionState.Transition -> { 127 logBuffer.log( 128 tag = TAG, 129 level = LogLevel.INFO, 130 messageInitializer = { 131 str1 = transitionState.fromContent.toString() 132 str2 = transitionState.toContent.toString() 133 }, 134 messagePrinter = { "Scene transition started: $str1 → $str2" }, 135 ) 136 } 137 is ObservableTransitionState.Idle -> { 138 logBuffer.log( 139 tag = TAG, 140 level = LogLevel.INFO, 141 messageInitializer = { 142 str1 = transitionState.currentScene.toString() 143 str2 = transitionState.currentOverlays.joinToString() 144 }, 145 messagePrinter = { "Scene transition idle on: $str1, overlays: $str2" }, 146 ) 147 } 148 } 149 } 150 logOverlayChangeRequestednull151 fun logOverlayChangeRequested( 152 from: OverlayKey? = null, 153 to: OverlayKey? = null, 154 reason: String, 155 ) { 156 logBuffer.log( 157 tag = TAG, 158 level = LogLevel.INFO, 159 messageInitializer = { 160 str1 = from?.toString() 161 str2 = to?.toString() 162 str3 = reason 163 }, 164 messagePrinter = { 165 buildString { 166 append("Overlay change requested: ") 167 if (str1 != null) { 168 append(str1) 169 append(if (str2 == null) " (hidden)" else " → $str2") 170 } else { 171 append("$str2 (shown)") 172 } 173 append(", reason: $str3") 174 } 175 }, 176 ) 177 } 178 logVisibilityChangenull179 fun logVisibilityChange(from: Boolean, to: Boolean, reason: String) { 180 fun asWord(isVisible: Boolean): String { 181 return if (isVisible) "visible" else "invisible" 182 } 183 184 logBuffer.log( 185 tag = TAG, 186 level = LogLevel.INFO, 187 messageInitializer = { 188 str1 = asWord(from) 189 str2 = asWord(to) 190 str3 = reason 191 }, 192 messagePrinter = { "$str1 → $str2, reason: $str3" }, 193 ) 194 } 195 logRemoteUserInputStartednull196 fun logRemoteUserInputStarted(reason: String) { 197 logBuffer.log( 198 tag = TAG, 199 level = LogLevel.INFO, 200 messageInitializer = { str1 = reason }, 201 messagePrinter = { "remote user interaction started, reason: $str1" }, 202 ) 203 } 204 logUserInputFinishednull205 fun logUserInputFinished() { 206 logBuffer.log( 207 tag = TAG, 208 level = LogLevel.INFO, 209 messageInitializer = {}, 210 messagePrinter = { "user interaction finished" }, 211 ) 212 } 213 logSceneBackStacknull214 fun logSceneBackStack(backStack: SceneStack) { 215 logBuffer.log( 216 tag = TAG, 217 level = LogLevel.INFO, 218 messageInitializer = { str1 = backStack.toString() }, 219 messagePrinter = { "back stack: $str1" }, 220 ) 221 } 222 223 companion object { 224 private const val TAG = "SceneFramework" 225 } 226 } 227