diff options
author | 2023-04-21 15:35:29 +0000 | |
---|---|---|
committer | 2023-04-27 21:02:48 +0000 | |
commit | ad7ef8b159f35c3ab73dbee692999afd14725576 (patch) | |
tree | ebac83e896d96c465f927c732c203d76d2310d8e | |
parent | ec396f015d60d5a29df43a8f464b004fd97c75de (diff) |
Add logging utilities for development with Kotlin
Test: manual
Flag: not needed
Fixes: b/274509846
Change-Id: I5d800d1bf94fbcbee85dfa706d7a43c92bbc4164
6 files changed, 148 insertions, 57 deletions
diff --git a/packages/SystemUI/src-debug/com/android/systemui/log/DebugLogger.kt b/packages/SystemUI/src-debug/com/android/systemui/log/DebugLogger.kt new file mode 100644 index 000000000000..af29b05a3fb1 --- /dev/null +++ b/packages/SystemUI/src-debug/com/android/systemui/log/DebugLogger.kt @@ -0,0 +1,80 @@ +/* + * 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 + +import android.os.Build +import android.util.Log +import android.util.Log.LOG_ID_MAIN + +/** + * A simplified debug logger built as a wrapper around Android's [Log]. Internal for development. + * + * The main advantages are: + * - Sensible defaults, automatically retrieving the class name from the call-site (i.e., tag); + * - The messages are purged from source on release builds (keep in mind they are visible on AOSP); + * - Lazily evaluate Strings for zero impact in production builds or when disabled; + * + * Usage example: + * ```kotlin + * // Logging a message: + * debugLog { "message" } + * + * // Logging an error: + * debugLog(error = exception) { "message" } + * + * // Logging the current stack trace, for debugging: + * debugLog(error = Throwable()) { "message" } + * ``` + */ +object DebugLogger { + + /** + * Log a debug message, with sensible defaults. + * + * For example: + * ```kotlin + * val one = 1 + * debugLog { "message#$one" } + * ``` + * + * The output will be: `D/NoteTaskController: message#1` + * + * Beware, the [debugLog] content is **REMOVED FROM SOURCE AND BINARY** in Release builds. + * + * @param enabled: whether or not the message should be logged. By default, it is + * [Build.IS_DEBUGGABLE]. + * @param priority: type of this log. By default, it is [Log.DEBUG]. + * @param tag: identifies the source of a log. By default, it is the receiver's simple name. + * @param error: a [Throwable] to log. + * @param message: a lazily evaluated message you wish to log. + */ + inline fun Any.debugLog( + enabled: Boolean = Build.IS_DEBUGGABLE, + priority: Int = Log.DEBUG, + tag: String = this::class.simpleName.orEmpty(), + error: Throwable? = null, + message: () -> String, + ) { + if (enabled) { + if (error == null) { + Log.println(priority, tag, message()) + } else { + Log.printlns(LOG_ID_MAIN, priority, tag, message(), error) + } + } + } +} diff --git a/packages/SystemUI/src-release/com/android/systemui/log/DebugLogger.kt b/packages/SystemUI/src-release/com/android/systemui/log/DebugLogger.kt new file mode 100644 index 000000000000..2764a1fdfe3d --- /dev/null +++ b/packages/SystemUI/src-release/com/android/systemui/log/DebugLogger.kt @@ -0,0 +1,35 @@ +/* + * 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 + +import android.os.Build +import android.util.Log + +/** An empty logger for release builds. */ +object DebugLogger { + + @JvmName("logcatMessage") + inline fun Any.debugLog( + enabled: Boolean = Build.IS_DEBUGGABLE, + priority: Int = Log.DEBUG, + tag: String = this::class.simpleName.orEmpty(), + error: Throwable? = null, + message: () -> String, + ) { + // no-op. + } +} diff --git a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskController.kt b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskController.kt index d4052f54b3da..f288b06678a7 100644 --- a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskController.kt +++ b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskController.kt @@ -31,15 +31,14 @@ import android.content.Intent import android.content.pm.PackageManager import android.content.pm.ShortcutManager import android.graphics.drawable.Icon -import android.os.Build import android.os.UserHandle import android.os.UserManager -import android.util.Log import android.widget.Toast import androidx.annotation.VisibleForTesting import com.android.systemui.R import com.android.systemui.dagger.SysUISingleton import com.android.systemui.devicepolicy.areKeyguardShortcutsDisabled +import com.android.systemui.log.DebugLogger.debugLog import com.android.systemui.notetask.NoteTaskRoleManagerExt.createNoteShortcutInfoAsUser import com.android.systemui.notetask.NoteTaskRoleManagerExt.getDefaultRoleHolderAsUser import com.android.systemui.notetask.shortcut.LaunchNoteTaskManagedProfileProxyActivity @@ -92,10 +91,10 @@ constructor( if (info.launchMode != NoteTaskLaunchMode.AppBubble) return if (isExpanding) { - logDebug { "onBubbleExpandChanged - expanding: $info" } + debugLog { "onBubbleExpandChanged - expanding: $info" } eventLogger.logNoteTaskOpened(info) } else { - logDebug { "onBubbleExpandChanged - collapsing: $info" } + debugLog { "onBubbleExpandChanged - collapsing: $info" } eventLogger.logNoteTaskClosed(info) } } @@ -168,14 +167,14 @@ constructor( isKeyguardLocked && devicePolicyManager.areKeyguardShortcutsDisabled(userId = user.identifier) ) { - logDebug { "Enterprise policy disallows launching note app when the screen is locked." } + debugLog { "Enterprise policy disallows launching note app when the screen is locked." } return } val info = resolver.resolveInfo(entryPoint, isKeyguardLocked, user) if (info == null) { - logDebug { "Default notes app isn't set" } + debugLog { "Default notes app isn't set" } showNoDefaultNotesAppToast() return } @@ -184,7 +183,7 @@ constructor( try { // TODO(b/266686199): We should handle when app not available. For now, we log. - logDebug { "onShowNoteTask - start: $info on user#${user.identifier}" } + debugLog { "onShowNoteTask - start: $info on user#${user.identifier}" } when (info.launchMode) { is NoteTaskLaunchMode.AppBubble -> { val intent = createNoteTaskIntent(info) @@ -192,7 +191,7 @@ constructor( Icon.createWithResource(context, R.drawable.ic_note_task_shortcut_widget) bubbles.showOrHideAppBubble(intent, user, icon) // App bubble logging happens on `onBubbleExpandChanged`. - logDebug { "onShowNoteTask - opened as app bubble: $info" } + debugLog { "onShowNoteTask - opened as app bubble: $info" } } is NoteTaskLaunchMode.Activity -> { if (activityManager.isInForeground(info.packageName)) { @@ -200,20 +199,20 @@ constructor( val intent = createHomeIntent() context.startActivityAsUser(intent, user) eventLogger.logNoteTaskClosed(info) - logDebug { "onShowNoteTask - closed as activity: $info" } + debugLog { "onShowNoteTask - closed as activity: $info" } } else { val intent = createNoteTaskIntent(info) context.startActivityAsUser(intent, user) eventLogger.logNoteTaskOpened(info) - logDebug { "onShowNoteTask - opened as activity: $info" } + debugLog { "onShowNoteTask - opened as activity: $info" } } } } - logDebug { "onShowNoteTask - success: $info" } + debugLog { "onShowNoteTask - success: $info" } } catch (e: ActivityNotFoundException) { - logDebug { "onShowNoteTask - failed: $info" } + debugLog { "onShowNoteTask - failed: $info" } } - logDebug { "onShowNoteTask - completed: $info" } + debugLog { "onShowNoteTask - completed: $info" } } @VisibleForTesting @@ -253,7 +252,7 @@ constructor( PackageManager.DONT_KILL_APP, ) - logDebug { "setNoteTaskShortcutEnabled - completed: $isEnabled" } + debugLog { "setNoteTaskShortcutEnabled - completed: $isEnabled" } } /** @@ -352,11 +351,6 @@ private fun createNoteTaskIntent(info: NoteTaskInfo): Intent = } } -/** [Log.println] a [Log.DEBUG] message, only when [Build.IS_DEBUGGABLE]. */ -private inline fun Any.logDebug(message: () -> String) { - if (Build.IS_DEBUGGABLE) Log.d(this::class.java.simpleName.orEmpty(), message()) -} - /** Creates an [Intent] which forces the current app to background by calling home. */ private fun createHomeIntent(): Intent = Intent(Intent.ACTION_MAIN).apply { diff --git a/packages/SystemUI/src/com/android/systemui/notetask/shortcut/LaunchNoteTaskActivity.kt b/packages/SystemUI/src/com/android/systemui/notetask/shortcut/LaunchNoteTaskActivity.kt index 0f38d32e0b64..8ca13b9776bb 100644 --- a/packages/SystemUI/src/com/android/systemui/notetask/shortcut/LaunchNoteTaskActivity.kt +++ b/packages/SystemUI/src/com/android/systemui/notetask/shortcut/LaunchNoteTaskActivity.kt @@ -18,12 +18,11 @@ package com.android.systemui.notetask.shortcut import android.content.Context import android.content.Intent -import android.os.Build import android.os.Bundle import android.os.UserHandle import android.os.UserManager -import android.util.Log import androidx.activity.ComponentActivity +import com.android.systemui.log.DebugLogger.debugLog import com.android.systemui.notetask.NoteTaskController import com.android.systemui.notetask.NoteTaskEntryPoint import com.android.systemui.settings.UserTracker @@ -68,7 +67,7 @@ constructor( val mainUser: UserHandle? = userManager.mainUser if (userManager.isManagedProfile) { if (mainUser == null) { - logDebug { "Can't find the main user. Skipping the notes app launch." } + debugLog { "Can't find the main user. Skipping the notes app launch." } } else { controller.startNoteTaskProxyActivityForUser(mainUser) } @@ -89,8 +88,3 @@ constructor( } } } - -/** [Log.println] a [Log.DEBUG] message, only when [Build.IS_DEBUGGABLE]. */ -private inline fun Any.logDebug(message: () -> String) { - if (Build.IS_DEBUGGABLE) Log.d(this::class.java.simpleName.orEmpty(), message()) -} diff --git a/packages/SystemUI/src/com/android/systemui/stylus/StylusManager.kt b/packages/SystemUI/src/com/android/systemui/stylus/StylusManager.kt index 412b3150489c..27aaa6828036 100644 --- a/packages/SystemUI/src/com/android/systemui/stylus/StylusManager.kt +++ b/packages/SystemUI/src/com/android/systemui/stylus/StylusManager.kt @@ -22,7 +22,6 @@ import android.content.Context import android.hardware.BatteryState import android.hardware.input.InputManager import android.hardware.input.InputSettings -import android.os.Build import android.os.Handler import android.util.ArrayMap import android.util.Log @@ -35,6 +34,7 @@ import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.flags.FeatureFlags import com.android.systemui.flags.Flags +import com.android.systemui.log.DebugLogger.debugLog import com.android.systemui.shared.hardware.hasInputDevice import com.android.systemui.shared.hardware.isInternalStylusSource import java.util.concurrent.CopyOnWriteArrayList @@ -81,7 +81,7 @@ constructor( fun startListener() { handler.post { if (hasStarted) return@post - logDebug { "Listener has started." } + debugLog { "Listener has started." } hasStarted = true isInUsiSession = @@ -109,7 +109,7 @@ constructor( val device: InputDevice = inputManager.getInputDevice(deviceId) ?: return if (!device.supportsSource(InputDevice.SOURCE_STYLUS)) return - logDebug { + debugLog { "Stylus InputDevice added: $deviceId ${device.name}, " + "External: ${device.isExternal}" } @@ -134,7 +134,7 @@ constructor( val device: InputDevice = inputManager.getInputDevice(deviceId) ?: return if (!device.supportsSource(InputDevice.SOURCE_STYLUS)) return - logDebug { "Stylus InputDevice changed: $deviceId ${device.name}" } + debugLog { "Stylus InputDevice changed: $deviceId ${device.name}" } val currAddress: String? = device.bluetoothAddress val prevAddress: String? = inputDeviceAddressMap[deviceId] @@ -155,7 +155,7 @@ constructor( if (!hasStarted) return if (!inputDeviceAddressMap.contains(deviceId)) return - logDebug { "Stylus InputDevice removed: $deviceId" } + debugLog { "Stylus InputDevice removed: $deviceId" } unregisterBatteryListener(deviceId) @@ -180,7 +180,7 @@ constructor( val isCharging = String(value) == "true" - logDebug { + debugLog { "Charging state metadata changed for device $inputDeviceId " + "${device.address}: $isCharging" } @@ -199,7 +199,7 @@ constructor( handler.post { if (!hasStarted) return@post - logDebug { + debugLog { "Battery state changed for $deviceId. " + "batteryState present: ${batteryState.isPresent}, " + "capacity: ${batteryState.capacity}" @@ -247,7 +247,7 @@ constructor( if (!featureFlags.isEnabled(Flags.TRACK_STYLUS_EVER_USED)) return if (InputSettings.isStylusEverUsed(context)) return - logDebug { "Stylus used for the first time." } + debugLog { "Stylus used for the first time." } InputSettings.setStylusEverUsed(context, true) executeStylusCallbacks { cb -> cb.onStylusFirstUsed() } } @@ -264,7 +264,7 @@ constructor( val hasBtConnection = if (inputDeviceBtSessionIdMap.isEmpty()) 0 else 1 if (batteryStateValid && usiSessionId == null) { - logDebug { "USI battery newly present, entering new USI session: $deviceId" } + debugLog { "USI battery newly present, entering new USI session: $deviceId" } usiSessionId = instanceIdSequence.newInstanceId() uiEventLogger.logWithInstanceIdAndPosition( StylusUiEvent.USI_STYLUS_BATTERY_PRESENCE_FIRST_DETECTED, @@ -274,7 +274,7 @@ constructor( hasBtConnection, ) } else if (!batteryStateValid && usiSessionId != null) { - logDebug { "USI battery newly absent, exiting USI session: $deviceId" } + debugLog { "USI battery newly absent, exiting USI session: $deviceId" } uiEventLogger.logWithInstanceIdAndPosition( StylusUiEvent.USI_STYLUS_BATTERY_PRESENCE_REMOVED, 0, @@ -291,7 +291,7 @@ constructor( btAddress: String, btConnected: Boolean ) { - logDebug { + debugLog { "Bluetooth stylus ${if (btConnected) "connected" else "disconnected"}:" + " $deviceId $btAddress" } @@ -386,9 +386,3 @@ constructor( val TAG = StylusManager::class.simpleName.orEmpty() } } - -private inline fun logDebug(message: () -> String) { - if (Build.IS_DEBUGGABLE) { - Log.d(StylusManager.TAG, message()) - } -} diff --git a/packages/SystemUI/src/com/android/systemui/stylus/StylusUsiPowerUI.kt b/packages/SystemUI/src/com/android/systemui/stylus/StylusUsiPowerUI.kt index 21b0efadb8d5..6eddd9eb7ad2 100644 --- a/packages/SystemUI/src/com/android/systemui/stylus/StylusUsiPowerUI.kt +++ b/packages/SystemUI/src/com/android/systemui/stylus/StylusUsiPowerUI.kt @@ -26,7 +26,6 @@ import android.content.Intent import android.content.IntentFilter import android.hardware.BatteryState import android.hardware.input.InputManager -import android.os.Build import android.os.Bundle import android.os.Handler import android.os.UserHandle @@ -40,6 +39,7 @@ import com.android.internal.logging.UiEventLogger import com.android.systemui.R import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Background +import com.android.systemui.log.DebugLogger.debugLog import com.android.systemui.shared.hardware.hasInputDevice import com.android.systemui.shared.hardware.isAnyStylusSource import com.android.systemui.util.NotificationChannels @@ -110,7 +110,7 @@ constructor( inputDeviceId = deviceId batteryCapacity = batteryState.capacity - logDebug { + debugLog { "Updating notification battery state to $batteryCapacity " + "for InputDevice $deviceId." } @@ -130,14 +130,14 @@ constructor( handler.post updateSuppressed@{ if (suppressed == suppress) return@updateSuppressed - logDebug { "Updating notification suppression to $suppress." } + debugLog { "Updating notification suppression to $suppress." } suppressed = suppress refresh() } } private fun hideNotification() { - logDebug { "Cancelling USI low battery notification." } + debugLog { "Cancelling USI low battery notification." } instanceId = null notificationManager.cancel(USI_NOTIFICATION_ID) } @@ -160,7 +160,7 @@ constructor( .setAutoCancel(true) .build() - logDebug { "Show or update USI low battery notification at $batteryCapacity." } + debugLog { "Show or update USI low battery notification at $batteryCapacity." } logUiEvent(StylusUiEvent.STYLUS_LOW_BATTERY_NOTIFICATION_SHOWN) notificationManager.notify(USI_NOTIFICATION_ID, notification) } @@ -188,12 +188,12 @@ constructor( override fun onReceive(context: Context, intent: Intent) { when (intent.action) { ACTION_DISMISSED_LOW_BATTERY -> { - logDebug { "USI low battery notification dismissed." } + debugLog { "USI low battery notification dismissed." } logUiEvent(StylusUiEvent.STYLUS_LOW_BATTERY_NOTIFICATION_DISMISSED) updateSuppression(true) } ACTION_CLICKED_LOW_BATTERY -> { - logDebug { "USI low battery notification clicked." } + debugLog { "USI low battery notification clicked." } logUiEvent(StylusUiEvent.STYLUS_LOW_BATTERY_NOTIFICATION_CLICKED) updateSuppression(true) if (inputDeviceId == null) return @@ -263,9 +263,3 @@ constructor( @VisibleForTesting const val KEY_SETTINGS_FRAGMENT_ARGS = ":settings:show_fragment_args" } } - -private inline fun logDebug(message: () -> String) { - if (Build.IS_DEBUGGABLE) { - Log.d(StylusUsiPowerUI.TAG, message()) - } -} |