1 /*
2  * Copyright 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  *      https://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  */
18 
19 package com.android.healthconnect.controller.permissions.additionalaccess
20 
21 import android.content.pm.PackageManager
22 import android.health.connect.HealthPermissions.READ_EXERCISE
23 import android.health.connect.HealthPermissions.READ_EXERCISE_ROUTES
24 import com.android.healthconnect.controller.permissions.api.GetHealthPermissionsFlagsUseCase
25 import com.android.healthconnect.controller.permissions.api.IGetGrantedHealthPermissionsUseCase
26 import com.android.healthconnect.controller.service.IoDispatcher
27 import com.android.healthconnect.controller.shared.usecase.BaseUseCase
28 import com.android.healthconnect.controller.shared.usecase.UseCaseResults
29 import javax.inject.Inject
30 import javax.inject.Singleton
31 import kotlinx.coroutines.CoroutineDispatcher
32 
33 @Singleton
34 class LoadExerciseRoutePermissionUseCase
35 @Inject
36 constructor(
37     private val loadDeclaredHealthPermissionUseCase: LoadDeclaredHealthPermissionUseCase,
38     private val getHealthPermissionsFlagsUseCase: GetHealthPermissionsFlagsUseCase,
39     private val getGrantedHealthPermissionsUseCase: IGetGrantedHealthPermissionsUseCase,
40     @IoDispatcher dispatcher: CoroutineDispatcher
41 ) : BaseUseCase<String, ExerciseRouteState>(dispatcher), ILoadExerciseRoutePermissionUseCase {
42 
executenull43     override suspend fun execute(input: String): ExerciseRouteState {
44         val grantedPermissions = getGrantedHealthPermissionsUseCase(input)
45         val appPermissions = loadDeclaredHealthPermissionUseCase(input)
46         val permissionFlags =
47             getHealthPermissionsFlagsUseCase(input, listOf(READ_EXERCISE_ROUTES, READ_EXERCISE))
48         return ExerciseRouteState(
49             exerciseRoutePermissionState =
50                 getPermissionState(
51                     READ_EXERCISE_ROUTES, grantedPermissions, appPermissions, permissionFlags),
52             exercisePermissionState =
53                 getPermissionState(
54                     READ_EXERCISE, grantedPermissions, appPermissions, permissionFlags))
55     }
56 
getPermissionStatenull57     private fun getPermissionState(
58         permission: String,
59         grantedPermissions: List<String>,
60         appPermissions: List<String>,
61         permissionFlags: Map<String, Int>
62     ): PermissionUiState {
63 
64         if (grantedPermissions.contains(permission)) {
65             return PermissionUiState.ALWAYS_ALLOW
66         }
67 
68         if (!appPermissions.contains(permission)) {
69             return PermissionUiState.NOT_DECLARED
70         }
71 
72         val flag = permissionFlags[permission] ?: return PermissionUiState.NOT_DECLARED
73         if (flag.and(PackageManager.FLAG_PERMISSION_USER_FIXED) != 0) {
74             return PermissionUiState.NEVER_ALLOW
75         }
76 
77         return PermissionUiState.ASK_EVERY_TIME
78     }
79 }
80 
81 data class ExerciseRouteState(
82     val exerciseRoutePermissionState: PermissionUiState,
83     val exercisePermissionState: PermissionUiState
84 )
85 
86 enum class PermissionUiState {
87     NOT_DECLARED,
88     ASK_EVERY_TIME,
89     ALWAYS_ALLOW,
90     NEVER_ALLOW
91 }
92 
93 interface ILoadExerciseRoutePermissionUseCase {
invokenull94     suspend operator fun invoke(input: String): UseCaseResults<ExerciseRouteState>
95 
96     suspend fun execute(input: String): ExerciseRouteState
97 }
98