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

Commit 38bbd06e authored by Sanatt Abrol's avatar Sanatt Abrol
Browse files

Add DesktopModeEventLogger which logs session events

Bug: b/320439743
Change-Id: I2649c63460a25d7c3d4632bbfb1dafef4540f791
parent 4ecb85fd
Loading
Loading
Loading
Loading
+218 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 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.wm.shell.desktopmode

import com.android.internal.util.FrameworkStatsLog
import com.android.wm.shell.protolog.ShellProtoLogGroup
import com.android.wm.shell.util.KtProtoLog

/**
 * Event logger for logging desktop mode session events
 */
class DesktopModeEventLogger {
    /**
     * Logs the enter of desktop mode having session id [sessionId] and the reason [enterReason] for
     * entering desktop mode
     */
    fun logSessionEnter(sessionId: Int, enterReason: EnterReason) {
        KtProtoLog.v(
            ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE,
            "DesktopModeLogger: Logging session enter, session: %s reason: %s",
            sessionId, enterReason.name
        )
        FrameworkStatsLog.write(DESKTOP_MODE_ATOM_ID,
            /* event */ FrameworkStatsLog.DESKTOP_MODE_UICHANGED__EVENT__ENTER,
            /* enterReason */ enterReason.reason,
            /* exitReason */ 0,
            /* session_id */ sessionId)
    }

    /**
     * Logs the exit of desktop mode having session id [sessionId] and the reason [exitReason] for
     * exiting desktop mode
     */
    fun logSessionExit(sessionId: Int, exitReason: ExitReason) {
        KtProtoLog.v(
            ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE,
            "DesktopModeLogger: Logging session exit, session: %s reason: %s",
            sessionId, exitReason.name
        )
        FrameworkStatsLog.write(DESKTOP_MODE_ATOM_ID,
            /* event */ FrameworkStatsLog.DESKTOP_MODE_UICHANGED__EVENT__EXIT,
            /* enterReason */ 0,
            /* exitReason */ exitReason.reason,
            /* session_id */ sessionId)
    }

    /**
     * Logs that the task with update [taskUpdate] was added in the desktop mode session having
     * session id [sessionId]
     */
    fun logTaskAdded(sessionId: Int, taskUpdate: TaskUpdate) {
        KtProtoLog.v(
            ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE,
            "DesktopModeLogger: Logging task added, session: %s taskId: %s",
            sessionId, taskUpdate.instanceId
        )
        FrameworkStatsLog.write(DESKTOP_MODE_TASK_UPDATE_ATOM_ID,
            /* task_event */
            FrameworkStatsLog.DESKTOP_MODE_SESSION_TASK_UPDATE__TASK_EVENT__TASK_ADDED,
            /* instance_id */
            taskUpdate.instanceId,
            /* uid */
            taskUpdate.uid,
            /* task_height */
            taskUpdate.taskHeight,
            /* task_width */
            taskUpdate.taskWidth,
            /* task_x */
            taskUpdate.taskX,
            /* task_y */
            taskUpdate.taskY,
            /* session_id */
            sessionId)
    }

    /**
     * Logs that the task with update [taskUpdate] was removed in the desktop mode session having
     * session id [sessionId]
     */
    fun logTaskRemoved(sessionId: Int, taskUpdate: TaskUpdate) {
        KtProtoLog.v(
            ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE,
            "DesktopModeLogger: Logging task remove, session: %s taskId: %s",
            sessionId, taskUpdate.instanceId
        )
        FrameworkStatsLog.write(DESKTOP_MODE_TASK_UPDATE_ATOM_ID,
            /* task_event */
            FrameworkStatsLog.DESKTOP_MODE_SESSION_TASK_UPDATE__TASK_EVENT__TASK_REMOVED,
            /* instance_id */
            taskUpdate.instanceId,
            /* uid */
            taskUpdate.uid,
            /* task_height */
            taskUpdate.taskHeight,
            /* task_width */
            taskUpdate.taskWidth,
            /* task_x */
            taskUpdate.taskX,
            /* task_y */
            taskUpdate.taskY,
            /* session_id */
            sessionId)
    }

    /**
     * Logs that the task with update [taskUpdate] had it's info changed in the desktop mode session
     * having session id [sessionId]
     */
    fun logTaskInfoChanged(sessionId: Int, taskUpdate: TaskUpdate) {
        KtProtoLog.v(
            ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE,
            "DesktopModeLogger: Logging task info changed, session: %s taskId: %s",
            sessionId, taskUpdate.instanceId
        )
        FrameworkStatsLog.write(DESKTOP_MODE_TASK_UPDATE_ATOM_ID,
            /* task_event */
            FrameworkStatsLog.DESKTOP_MODE_SESSION_TASK_UPDATE__TASK_EVENT__TASK_INFO_CHANGED,
            /* instance_id */
            taskUpdate.instanceId,
            /* uid */
            taskUpdate.uid,
            /* task_height */
            taskUpdate.taskHeight,
            /* task_width */
            taskUpdate.taskWidth,
            /* task_x */
            taskUpdate.taskX,
            /* task_y */
            taskUpdate.taskY,
            /* session_id */
            sessionId)
    }

    companion object {
        data class TaskUpdate(
            val instanceId: Int,
            val uid: Int,
            val taskHeight: Int = Int.MIN_VALUE,
            val taskWidth: Int = Int.MIN_VALUE,
            val taskX: Int = Int.MIN_VALUE,
            val taskY: Int = Int.MIN_VALUE,
        )

        /**
         * Enum EnterReason mapped to the EnterReason definition in
         * stats/atoms/desktopmode/desktopmode_extensions_atoms.proto
         */
        enum class EnterReason(val reason: Int) {
            UNKNOWN_ENTER(
                FrameworkStatsLog.DESKTOP_MODE_UICHANGED__ENTER_REASON__UNKNOWN_ENTER
            ),
            OVERVIEW(
                FrameworkStatsLog.DESKTOP_MODE_UICHANGED__ENTER_REASON__OVERVIEW
            ),
            APP_HANDLE_DRAG(
                FrameworkStatsLog.DESKTOP_MODE_UICHANGED__ENTER_REASON__APP_HANDLE_DRAG
            ),
            APP_HANDLE_MENU_BUTTON(
                FrameworkStatsLog.DESKTOP_MODE_UICHANGED__ENTER_REASON__APP_HANDLE_MENU_BUTTON
            ),
            APP_FREEFORM_INTENT(
                FrameworkStatsLog.DESKTOP_MODE_UICHANGED__ENTER_REASON__APP_FREEFORM_INTENT
            ),
            KEYBOARD_SHORTCUT_ENTER(
                FrameworkStatsLog.DESKTOP_MODE_UICHANGED__ENTER_REASON__KEYBOARD_SHORTCUT_ENTER
            ),
            SCREEN_ON(
                FrameworkStatsLog.DESKTOP_MODE_UICHANGED__ENTER_REASON__SCREEN_ON
            );
        }

        /**
         * Enum ExitReason mapped to the ExitReason definition in
         * stats/atoms/desktopmode/desktopmode_extensions_atoms.proto
         */
        enum class ExitReason(val reason: Int) {
            UNKNOWN_EXIT(
                FrameworkStatsLog.DESKTOP_MODE_UICHANGED__EXIT_REASON__UNKNOWN_EXIT
            ),
            DRAG_TO_EXIT(
                FrameworkStatsLog.DESKTOP_MODE_UICHANGED__EXIT_REASON__DRAG_TO_EXIT
            ),
            APP_HANDLE_MENU_BUTTON_EXIT(
                FrameworkStatsLog.DESKTOP_MODE_UICHANGED__EXIT_REASON__APP_HANDLE_MENU_BUTTON_EXIT
            ),
            KEYBOARD_SHORTCUT_EXIT(
                FrameworkStatsLog.DESKTOP_MODE_UICHANGED__EXIT_REASON__KEYBOARD_SHORTCUT_EXIT
            ),
            RETURN_HOME_OR_OVERVIEW(
                FrameworkStatsLog.SPLITSCREEN_UICHANGED__EXIT_REASON__RETURN_HOME
            ),
            TASK_FINISHED(
                FrameworkStatsLog.DESKTOP_MODE_UICHANGED__EXIT_REASON__TASK_FINISHED
            ),
            SCREEN_OFF(
                FrameworkStatsLog.DESKTOP_MODE_UICHANGED__EXIT_REASON__SCREEN_OFF
            )
        }

        private const val DESKTOP_MODE_ATOM_ID = FrameworkStatsLog.DESKTOP_MODE_UI_CHANGED
        private const val DESKTOP_MODE_TASK_UPDATE_ATOM_ID =
            FrameworkStatsLog.DESKTOP_MODE_SESSION_TASK_UPDATE
    }
}
 No newline at end of file
+4 −1
Original line number Diff line number Diff line
@@ -24,7 +24,10 @@ package {

android_test {
    name: "WMShellUnitTests",

    defaults: [
        // For ExtendedMockito dependencies.
        "modules-utils-testable-device-config-defaults",
    ],
    srcs: [
        "**/*.java",
        "**/*.kt",
+169 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 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.wm.shell.desktopmode

import com.android.dx.mockito.inline.extended.ExtendedMockito
import com.android.internal.util.FrameworkStatsLog
import com.android.modules.utils.testing.ExtendedMockitoRule
import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.EnterReason
import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.ExitReason
import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.TaskUpdate
import kotlinx.coroutines.runBlocking
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.mockito.kotlin.eq

/**
 * Tests for [DesktopModeEventLogger].
 */
class DesktopModeEventLoggerTest {

    private val desktopModeEventLogger  = DesktopModeEventLogger()

    @JvmField
    @Rule
    val extendedMockitoRule = ExtendedMockitoRule.Builder(this)
            .mockStatic(FrameworkStatsLog::class.java).build()!!

    @Test
    fun logSessionEnter_enterReason() = runBlocking {
        desktopModeEventLogger.logSessionEnter(sessionId = SESSION_ID, EnterReason.UNKNOWN_ENTER)

        ExtendedMockito.verify {
            FrameworkStatsLog.write(
                eq(FrameworkStatsLog.DESKTOP_MODE_UI_CHANGED),
                /* event */
                eq(FrameworkStatsLog.DESKTOP_MODE_UICHANGED__EVENT__ENTER),
                /* enter_reason */
                eq(FrameworkStatsLog.DESKTOP_MODE_UICHANGED__ENTER_REASON__UNKNOWN_ENTER),
                /* exit_reason */
                eq(0),
                /* sessionId */
                eq(SESSION_ID)
            )
        }
    }

    @Test
    fun logSessionExit_exitReason() = runBlocking {
        desktopModeEventLogger.logSessionExit(sessionId = SESSION_ID, ExitReason.UNKNOWN_EXIT)

        ExtendedMockito.verify {
            FrameworkStatsLog.write(
                eq(FrameworkStatsLog.DESKTOP_MODE_UI_CHANGED),
                /* event */
                eq(FrameworkStatsLog.DESKTOP_MODE_UICHANGED__EVENT__EXIT),
                /* enter_reason */
                eq(0),
                /* exit_reason */
                eq(FrameworkStatsLog.DESKTOP_MODE_UICHANGED__EXIT_REASON__UNKNOWN_EXIT),
                /* sessionId */
                eq(SESSION_ID)
            )
        }
    }

    @Test
    fun logTaskAdded_taskUpdate() = runBlocking {
        desktopModeEventLogger.logTaskAdded(sessionId = SESSION_ID, TASK_UPDATE)

        ExtendedMockito.verify {
            FrameworkStatsLog.write(eq(FrameworkStatsLog.DESKTOP_MODE_SESSION_TASK_UPDATE),
                /* task_event */
                eq(FrameworkStatsLog.DESKTOP_MODE_SESSION_TASK_UPDATE__TASK_EVENT__TASK_ADDED),
                /* instance_id */
                eq(TASK_UPDATE.instanceId),
                /* uid */
                eq(TASK_UPDATE.uid),
                /* task_height */
                eq(TASK_UPDATE.taskHeight),
                /* task_width */
                eq(TASK_UPDATE.taskWidth),
                /* task_x */
                eq(TASK_UPDATE.taskX),
                /* task_y */
                eq(TASK_UPDATE.taskY),
                /* session_id */
                eq(SESSION_ID))
        }
    }

    @Test
    fun logTaskRemoved_taskUpdate() = runBlocking {
        desktopModeEventLogger.logTaskRemoved(sessionId = SESSION_ID, TASK_UPDATE)

        ExtendedMockito.verify {
            FrameworkStatsLog.write(eq(FrameworkStatsLog.DESKTOP_MODE_SESSION_TASK_UPDATE),
                /* task_event */
                eq(FrameworkStatsLog.DESKTOP_MODE_SESSION_TASK_UPDATE__TASK_EVENT__TASK_REMOVED),
                /* instance_id */
                eq(TASK_UPDATE.instanceId),
                /* uid */
                eq(TASK_UPDATE.uid),
                /* task_height */
                eq(TASK_UPDATE.taskHeight),
                /* task_width */
                eq(TASK_UPDATE.taskWidth),
                /* task_x */
                eq(TASK_UPDATE.taskX),
                /* task_y */
                eq(TASK_UPDATE.taskY),
                /* session_id */
                eq(SESSION_ID))
        }
    }

    @Test
    fun logTaskInfoChanged_taskUpdate() = runBlocking {
        desktopModeEventLogger.logTaskInfoChanged(sessionId = SESSION_ID, TASK_UPDATE)

        ExtendedMockito.verify {
            FrameworkStatsLog.write(eq(FrameworkStatsLog.DESKTOP_MODE_SESSION_TASK_UPDATE),
                /* task_event */
                eq(FrameworkStatsLog.DESKTOP_MODE_SESSION_TASK_UPDATE__TASK_EVENT__TASK_INFO_CHANGED),
                /* instance_id */
                eq(TASK_UPDATE.instanceId),
                /* uid */
                eq(TASK_UPDATE.uid),
                /* task_height */
                eq(TASK_UPDATE.taskHeight),
                /* task_width */
                eq(TASK_UPDATE.taskWidth),
                /* task_x */
                eq(TASK_UPDATE.taskX),
                /* task_y */
                eq(TASK_UPDATE.taskY),
                /* session_id */
                eq(SESSION_ID))
        }
    }

    companion object {
        private const val SESSION_ID = 1
        private const val TASK_ID = 1
        private const val TASK_UID = 1
        private const val TASK_X = 0
        private const val TASK_Y = 0
        private const val TASK_HEIGHT = 100
        private const val TASK_WIDTH = 100

        private val TASK_UPDATE = TaskUpdate(
            TASK_ID, TASK_UID, TASK_HEIGHT, TASK_WIDTH, TASK_X, TASK_Y
        )
    }
}
 No newline at end of file