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

Commit a242fec6 authored by Alina Zaidi's avatar Alina Zaidi Committed by Android (Google) Code Review
Browse files

Merge "Add a class for Desktop Mode UIEvent logging." into main

parents 5882d11f 309812ac
Loading
Loading
Loading
Loading
+100 −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 android.util.Log
import com.android.internal.logging.InstanceId
import com.android.internal.logging.InstanceIdSequence
import com.android.internal.logging.UiEvent
import com.android.internal.logging.UiEventLogger
import com.android.wm.shell.dagger.WMSingleton
import javax.inject.Inject

/**
 * Log Aster UIEvents for desktop windowing mode.
 */
@WMSingleton
class DesktopModeUiEventLogger @Inject constructor(
    private val mUiEventLogger: UiEventLogger,
    private val mInstanceIdSequence: InstanceIdSequence
) {
    /**
     * Logs an event for a CUI, on a particular package.
     *
     * @param uid The user id associated with the package the user is interacting with
     * @param packageName The name of the package the user is interacting with
     * @param event The event type to generate
     */
    fun log(uid: Int, packageName: String, event: DesktopUiEventEnum) {
        if (packageName.isEmpty() || uid < 0) {
            Log.d(TAG, "Skip logging since package name is empty or bad uid")
            return
        }
        mUiEventLogger.log(event, uid, packageName)
    }

    /**
     * Retrieves a new instance id for a new interaction.
     */
    fun getNewInstanceId(): InstanceId = mInstanceIdSequence.newInstanceId()

    /**
     * Logs an event as part of a particular CUI, on a particular package.
     *
     * @param instanceId The id identifying an interaction, potentially taking place across multiple
     * surfaces. There should be a new id generated for each distinct CUI.
     * @param uid The user id associated with the package the user is interacting with
     * @param packageName The name of the package the user is interacting with
     * @param event The event type to generate
     */
    fun logWithInstanceId(
        instanceId: InstanceId,
        uid: Int,
        packageName: String,
        event: DesktopUiEventEnum
    ) {
        if (packageName.isEmpty() || uid < 0) {
            Log.d(TAG, "Skip logging since package name is empty or bad uid")
            return
        }
        mUiEventLogger.logWithInstanceId(event, uid, packageName, instanceId)
    }

    companion object {
        /**
         * Enums for logging desktop windowing mode UiEvents.
         */
        enum class DesktopUiEventEnum(private val mId: Int) : UiEventLogger.UiEventEnum {

            @UiEvent(doc = "Resize the window in desktop windowing mode by dragging the edge")
            DESKTOP_WINDOW_EDGE_DRAG_RESIZE(1721),

            @UiEvent(doc = "Resize the window in desktop windowing mode by dragging the corner")
            DESKTOP_WINDOW_CORNER_DRAG_RESIZE(1722),

            @UiEvent(doc = "Tap on the window header maximize button in desktop windowing mode")
            DESKTOP_WINDOW_MAXIMIZE_BUTTON_TAP(1723),

            @UiEvent(doc = "Double tap on window header to maximize it in desktop windowing mode")
            DESKTOP_WINDOW_HEADER_DOUBLE_TAP_TO_MAXIMIZE(1724);

            override fun getId(): Int = mId
        }

        private const val TAG = "DesktopModeUiEventLogger"
    }
}
 No newline at end of file
+111 −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 android.testing.AndroidTestingRunner
import androidx.test.filters.SmallTest
import com.android.internal.logging.InstanceId
import com.android.internal.logging.InstanceIdSequence
import com.android.internal.logging.testing.UiEventLoggerFake
import com.android.wm.shell.ShellTestCase
import com.android.wm.shell.desktopmode.DesktopModeUiEventLogger.Companion.DesktopUiEventEnum.DESKTOP_WINDOW_EDGE_DRAG_RESIZE
import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith

/**
 * Test class for [DesktopModeUiEventLogger]
 *
 * Usage: atest WMShellUnitTests:DesktopModeUiEventLoggerTest
 */
@SmallTest
@RunWith(AndroidTestingRunner::class)
class DesktopModeUiEventLoggerTest : ShellTestCase() {
    private lateinit var uiEventLoggerFake: UiEventLoggerFake
    private lateinit var logger: DesktopModeUiEventLogger
    private val instanceIdSequence = InstanceIdSequence(10)


    @Before
    fun setUp() {
        uiEventLoggerFake = UiEventLoggerFake()
        logger = DesktopModeUiEventLogger(uiEventLoggerFake, instanceIdSequence)
    }

    @Test
    fun log_invalidUid_eventNotLogged() {
        logger.log(-1, PACKAGE_NAME, DESKTOP_WINDOW_EDGE_DRAG_RESIZE)
        assertThat(uiEventLoggerFake.numLogs()).isEqualTo(0)
    }

    @Test
    fun log_emptyPackageName_eventNotLogged() {
        logger.log(UID, "", DESKTOP_WINDOW_EDGE_DRAG_RESIZE)
        assertThat(uiEventLoggerFake.numLogs()).isEqualTo(0)
    }

    @Test
    fun log_eventLogged() {
        val event =
            DESKTOP_WINDOW_EDGE_DRAG_RESIZE
        logger.log(UID, PACKAGE_NAME, event)
        assertThat(uiEventLoggerFake.numLogs()).isEqualTo(1)
        assertThat(uiEventLoggerFake.eventId(0)).isEqualTo(event.id)
        assertThat(uiEventLoggerFake[0].instanceId).isNull()
        assertThat(uiEventLoggerFake[0].uid).isEqualTo(UID)
        assertThat(uiEventLoggerFake[0].packageName).isEqualTo(PACKAGE_NAME)
    }

    @Test
    fun getNewInstanceId() {
        val first = logger.getNewInstanceId()
        assertThat(first).isNotEqualTo(logger.getNewInstanceId())
    }

    @Test
    fun logWithInstanceId_invalidUid_eventNotLogged() {
        logger.logWithInstanceId(INSTANCE_ID, -1, PACKAGE_NAME, DESKTOP_WINDOW_EDGE_DRAG_RESIZE)
        assertThat(uiEventLoggerFake.numLogs()).isEqualTo(0)
    }

    @Test
    fun logWithInstanceId_emptyPackageName_eventNotLogged() {
        logger.logWithInstanceId(INSTANCE_ID, UID, "", DESKTOP_WINDOW_EDGE_DRAG_RESIZE)
        assertThat(uiEventLoggerFake.numLogs()).isEqualTo(0)
    }

    @Test
    fun logWithInstanceId_eventLogged() {
        val event =
            DESKTOP_WINDOW_EDGE_DRAG_RESIZE
        logger.logWithInstanceId(INSTANCE_ID, UID, PACKAGE_NAME, event)
        assertThat(uiEventLoggerFake.numLogs()).isEqualTo(1)
        assertThat(uiEventLoggerFake.eventId(0)).isEqualTo(event.id)
        assertThat(uiEventLoggerFake[0].instanceId).isEqualTo(INSTANCE_ID)
        assertThat(uiEventLoggerFake[0].uid).isEqualTo(UID)
        assertThat(uiEventLoggerFake[0].packageName).isEqualTo(PACKAGE_NAME)
    }


    companion object {
        private val INSTANCE_ID = InstanceId.fakeInstanceId(0)
        private const val UID = 10
        private const val PACKAGE_NAME = "com.foo"
    }
}