Merge "Add logging utilities for development with Kotlin" into udc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
4af8abb397
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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.
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
@@ -188,14 +187,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
|
||||
}
|
||||
@@ -204,7 +203,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)
|
||||
@@ -212,7 +211,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)) {
|
||||
@@ -220,20 +219,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
|
||||
@@ -273,7 +272,7 @@ constructor(
|
||||
PackageManager.DONT_KILL_APP,
|
||||
)
|
||||
|
||||
logDebug { "setNoteTaskShortcutEnabled - completed: $isEnabled" }
|
||||
debugLog { "setNoteTaskShortcutEnabled - completed: $isEnabled" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -372,11 +371,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 {
|
||||
|
||||
@@ -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())
|
||||
}
|
||||
|
||||
@@ -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())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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())
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user