1 /*
2  * Copyright (C) 2024 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.systemui.screenshot.message
18 
19 import android.content.ComponentName
20 import androidx.test.ext.junit.runners.AndroidJUnit4
21 import android.content.pm.PackageManager
22 import android.graphics.Canvas
23 import android.graphics.ColorFilter
24 import android.graphics.drawable.Drawable
25 import android.os.UserHandle
26 import com.android.systemui.screenshot.data.model.ProfileType
27 import com.android.systemui.screenshot.data.repository.ProfileTypeRepository
28 import com.google.common.truth.Truth.assertThat
29 import kotlinx.coroutines.test.runTest
30 import org.junit.Test
31 import org.junit.runner.RunWith
32 
33 @RunWith(AndroidJUnit4::class)
34 class ProfileMessageControllerTest {
35     @Test
<lambda>null36     fun personalScreenshot() = runTest {
37         assertThat(
38                 getMessageController()
39                     .onScreenshotTaken(UserHandle.of(profileTypeRepository.personalUser))
40             )
41             .isNull()
42     }
43 
44     @Test
<lambda>null45     fun communalScreenshot() = runTest {
46         assertThat(
47                 getMessageController()
48                     .onScreenshotTaken(UserHandle.of(profileTypeRepository.communalUser))
49             )
50             .isNull()
51     }
52 
53     @Test
<lambda>null54     fun noUserScreenshot() = runTest {
55         assertThat(getMessageController().onScreenshotTaken(null)).isNull()
56     }
57 
58     @Test
<lambda>null59     fun alreadyDismissed() = runTest {
60         val messageController = getMessageController()
61         profileFirstRunSettings.onMessageDismissed(ProfileMessageController.FirstRunProfile.WORK)
62         assertThat(
63                 messageController.onScreenshotTaken(UserHandle.of(profileTypeRepository.workUser))
64             )
65             .isNull()
66     }
67 
68     @Test
<lambda>null69     fun noFileManager() = runTest {
70         val messageController = getMessageController(fileManagerComponent = null)
71         val data =
72             messageController.onScreenshotTaken(UserHandle.of(profileTypeRepository.workUser))
73         assertThat(data?.profileType).isEqualTo(ProfileMessageController.FirstRunProfile.WORK)
74         assertThat(data?.labeledIcon?.label).isEqualTo(DEFAULT_APP_NAME)
75         assertThat(data?.labeledIcon?.badgedIcon).isNull()
76     }
77 
78     @Test
<lambda>null79     fun fileManagerNotFound() = runTest {
80         val messageController =
81             getMessageController(fileManagerComponent = ComponentName("Something", "Random"))
82         val data =
83             messageController.onScreenshotTaken(UserHandle.of(profileTypeRepository.privateUser))
84         assertThat(data?.profileType).isEqualTo(ProfileMessageController.FirstRunProfile.PRIVATE)
85         assertThat(data?.labeledIcon?.label).isEqualTo(DEFAULT_APP_NAME)
86         assertThat(data?.labeledIcon?.badgedIcon).isNull()
87     }
88 
89     @Test
<lambda>null90     fun fileManagerFound() = runTest {
91         val messageController = getMessageController()
92         val data =
93             messageController.onScreenshotTaken(UserHandle.of(profileTypeRepository.privateUser))
94         assertThat(data?.profileType).isEqualTo(ProfileMessageController.FirstRunProfile.PRIVATE)
95         assertThat(data?.labeledIcon?.label).isEqualTo(FILE_MANAGER_LABEL)
96         assertThat(data?.labeledIcon?.badgedIcon).isEqualTo(drawable)
97     }
98 
99     private val drawable =
100         object : Drawable() {
drawnull101             override fun draw(canvas: Canvas) {}
102 
setAlphanull103             override fun setAlpha(alpha: Int) {}
104 
setColorFilternull105             override fun setColorFilter(colorFilter: ColorFilter?) {}
106 
getOpacitynull107             override fun getOpacity(): Int = 0
108         }
109 
110     private val packageLabelIconProvider =
111         object : PackageLabelIconProvider {
112             override suspend fun getPackageLabelIcon(
113                 componentName: ComponentName,
114                 userHandle: UserHandle
115             ): LabeledIcon {
116                 if (componentName.equals(FILE_MANAGER_COMPONENT)) {
117                     return LabeledIcon(FILE_MANAGER_LABEL, drawable)
118                 } else {
119                     throw PackageManager.NameNotFoundException()
120                 }
121             }
122         }
123 
124     private class FakeProfileFirstRunResources(private val fileManager: ComponentName?) :
125         ProfileFirstRunFileResources {
fileManagerComponentNamenull126         override fun fileManagerComponentName(): ComponentName? {
127             return fileManager
128         }
129 
defaultFileAppnull130         override fun defaultFileApp() = LabeledIcon(DEFAULT_APP_NAME, badgedIcon = null)
131     }
132 
133     private val profileFirstRunSettings =
134         object : ProfileFirstRunSettings {
135             private val dismissed =
136                 mutableMapOf(
137                     ProfileMessageController.FirstRunProfile.WORK to false,
138                     ProfileMessageController.FirstRunProfile.PRIVATE to false,
139                 )
140 
141             override fun messageAlreadyDismissed(
142                 profileType: ProfileMessageController.FirstRunProfile
143             ): Boolean {
144                 return dismissed.getOrDefault(profileType, false)
145             }
146 
147             override fun onMessageDismissed(profileType: ProfileMessageController.FirstRunProfile) {
148                 dismissed[profileType] = true
149             }
150         }
151 
152     private val profileTypeRepository =
153         object : ProfileTypeRepository {
getProfileTypenull154             override suspend fun getProfileType(userId: Int): ProfileType {
155                 return when (userId) {
156                     workUser -> ProfileType.WORK
157                     privateUser -> ProfileType.PRIVATE
158                     communalUser -> ProfileType.COMMUNAL
159                     else -> ProfileType.NONE
160                 }
161             }
162 
163             val personalUser = 0
164             val workUser = 1
165             val privateUser = 2
166             val communalUser = 3
167         }
168 
getMessageControllernull169     private fun getMessageController(
170         fileManagerComponent: ComponentName? = FILE_MANAGER_COMPONENT
171     ) =
172         ProfileMessageController(
173             packageLabelIconProvider,
174             FakeProfileFirstRunResources(fileManagerComponent),
175             profileFirstRunSettings,
176             profileTypeRepository
177         )
178 
179     companion object {
180         val FILE_MANAGER_COMPONENT = ComponentName("package", "component")
181         const val DEFAULT_APP_NAME = "default app"
182         const val FILE_MANAGER_LABEL = "file manager"
183     }
184 }
185