Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 416c8b6e authored by Marcello Galhardo's avatar Marcello Galhardo Committed by Automerger Merge Worker
Browse files

Merge "Add logging utilities for development with Kotlin" into udc-dev am:...

Merge "Add logging utilities for development with Kotlin" into udc-dev am: 4af8abb3 am: be3b61cd

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/22787396



Change-Id: Icff15e3fd4cde53ac5121b4ce89f8f4a7a11e4b3
Signed-off-by: default avatarAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
parents 256c27cf be3b61cd
Loading
Loading
Loading
Loading
+80 −0
Original line number Diff line number Diff line
/*
 * 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)
            }
        }
    }
}
+35 −0
Original line number Diff line number Diff line
/*
 * 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.
    }
}
+13 −19
Original line number Diff line number Diff line
@@ -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 {
+2 −8
Original line number Diff line number Diff line
@@ -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())
}
+11 −17
Original line number Diff line number Diff line
@@ -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())
    }
}
Loading