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

Commit 8f0e54c7 authored by Mark Renouf's avatar Mark Renouf
Browse files

Test coverage for Work and Private profile policies

Bug: 327613051
Test: atest WorkProfilePolicyTest PrivateProfilePolicyTest
Flag: NONE
Change-Id: I7c9095ce112c0465d0e2ba46ae6a97f12082b5ab
parent 9be7dbc6
Loading
Loading
Loading
Loading
+8 −6
Original line number Diff line number Diff line
@@ -39,11 +39,11 @@ constructor(
    override suspend fun check(content: DisplayContentModel): PolicyResult {
        // The systemUI notification shade isn't a private profile app, skip.
        if (content.systemUiState.shadeExpanded) {
            return NotMatched(policy = NAME, reason = "Notification shade is expanded")
            return NotMatched(policy = NAME, reason = SHADE_EXPANDED)
        }

        // Find the first visible rootTaskInfo with a child task owned by a private user
        val (rootTask, childTask) =
        val childTask =
            content.rootTasks
                .filter { it.isVisible }
                .firstNotNullOfOrNull { root ->
@@ -52,22 +52,24 @@ constructor(
                        .firstOrNull {
                            profileTypes.getProfileType(it.userId) == ProfileType.PRIVATE
                        }
                        ?.let { root to it }
                }
                ?: return NotMatched(policy = NAME, reason = "No private profile tasks are visible")
                ?: return NotMatched(policy = NAME, reason = NO_VISIBLE_TASKS)

        // If matched, return parameters needed to modify the request.
        return Matched(
            policy = NAME,
            reason = "At least one private profile task is visible",
            reason = PRIVATE_TASK_VISIBLE,
            CaptureParameters(
                type = FullScreen(content.displayId),
                component = childTask.componentName ?: rootTask.topActivity,
                component = content.rootTasks.first { it.isVisible }.topActivity,
                owner = UserHandle.of(childTask.userId),
            )
        )
    }
    companion object {
        const val NAME = "PrivateProfile"
        const val SHADE_EXPANDED = "Notification shade is expanded"
        const val NO_VISIBLE_TASKS = "No private profile tasks are visible"
        const val PRIVATE_TASK_VISIBLE = "At least one private profile task is visible"
    }
}
+8 −4
Original line number Diff line number Diff line
@@ -41,7 +41,7 @@ constructor(
    override suspend fun check(content: DisplayContentModel): PolicyResult {
        // The systemUI notification shade isn't a work app, skip.
        if (content.systemUiState.shadeExpanded) {
            return NotMatched(policy = NAME, reason = "Notification shade is expanded")
            return NotMatched(policy = NAME, reason = SHADE_EXPANDED)
        }

        // Find the first non PiP rootTask with a top child task owned by a work user
@@ -54,13 +54,13 @@ constructor(
                }
                ?: return NotMatched(
                    policy = NAME,
                    reason = "The top-most non-PINNED task does not belong to a work profile user"
                    reason = WORK_TASK_NOT_TOP,
                )

        // If matched, return parameters needed to modify the request.
        return PolicyResult.Matched(
            policy = NAME,
            reason = "The top-most non-PINNED task ($childTask) belongs to a work profile user",
            reason = WORK_TASK_IS_TOP,
            CaptureParameters(
                type = IsolatedTask(taskId = childTask.id, taskBounds = childTask.bounds),
                component = childTask.componentName ?: rootTask.topActivity,
@@ -70,6 +70,10 @@ constructor(
    }

    companion object {
        val NAME = "WorkProfile"
        const val NAME = "WorkProfile"
        const val SHADE_EXPANDED = "Notification shade is expanded"
        const val WORK_TASK_NOT_TOP =
            "The top-most non-PINNED task does not belong to a work profile user"
        const val WORK_TASK_IS_TOP = "The top-most non-PINNED task belongs to a work profile user"
    }
}
+225 −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.systemui.screenshot.policy

import android.content.ComponentName
import android.os.UserHandle
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.screenshot.data.model.DisplayContentModel
import com.android.systemui.screenshot.data.model.DisplayContentScenarios.ActivityNames.FILES
import com.android.systemui.screenshot.data.model.DisplayContentScenarios.ActivityNames.YOUTUBE
import com.android.systemui.screenshot.data.model.DisplayContentScenarios.ActivityNames.YOUTUBE_PIP
import com.android.systemui.screenshot.data.model.DisplayContentScenarios.RootTasks.emptyRootSplit
import com.android.systemui.screenshot.data.model.DisplayContentScenarios.RootTasks.fullScreen
import com.android.systemui.screenshot.data.model.DisplayContentScenarios.RootTasks.launcher
import com.android.systemui.screenshot.data.model.DisplayContentScenarios.TaskSpec
import com.android.systemui.screenshot.data.model.DisplayContentScenarios.pictureInPictureApp
import com.android.systemui.screenshot.data.model.DisplayContentScenarios.singleFullScreen
import com.android.systemui.screenshot.data.model.DisplayContentScenarios.splitScreenApps
import com.android.systemui.screenshot.data.model.SystemUiState
import com.android.systemui.screenshot.data.repository.profileTypeRepository
import com.android.systemui.screenshot.policy.CapturePolicy.PolicyResult.Matched
import com.android.systemui.screenshot.policy.CapturePolicy.PolicyResult.NotMatched
import com.android.systemui.screenshot.policy.CaptureType.FullScreen
import com.android.systemui.screenshot.policy.TestUserIds.PERSONAL
import com.android.systemui.screenshot.policy.TestUserIds.PRIVATE
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.test.runTest
import org.junit.Test

class PrivateProfilePolicyTest {
    private val kosmos = Kosmos()
    private val policy = PrivateProfilePolicy(kosmos.profileTypeRepository)

    // TODO:
    // private app in PIP
    // private app below personal PIP app
    // Freeform windows

    @Test
    fun shadeExpanded_notMatched() = runTest {
        val result =
            policy.check(
                singleFullScreen(
                    spec = TaskSpec(taskId = 1002, name = YOUTUBE, userId = PRIVATE),
                    shadeExpanded = true
                )
            )

        assertThat(result)
            .isEqualTo(NotMatched(PrivateProfilePolicy.NAME, PrivateProfilePolicy.SHADE_EXPANDED))
    }

    @Test
    fun noPrivate_notMatched() = runTest {
        val result =
            policy.check(
                singleFullScreen(TaskSpec(taskId = 1002, name = YOUTUBE, userId = PERSONAL))
            )

        assertThat(result)
            .isEqualTo(NotMatched(PrivateProfilePolicy.NAME, PrivateProfilePolicy.NO_VISIBLE_TASKS))
    }

    @Test
    fun withPrivateFullScreen_isMatched() = runTest {
        val result =
            policy.check(
                singleFullScreen(TaskSpec(taskId = 1002, name = YOUTUBE, userId = PRIVATE))
            )

        assertThat(result)
            .isEqualTo(
                Matched(
                    PrivateProfilePolicy.NAME,
                    PrivateProfilePolicy.PRIVATE_TASK_VISIBLE,
                    CaptureParameters(
                        type = FullScreen(displayId = 0),
                        component = ComponentName.unflattenFromString(YOUTUBE),
                        owner = UserHandle.of(PRIVATE)
                    )
                )
            )
    }

    @Test
    fun withPrivateNotVisible_notMatched() = runTest {
        val result =
            policy.check(
                DisplayContentModel(
                    displayId = 0,
                    systemUiState = SystemUiState(shadeExpanded = false),
                    rootTasks =
                        listOf(
                            fullScreen(
                                TaskSpec(taskId = 1002, name = FILES, userId = PERSONAL),
                                visible = true
                            ),
                            fullScreen(
                                TaskSpec(taskId = 1003, name = YOUTUBE, userId = PRIVATE),
                                visible = false
                            ),
                            launcher(visible = false),
                            emptyRootSplit,
                        )
                )
            )

        assertThat(result)
            .isEqualTo(
                NotMatched(
                    PrivateProfilePolicy.NAME,
                    PrivateProfilePolicy.NO_VISIBLE_TASKS,
                )
            )
    }

    @Test
    fun withPrivateFocusedInSplitScreen_isMatched() = runTest {
        val result =
            policy.check(
                splitScreenApps(
                    top = TaskSpec(taskId = 1002, name = FILES, userId = PERSONAL),
                    bottom = TaskSpec(taskId = 1003, name = YOUTUBE, userId = PRIVATE),
                    focusedTaskId = 1003
                )
            )

        assertThat(result)
            .isEqualTo(
                Matched(
                    PrivateProfilePolicy.NAME,
                    PrivateProfilePolicy.PRIVATE_TASK_VISIBLE,
                    CaptureParameters(
                        type = FullScreen(displayId = 0),
                        component = ComponentName.unflattenFromString(YOUTUBE),
                        owner = UserHandle.of(PRIVATE)
                    )
                )
            )
    }

    @Test
    fun withPrivateNotFocusedInSplitScreen_isMatched() = runTest {
        val result =
            policy.check(
                splitScreenApps(
                    top = TaskSpec(taskId = 1002, name = FILES, userId = PERSONAL),
                    bottom = TaskSpec(taskId = 1003, name = YOUTUBE, userId = PRIVATE),
                    focusedTaskId = 1002
                )
            )

        assertThat(result)
            .isEqualTo(
                Matched(
                    PrivateProfilePolicy.NAME,
                    PrivateProfilePolicy.PRIVATE_TASK_VISIBLE,
                    CaptureParameters(
                        type = FullScreen(displayId = 0),
                        component = ComponentName.unflattenFromString(FILES),
                        owner = UserHandle.of(PRIVATE)
                    )
                )
            )
    }

    @Test
    fun withPrivatePictureInPictureApp_isMatched() = runTest {
        val result =
            policy.check(
                pictureInPictureApp(TaskSpec(taskId = 1002, name = YOUTUBE_PIP, userId = PRIVATE))
            )

        assertThat(result)
            .isEqualTo(
                Matched(
                    PrivateProfilePolicy.NAME,
                    PrivateProfilePolicy.PRIVATE_TASK_VISIBLE,
                    CaptureParameters(
                        type = FullScreen(displayId = 0),
                        component = ComponentName.unflattenFromString(YOUTUBE_PIP),
                        owner = UserHandle.of(PRIVATE)
                    )
                )
            )
    }

    @Test
    fun withPrivateAppBelowPictureInPictureApp_isMatched() = runTest {
        val result =
            policy.check(
                pictureInPictureApp(
                    pip = TaskSpec(taskId = 1002, name = YOUTUBE_PIP, userId = PERSONAL),
                    fullScreen = TaskSpec(taskId = 1003, name = FILES, userId = PRIVATE),
                )
            )

        assertThat(result)
            .isEqualTo(
                Matched(
                    PrivateProfilePolicy.NAME,
                    PrivateProfilePolicy.PRIVATE_TASK_VISIBLE,
                    CaptureParameters(
                        type = FullScreen(displayId = 0),
                        component = ComponentName.unflattenFromString(YOUTUBE_PIP),
                        owner = UserHandle.of(PRIVATE)
                    )
                )
            )
    }
}
+196 −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.systemui.screenshot.policy

import android.content.ComponentName
import android.os.UserHandle
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.screenshot.data.model.DisplayContentScenarios.ActivityNames.FILES
import com.android.systemui.screenshot.data.model.DisplayContentScenarios.ActivityNames.YOUTUBE
import com.android.systemui.screenshot.data.model.DisplayContentScenarios.Bounds.FREE_FORM
import com.android.systemui.screenshot.data.model.DisplayContentScenarios.Bounds.FULL_SCREEN
import com.android.systemui.screenshot.data.model.DisplayContentScenarios.Bounds.SPLIT_TOP
import com.android.systemui.screenshot.data.model.DisplayContentScenarios.TaskSpec
import com.android.systemui.screenshot.data.model.DisplayContentScenarios.freeFormApps
import com.android.systemui.screenshot.data.model.DisplayContentScenarios.pictureInPictureApp
import com.android.systemui.screenshot.data.model.DisplayContentScenarios.singleFullScreen
import com.android.systemui.screenshot.data.model.DisplayContentScenarios.splitScreenApps
import com.android.systemui.screenshot.data.repository.profileTypeRepository
import com.android.systemui.screenshot.policy.CapturePolicy.PolicyResult
import com.android.systemui.screenshot.policy.CapturePolicy.PolicyResult.NotMatched
import com.android.systemui.screenshot.policy.CaptureType.IsolatedTask
import com.android.systemui.screenshot.policy.TestUserIds.PERSONAL
import com.android.systemui.screenshot.policy.TestUserIds.WORK
import com.android.systemui.screenshot.policy.WorkProfilePolicy.Companion.SHADE_EXPANDED
import com.android.systemui.screenshot.policy.WorkProfilePolicy.Companion.WORK_TASK_IS_TOP
import com.android.systemui.screenshot.policy.WorkProfilePolicy.Companion.WORK_TASK_NOT_TOP
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.test.runTest
import org.junit.Test

class WorkProfilePolicyTest {
    private val kosmos = Kosmos()
    private val policy = WorkProfilePolicy(kosmos.profileTypeRepository)

    @Test
    fun noWorkApp_notMatched() = runTest {
        val result =
            policy.check(
                singleFullScreen(TaskSpec(taskId = 1002, name = YOUTUBE, userId = PERSONAL))
            )

        assertThat(result)
            .isEqualTo(
                NotMatched(
                    WorkProfilePolicy.NAME,
                    WORK_TASK_NOT_TOP,
                )
            )
    }

    @Test
    fun withWorkFullScreen_shadeExpanded_notMatched() = runTest {
        val result =
            policy.check(
                singleFullScreen(
                    TaskSpec(taskId = 1002, name = FILES, userId = WORK),
                    shadeExpanded = true
                )
            )

        assertThat(result)
            .isEqualTo(
                NotMatched(
                    WorkProfilePolicy.NAME,
                    SHADE_EXPANDED,
                )
            )
    }

    @Test
    fun withWorkFullScreen_matched() = runTest {
        val result =
            policy.check(singleFullScreen(TaskSpec(taskId = 1002, name = FILES, userId = WORK)))

        assertThat(result)
            .isEqualTo(
                PolicyResult.Matched(
                    policy = WorkProfilePolicy.NAME,
                    reason = WORK_TASK_IS_TOP,
                    CaptureParameters(
                        type = IsolatedTask(taskId = 1002, taskBounds = FULL_SCREEN),
                        component = ComponentName.unflattenFromString(FILES),
                        owner = UserHandle.of(WORK),
                    )
                )
            )
    }

    @Test
    fun withWorkFocusedInSplitScreen_matched() = runTest {
        val result =
            policy.check(
                splitScreenApps(
                    top = TaskSpec(taskId = 1002, name = FILES, userId = WORK),
                    bottom = TaskSpec(taskId = 1003, name = YOUTUBE, userId = PERSONAL),
                    focusedTaskId = 1002
                )
            )

        assertThat(result)
            .isEqualTo(
                PolicyResult.Matched(
                    policy = WorkProfilePolicy.NAME,
                    reason = WORK_TASK_IS_TOP,
                    CaptureParameters(
                        type = IsolatedTask(taskId = 1002, taskBounds = SPLIT_TOP),
                        component = ComponentName.unflattenFromString(FILES),
                        owner = UserHandle.of(WORK),
                    )
                )
            )
    }

    @Test
    fun withWorkNotFocusedInSplitScreen_notMatched() = runTest {
        val result =
            policy.check(
                splitScreenApps(
                    top = TaskSpec(taskId = 1002, name = FILES, userId = WORK),
                    bottom = TaskSpec(taskId = 1003, name = YOUTUBE, userId = PERSONAL),
                    focusedTaskId = 1003
                )
            )

        assertThat(result)
            .isEqualTo(
                NotMatched(
                    WorkProfilePolicy.NAME,
                    WORK_TASK_NOT_TOP,
                )
            )
    }

    @Test
    fun withWorkBelowPersonalPictureInPicture_matched() = runTest {
        val result =
            policy.check(
                pictureInPictureApp(
                    pip = TaskSpec(taskId = 1002, name = YOUTUBE, userId = PERSONAL),
                    fullScreen = TaskSpec(taskId = 1003, name = FILES, userId = WORK),
                )
            )

        assertThat(result)
            .isEqualTo(
                PolicyResult.Matched(
                    policy = WorkProfilePolicy.NAME,
                    reason = WORK_TASK_IS_TOP,
                    CaptureParameters(
                        type = IsolatedTask(taskId = 1003, taskBounds = FULL_SCREEN),
                        component = ComponentName.unflattenFromString(FILES),
                        owner = UserHandle.of(WORK),
                    )
                )
            )
    }

    @Test
    fun withWorkFocusedInFreeForm_matched() = runTest {
        val result =
            policy.check(
                freeFormApps(
                    TaskSpec(taskId = 1002, name = YOUTUBE, userId = PERSONAL),
                    TaskSpec(taskId = 1003, name = FILES, userId = WORK),
                    focusedTaskId = 1003
                )
            )

        assertThat(result)
            .isEqualTo(
                PolicyResult.Matched(
                    policy = WorkProfilePolicy.NAME,
                    reason = WORK_TASK_IS_TOP,
                    CaptureParameters(
                        type = IsolatedTask(taskId = 1003, taskBounds = FREE_FORM),
                        component = ComponentName.unflattenFromString(FILES),
                        owner = UserHandle.of(WORK),
                    )
                )
            )
    }
}