1 /** 2 * Copyright (C) 2024 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 * in compliance with the License. You may obtain a copy of the License at 6 * 7 * ``` 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * ``` 10 * 11 * Unless required by applicable law or agreed to in writing, software distributed under the License 12 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 13 * or implied. See the License for the specific language governing permissions and limitations under 14 * the License. 15 */ 16 package com.android.healthconnect.controller.permissions.data 17 18 import android.health.connect.HealthPermissions 19 20 sealed class HealthPermission { 21 22 companion object { 23 /** Special health permissions that don't represent health data types. */ 24 private val additionalPermissions = 25 setOf( 26 HealthPermissions.READ_EXERCISE_ROUTES, 27 HealthPermissions.READ_HEALTH_DATA_IN_BACKGROUND, 28 HealthPermissions.READ_HEALTH_DATA_HISTORY) 29 30 /** Permissions that are grouped separately to general health data types */ 31 private val medicalPermissions = 32 setOf( 33 HealthPermissions.WRITE_MEDICAL_DATA, 34 HealthPermissions.READ_MEDICAL_DATA_IMMUNIZATION) 35 fromPermissionStringnull36 fun fromPermissionString(permission: String): HealthPermission { 37 return if (permission in additionalPermissions) { 38 AdditionalPermission.fromPermissionString(permission) 39 } else if (permission in medicalPermissions) { 40 MedicalPermission.fromPermissionString(permission) 41 } else { 42 FitnessPermission.fromPermissionString(permission) 43 } 44 } 45 } 46 47 /** Pair of {@link HealthPermissionType} and {@link PermissionsAccessType}. */ 48 data class FitnessPermission( 49 val healthPermissionType: HealthPermissionType, 50 val permissionsAccessType: PermissionsAccessType 51 ) : HealthPermission() { 52 companion object { 53 private const val READ_PERMISSION_PREFIX = "android.permission.health.READ_" 54 private const val WRITE_PERMISSION_PREFIX = "android.permission.health.WRITE_" 55 fromPermissionStringnull56 fun fromPermissionString(permission: String): FitnessPermission { 57 return if (permission.startsWith(READ_PERMISSION_PREFIX)) { 58 val type = 59 getHealthPermissionType(permission.substring(READ_PERMISSION_PREFIX.length)) 60 FitnessPermission(type, PermissionsAccessType.READ) 61 } else if (permission.startsWith(WRITE_PERMISSION_PREFIX)) { 62 val type = 63 getHealthPermissionType( 64 permission.substring(WRITE_PERMISSION_PREFIX.length)) 65 FitnessPermission(type, PermissionsAccessType.WRITE) 66 } else { 67 throw IllegalArgumentException("Fitness permission not supported! $permission") 68 } 69 } 70 getHealthPermissionTypenull71 private fun getHealthPermissionType(value: String): HealthPermissionType { 72 return HealthPermissionType.valueOf(value) 73 } 74 } 75 toStringnull76 override fun toString(): String { 77 return if (permissionsAccessType == PermissionsAccessType.READ) { 78 "$READ_PERMISSION_PREFIX${healthPermissionType.name}" 79 } else { 80 "$WRITE_PERMISSION_PREFIX${healthPermissionType.name}" 81 } 82 } 83 } 84 85 data class AdditionalPermission(val additionalPermission: String) : HealthPermission() { 86 87 companion object { fromPermissionStringnull88 fun fromPermissionString(permission: String): AdditionalPermission = 89 AdditionalPermission(permission) 90 91 // Predefined instances for convenience 92 val READ_HEALTH_DATA_HISTORY = 93 AdditionalPermission(HealthPermissions.READ_HEALTH_DATA_HISTORY) 94 val READ_HEALTH_DATA_IN_BACKGROUND = 95 AdditionalPermission(HealthPermissions.READ_HEALTH_DATA_IN_BACKGROUND) 96 val READ_EXERCISE_ROUTES = AdditionalPermission(HealthPermissions.READ_EXERCISE_ROUTES) 97 } 98 99 override fun toString(): String { 100 return additionalPermission 101 } 102 isExerciseRoutesPermissionnull103 fun isExerciseRoutesPermission(): Boolean = 104 this.additionalPermission == HealthPermissions.READ_EXERCISE_ROUTES 105 106 fun isBackgroundReadPermission(): Boolean = 107 this.additionalPermission == HealthPermissions.READ_HEALTH_DATA_IN_BACKGROUND 108 109 fun isHistoryReadPermission(): Boolean = 110 this.additionalPermission == HealthPermissions.READ_HEALTH_DATA_HISTORY 111 } 112 113 data class MedicalPermission(val medicalPermissionType: MedicalPermissionType) : 114 HealthPermission() { 115 companion object { 116 private const val WRITE_MEDICAL_DATA = 117 "android.permission.health.WRITE_MEDICAL_DATA" 118 private const val READ_MEDICAL_DATA_PREFIX = 119 "android.permission.health.READ_MEDICAL_DATA_" 120 121 fun fromPermissionString(permission: String): MedicalPermission { 122 return if (permission == WRITE_MEDICAL_DATA) { 123 MedicalPermission(MedicalPermissionType.ALL_MEDICAL_DATA) 124 } else if (permission.startsWith(READ_MEDICAL_DATA_PREFIX)) { 125 val medicalType = 126 getHealthPermissionType( 127 permission.substring(READ_MEDICAL_DATA_PREFIX.length)) 128 MedicalPermission(medicalType) 129 } else { 130 throw IllegalArgumentException(" Medical permission not supported! $permission") 131 } 132 } 133 134 private fun getHealthPermissionType(value: String): MedicalPermissionType { 135 return MedicalPermissionType.valueOf(value) 136 } 137 } 138 139 override fun toString(): String { 140 return if (medicalPermissionType == MedicalPermissionType.ALL_MEDICAL_DATA) { 141 WRITE_MEDICAL_DATA 142 } else { 143 "$READ_MEDICAL_DATA_PREFIX${medicalPermissionType.name}" 144 } 145 } 146 } 147 } 148