1 /*
2  * Copyright (C) 2023 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.permissioncontroller.permission.util
18 
19 import android.Manifest.permission.READ_CONTACTS
20 import android.Manifest.permission_group.ACTIVITY_RECOGNITION
21 import android.Manifest.permission_group.CALENDAR
22 import android.Manifest.permission_group.CALL_LOG
23 import android.Manifest.permission_group.CAMERA
24 import android.Manifest.permission_group.CONTACTS
25 import android.Manifest.permission_group.LOCATION
26 import android.Manifest.permission_group.MICROPHONE
27 import android.Manifest.permission_group.NEARBY_DEVICES
28 import android.Manifest.permission_group.PHONE
29 import android.Manifest.permission_group.READ_MEDIA_AURAL
30 import android.Manifest.permission_group.READ_MEDIA_VISUAL
31 import android.Manifest.permission_group.SENSORS
32 import android.Manifest.permission_group.SMS
33 import android.Manifest.permission_group.STORAGE
34 import android.Manifest.permission_group.UNDEFINED
35 import android.content.ComponentName
36 import android.content.Context
37 import android.content.Intent
38 import android.content.SharedPreferences
39 import android.content.pm.PackageManager.NameNotFoundException
40 import android.content.res.Resources
41 import androidx.test.platform.app.InstrumentationRegistry
42 import com.android.permissioncontroller.Constants.EXTRA_SESSION_ID
43 import com.android.permissioncontroller.Constants.INVALID_SESSION_ID
44 import com.android.permissioncontroller.R
45 import com.android.permissioncontroller.permission.utils.Utils
46 import com.android.permissioncontroller.privacysources.WorkPolicyInfo
47 import com.google.common.truth.Truth.assertThat
48 import kotlin.test.assertFailsWith
49 import org.junit.Ignore
50 import org.junit.Test
51 
52 class UtilsTest {
53     private val context = InstrumentationRegistry.getInstrumentation().targetContext as Context
54 
55     @Test
getAbsoluteTimeString_zero_returnsNullnull56     fun getAbsoluteTimeString_zero_returnsNull() {
57         assertThat(Utils.getAbsoluteTimeString(context, 0)).isNull()
58     }
59 
60     @Test
getAbsoluteTimeString_currentTime_returnsTimeFormatStringnull61     fun getAbsoluteTimeString_currentTime_returnsTimeFormatString() {
62         val time = Utils.getAbsoluteTimeString(context, System.currentTimeMillis())
63         assertThat(time).isNotNull()
64         if (time != null) {
65             if (time.contains(":")) {
66                 val times = time.split(":")
67                 assertThat(times.size).isEqualTo(2)
68                 val isTime = times[1].contains("am", true) || times[1].contains("pm", true)
69                 assertThat(isTime).isTrue()
70             } else {
71                 assertThat(time.contains(".")).isTrue()
72                 val times = time.split(".")
73                 assertThat(times.size).isEqualTo(3)
74             }
75         }
76     }
77 
78     @Test
getAbsoluteTimeString_previousDateTime_returnsDateFormatStringnull79     fun getAbsoluteTimeString_previousDateTime_returnsDateFormatString() {
80         val lastAccessTime = 1680739840723L
81         val time = Utils.getAbsoluteTimeString(context, lastAccessTime)
82         assertThat(time == "Apr 5, 2023" || time == "Apr 6, 2023").isTrue()
83     }
84 
85     @Test
getBlockedIcon_invalidGroupName_returnsMinusOnenull86     fun getBlockedIcon_invalidGroupName_returnsMinusOne() {
87         assertThat(Utils.getBlockedIcon(INVALID_GROUP_NAME)).isEqualTo(-1)
88     }
89 
90     @Test
getBlockedIcon_validGroupNamenull91     fun getBlockedIcon_validGroupName() {
92         assertThat(Utils.getBlockedIcon(CAMERA)).isEqualTo(R.drawable.ic_camera_blocked)
93     }
94 
95     @Test
getBlockedTitle_invalidGroupName_returnsMinusOnenull96     fun getBlockedTitle_invalidGroupName_returnsMinusOne() {
97         assertThat(Utils.getBlockedTitle(INVALID_GROUP_NAME)).isEqualTo(-1)
98     }
99     @Test
getBlockedTitle_validGroupNamenull100     fun getBlockedTitle_validGroupName() {
101         assertThat(Utils.getBlockedTitle(CAMERA)).isEqualTo(R.string.blocked_camera_title)
102     }
103 
104     @Test
getDeviceProtectedSharedPreferencesnull105     fun getDeviceProtectedSharedPreferences() {
106         assertThat(Utils.getDeviceProtectedSharedPreferences(context))
107             .isInstanceOf(SharedPreferences::class.java)
108     }
109 
110     @Test
111     @Ignore("b/277782895")
getEnterpriseStringnull112     fun getEnterpriseString() {
113         assertThat(
114                 Utils.getEnterpriseString(
115                     context,
116                     WorkPolicyInfo.WORK_POLICY_TITLE,
117                     R.string.work_policy_title
118                 )
119             )
120             .isInstanceOf(String::class.java)
121     }
122 
123     @Test
getOneTimePermissionsTimeout_returnsNonNegativeTimeoutnull124     fun getOneTimePermissionsTimeout_returnsNonNegativeTimeout() {
125         assertThat(Utils.getOneTimePermissionsTimeout()).isGreaterThan(0L)
126     }
127 
128     @Test
getOneTimePermissionsKilledDelaySelfRevokednull129     fun getOneTimePermissionsKilledDelaySelfRevoked() {
130         assertThat(Utils.getOneTimePermissionsKilledDelay(true)).isEqualTo(0)
131     }
132 
133     @Test
getOneTimePermissionsKilledDelayNonSelfRevokednull134     fun getOneTimePermissionsKilledDelayNonSelfRevoked() {
135         assertThat(Utils.getOneTimePermissionsKilledDelay(false)).isAtLeast(0L)
136     }
137 
138     @Test
getPackageInfoForComponentName_NonExistComponent_throwsNameNotFoundExceptionnull139     fun getPackageInfoForComponentName_NonExistComponent_throwsNameNotFoundException() {
140         val testComponent = ComponentName("com.test.package", "TestClass")
141         assertFailsWith<NameNotFoundException> {
142             Utils.getPackageInfoForComponentName(context, testComponent)
143         }
144     }
145 
146     @Test
getPermissionGroupDescriptionString_undefinedPermissionGroupnull147     fun getPermissionGroupDescriptionString_undefinedPermissionGroup() {
148         val description = "test permission group description"
149         val resultString =
150             context.getString(R.string.permission_description_summary_generic, description)
151         assertThat(Utils.getPermissionGroupDescriptionString(context, UNDEFINED, description))
152             .isEqualTo(resultString)
153     }
154 
155     @Test
getPermissionGroupDescriptionString_validPermissionGroupnull156     fun getPermissionGroupDescriptionString_validPermissionGroup() {
157         val permissionGroupNames =
158             listOf(
159                 ACTIVITY_RECOGNITION,
160                 CALENDAR,
161                 CALL_LOG,
162                 CAMERA,
163                 CONTACTS,
164                 LOCATION,
165                 MICROPHONE,
166                 NEARBY_DEVICES,
167                 PHONE,
168                 READ_MEDIA_AURAL,
169                 READ_MEDIA_VISUAL,
170                 SENSORS,
171                 SMS,
172                 STORAGE
173             )
174         for (permissionGroupName in permissionGroupNames) {
175             assertThat(Utils.getPermissionGroupDescriptionString(context, permissionGroupName, ""))
176                 .isNotNull()
177         }
178     }
179 
180     @Test
getPermissionLastAccessSummaryTimestamp_lastAccessSummaryTimestampIsNullnull181     fun getPermissionLastAccessSummaryTimestamp_lastAccessSummaryTimestampIsNull() {
182         val result = Utils.getPermissionLastAccessSummaryTimestamp(null, context, LOCATION)
183         assertThat(result.first).isEqualTo("")
184         assertThat(result.second).isEqualTo(Utils.NOT_IN_LAST_7D)
185         assertThat(result.third).isEqualTo("")
186     }
187 
188     @Test
getPermissionLastAccessSummaryTimestamp_sensorDataPermission_lastAccessSummaryTimestampIsTodaynull189     fun getPermissionLastAccessSummaryTimestamp_sensorDataPermission_lastAccessSummaryTimestampIsToday() {
190         val result =
191             Utils.getPermissionLastAccessSummaryTimestamp(
192                 System.currentTimeMillis(),
193                 context,
194                 LOCATION
195             )
196         assertThat(result.first).isNotEmpty()
197         assertThat(result.second).isEqualTo(Utils.LAST_24H_SENSOR_TODAY)
198         assertThat(result.third).isNotEmpty()
199     }
200 
201     @Test
getPermissionLastAccessSummaryTimestamp_sensorDataPermission_lastAccessSummaryTimestampIsYesterdaynull202     fun getPermissionLastAccessSummaryTimestamp_sensorDataPermission_lastAccessSummaryTimestampIsYesterday() {
203         val result =
204             Utils.getPermissionLastAccessSummaryTimestamp(
205                 System.currentTimeMillis() - 24 * 60 * 60 * 1000,
206                 context,
207                 LOCATION
208             )
209         assertThat(result.first).isNotEmpty()
210         assertThat(result.second).isEqualTo(Utils.LAST_24H_SENSOR_YESTERDAY)
211         assertThat(result.third).isNotEmpty()
212     }
213 
214     @Test
getPermissionLastAccessSummaryTimestamp_sensorDataPermission_lastAccessSummaryTimestampIsLast7Daysnull215     fun getPermissionLastAccessSummaryTimestamp_sensorDataPermission_lastAccessSummaryTimestampIsLast7Days() {
216         val result =
217             Utils.getPermissionLastAccessSummaryTimestamp(
218                 System.currentTimeMillis() - 5 * 24 * 60 * 60 * 1000,
219                 context,
220                 LOCATION
221             )
222         assertThat(result.first).isNotEmpty()
223         assertThat(result.second).isEqualTo(Utils.LAST_7D_SENSOR)
224         assertThat(result.third).isNotEmpty()
225     }
226 
227     @Test
getPermissionLastAccessSummaryTimestamp_nonSensorDataPermission_lastAccessSummaryTimestampIsLast24Hrsnull228     fun getPermissionLastAccessSummaryTimestamp_nonSensorDataPermission_lastAccessSummaryTimestampIsLast24Hrs() {
229         val result =
230             Utils.getPermissionLastAccessSummaryTimestamp(
231                 System.currentTimeMillis(),
232                 context,
233                 STORAGE
234             )
235         assertThat(result.first).isNotEmpty()
236         assertThat(result.second).isEqualTo(Utils.LAST_24H_CONTENT_PROVIDER)
237         assertThat(result.third).isNotEmpty()
238     }
239 
240     @Test
getPermissionLastAccessSummaryTimestamp_nonSensorDataPermission_lastAccessSummaryTimestampIs7Daysnull241     fun getPermissionLastAccessSummaryTimestamp_nonSensorDataPermission_lastAccessSummaryTimestampIs7Days() {
242         val result =
243             Utils.getPermissionLastAccessSummaryTimestamp(
244                 System.currentTimeMillis() - 5 * 60 * 60 * 24 * 1000,
245                 context,
246                 STORAGE
247             )
248         assertThat(result.first).isNotEmpty()
249         assertThat(result.second).isEqualTo(Utils.LAST_7D_CONTENT_PROVIDER)
250         assertThat(result.third).isNotEmpty()
251     }
252 
253     @Test
getOrGenerateSessionId_validSessionIdnull254     fun getOrGenerateSessionId_validSessionId() {
255         val intent = Intent()
256         intent.putExtra(EXTRA_SESSION_ID, VALID_SESSION_ID)
257         val sessionId = Utils.getOrGenerateSessionId(intent)
258         assertThat(sessionId).isEqualTo(VALID_SESSION_ID)
259     }
260 
261     @Test
getOrGenerateSessionId_invalidSessionIdnull262     fun getOrGenerateSessionId_invalidSessionId() {
263         val intent = Intent()
264         val sessionId = Utils.getOrGenerateSessionId(intent)
265         assertThat(sessionId).isNotEqualTo(INVALID_SESSION_ID)
266     }
267 
268     @Test
getGroupPermissionInfos_validGroupName_returnsGroupPermissionsnull269     fun getGroupPermissionInfos_validGroupName_returnsGroupPermissions() {
270         val permissionInfos = Utils.getGroupPermissionInfos(CONTACTS, context)
271         assertThat(permissionInfos).isNotNull()
272         val permissions = mutableListOf<String>()
273         for (permissionInfo in permissionInfos!!) {
274             permissions.add(permissionInfo.name)
275         }
276         assertThat(permissions.contains(READ_CONTACTS)).isTrue()
277     }
278 
279     @Test
getGroupPermissionInfos_inValidGroup_returnsNullnull280     fun getGroupPermissionInfos_inValidGroup_returnsNull() {
281         assertThat(Utils.getGroupPermissionInfos(INVALID_GROUP_NAME, context)).isNull()
282     }
283 
284     @Test
getGroupPermissionInfos_undefinedGroup_returnsAllSystemPermissionsnull285     fun getGroupPermissionInfos_undefinedGroup_returnsAllSystemPermissions() {
286         val permissionInfos = Utils.getGroupPermissionInfos(UNDEFINED, context)
287         assertThat(permissionInfos).isNotNull()
288     }
289 
290     @Test
getGroupPermissionInfo_permissionName_returnsSamePermissionnull291     fun getGroupPermissionInfo_permissionName_returnsSamePermission() {
292         val permissionInfos = Utils.getGroupPermissionInfos(READ_CONTACTS, context)
293         assertThat(permissionInfos).isNotNull()
294         assertThat(permissionInfos!!.size).isEqualTo(1)
295         assertThat(permissionInfos[0].name).isEqualTo(READ_CONTACTS)
296     }
297 
298     @Test
getColorResId_validId_returnsNonZeronull299     fun getColorResId_validId_returnsNonZero() {
300         assertThat(Utils.getColorResId(context, android.R.attr.colorPrimary))
301             .isNotEqualTo(Resources.ID_NULL)
302     }
303 
304     @Test
getColorResId_inValidId_returnsZeronull305     fun getColorResId_inValidId_returnsZero() {
306         assertThat(Utils.getColorResId(context, INVALID_ATTR_ID)).isEqualTo(Resources.ID_NULL)
307     }
308 
309     companion object {
310         private const val INVALID_ATTR_ID = 1000
311         private const val VALID_SESSION_ID = 10000L
312         private const val INVALID_GROUP_NAME = "invalid group name"
313     }
314 }
315