1 /** <lambda>null2 * Copyright (C) 2022 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.testapps.toolbox.ui 17 18 import android.content.ComponentName 19 import android.content.Intent 20 import android.content.pm.PackageManager 21 import android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT 22 import android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED 23 import android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED 24 import android.health.connect.HealthConnectManager 25 import android.os.Bundle 26 import android.view.LayoutInflater 27 import android.view.View 28 import android.view.ViewGroup 29 import android.widget.Button 30 import android.widget.Toast 31 import androidx.activity.result.ActivityResultLauncher 32 import androidx.activity.result.contract.ActivityResultContracts 33 import androidx.core.content.ContextCompat 34 import androidx.fragment.app.Fragment 35 import androidx.fragment.app.viewModels 36 import androidx.navigation.NavController 37 import androidx.navigation.fragment.findNavController 38 import com.android.healthconnect.testapps.toolbox.Constants.ADDITIONAL_PERMISSIONS 39 import com.android.healthconnect.testapps.toolbox.Constants.DATA_TYPE_PERMISSIONS 40 import com.android.healthconnect.testapps.toolbox.Constants.HEALTH_PERMISSIONS 41 import com.android.healthconnect.testapps.toolbox.Constants.MEDICAL_PERMISSIONS 42 import com.android.healthconnect.testapps.toolbox.Constants.READ_HEALTH_DATA_HISTORY 43 import com.android.healthconnect.testapps.toolbox.Constants.READ_HEALTH_DATA_IN_BACKGROUND 44 import com.android.healthconnect.testapps.toolbox.PerformanceTestingFragment 45 import com.android.healthconnect.testapps.toolbox.R 46 import com.android.healthconnect.testapps.toolbox.seed.SeedData 47 import com.android.healthconnect.testapps.toolbox.viewmodels.PerformanceTestingViewModel 48 import kotlin.system.exitProcess 49 50 /** Home fragment for Health Connect Toolbox. */ 51 class HomeFragment : Fragment() { 52 53 override fun onCreateView( 54 inflater: LayoutInflater, 55 container: ViewGroup?, 56 savedInstanceState: Bundle?, 57 ): View? { 58 return inflater.inflate(R.layout.fragment_home, container, false) 59 } 60 61 private lateinit var mRequestPermissionLauncher: ActivityResultLauncher<Array<String>> 62 private lateinit var mNavigationController: NavController 63 private val performanceTestingViewModel: PerformanceTestingViewModel by viewModels() 64 65 private val manager by lazy { 66 requireContext().getSystemService(HealthConnectManager::class.java) 67 } 68 69 override fun onCreate(savedInstanceState: Bundle?) { 70 super.onCreate(savedInstanceState) 71 72 // Starting API Level 30 If permission is denied more than once, user doesn't see the dialog 73 // asking permissions again unless they grant the permission from settings. 74 mRequestPermissionLauncher = 75 registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { 76 permissionMap: Map<String, Boolean> -> 77 requestPermissionResultHandler(permissionMap) 78 } 79 } 80 81 private fun requestPermissionResultHandler(permissionMap: Map<String, Boolean>) { 82 var numberOfPermissionsMissing = HEALTH_PERMISSIONS.size 83 for (value in permissionMap.values) { 84 if (value) { 85 numberOfPermissionsMissing-- 86 } 87 } 88 89 if (numberOfPermissionsMissing == 0) { 90 Toast.makeText( 91 this.requireContext(), R.string.all_permissions_success, Toast.LENGTH_SHORT) 92 .show() 93 } else { 94 Toast.makeText( 95 this.requireContext(), 96 getString( 97 R.string.number_of_permissions_not_granted, numberOfPermissionsMissing), 98 Toast.LENGTH_SHORT) 99 .show() 100 } 101 } 102 103 override fun onViewCreated(view: View, savedInstanceState: Bundle?) { 104 super.onViewCreated(view, savedInstanceState) 105 val performanceTesting = PerformanceTestingFragment() 106 childFragmentManager 107 .beginTransaction() 108 .add(performanceTesting, "PERFORMANCE_TESTING_FRAGMENT") 109 .commit() 110 view.findViewById<Button>(R.id.launch_health_connect_button).setOnClickListener { 111 launchHealthConnect() 112 } 113 view.findViewById<Button>(R.id.request_data_type_permissions_button).setOnClickListener { 114 requestDataTypePermissions() 115 } 116 view.findViewById<Button>(R.id.request_route_button).setOnClickListener { 117 goToRequestRoute() 118 } 119 view.findViewById<Button>(R.id.insert_update_data_button).setOnClickListener { 120 goToCategoryListPage() 121 } 122 view.findViewById<Button>(R.id.seed_random_data_button).setOnClickListener { 123 seedDataButtonPressed() 124 } 125 view.findViewById<Button>(R.id.seed_performance_read_data_button).setOnClickListener { 126 performanceTestingViewModel.beginReadingData() 127 } 128 view.findViewById<Button>(R.id.seed_performance_insert_data_button).setOnClickListener { 129 performanceTestingViewModel.beginInsertingData(false) 130 } 131 view.findViewById<Button>(R.id.toggle_permission_intent_filter).setOnClickListener { 132 togglePermissionIntentFilter() 133 } 134 view.requireViewById<Button>(R.id.read_data_in_background_button).setOnClickListener { 135 goToReadDataInBackgroundPage() 136 } 137 view.requireViewById<Button>(R.id.read_data_in_foreground_button).setOnClickListener { 138 goToReadDataInForegroundPage() 139 } 140 view.findViewById<Button>(R.id.phr_options_button).setOnClickListener { goToPhrOptions() } 141 view.requireViewById<Button>(R.id.exit_process_button).setOnClickListener { 142 exitProcess(status = 0) 143 } 144 145 view.findViewById<Button>(R.id.request_health_permissions).setOnClickListener { 146 requestHealthPermissions() 147 } 148 149 view.findViewById<Button>(R.id.request_additional_permissions).setOnClickListener { 150 requestAdditionalPermissions() 151 } 152 153 view.findViewById<Button>(R.id.request_bg_read_permission).setOnClickListener { 154 requestBgReadPermission() 155 } 156 157 view.findViewById<Button>(R.id.request_history_read_permission).setOnClickListener { 158 requestHistoryReadPermission() 159 } 160 161 // view 162 // .findViewById<Button>(R.id.seed_performance_insert_data_button_in_parallel) 163 // .setOnClickListener { performanceTestingViewModel.beginInsertingData(true) } 164 mNavigationController = findNavController() 165 } 166 167 private fun launchHealthConnect() { 168 val intent = Intent("android.health.connect.action.HEALTH_HOME_SETTINGS") 169 intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK 170 startActivity(intent) 171 } 172 173 private fun seedDataButtonPressed() { 174 try { 175 SeedData(requireContext(), manager).seedData() 176 Toast.makeText( 177 this.requireContext(), R.string.toast_seed_data_success, Toast.LENGTH_SHORT) 178 .show() 179 } catch (ex: Exception) { 180 Toast.makeText(this.requireContext(), ex.localizedMessage, Toast.LENGTH_SHORT).show() 181 } 182 } 183 184 private fun isPermissionGranted(permission: String): Boolean { 185 return ContextCompat.checkSelfPermission(this.requireContext(), permission) == 186 PackageManager.PERMISSION_GRANTED 187 } 188 189 private fun isMedicalPermissionMissing(): Boolean { 190 for (permission in MEDICAL_PERMISSIONS) { 191 if (!isPermissionGranted(permission)) { 192 return true 193 } 194 } 195 return false 196 } 197 198 private fun isDataTypePermissionMissing(): Boolean { 199 for (permission in DATA_TYPE_PERMISSIONS) { 200 if (!isPermissionGranted(permission)) { 201 return true 202 } 203 } 204 return false 205 } 206 207 private fun isAdditionalPermissionMissing(): Boolean { 208 for (permission in ADDITIONAL_PERMISSIONS) { 209 if (!isPermissionGranted(permission)) { 210 return true 211 } 212 } 213 return false 214 } 215 216 private fun togglePermissionIntentFilter() { 217 val pm = requireActivity().applicationContext.packageManager 218 val packageName = requireActivity().packageName 219 val compName = ComponentName(packageName, "$packageName.AliasMainActivity") 220 val componentState = pm.getComponentEnabledSetting(compName) 221 var desiredState = COMPONENT_ENABLED_STATE_ENABLED 222 if (componentState == COMPONENT_ENABLED_STATE_DEFAULT || 223 componentState == COMPONENT_ENABLED_STATE_ENABLED) { 224 desiredState = COMPONENT_ENABLED_STATE_DISABLED 225 } 226 pm.setComponentEnabledSetting(compName, desiredState, PackageManager.DONT_KILL_APP) 227 228 val toastText = 229 if (desiredState == COMPONENT_ENABLED_STATE_ENABLED) 230 R.string.toast_permission_filter_enabled 231 else R.string.toast_permission_filter_disabled 232 233 Toast.makeText(this.requireContext(), toastText, Toast.LENGTH_SHORT).show() 234 } 235 236 private fun requestHealthPermissions() { 237 mRequestPermissionLauncher.launch(HEALTH_PERMISSIONS) 238 return 239 } 240 241 private fun requestDataTypePermissions() { 242 if (isDataTypePermissionMissing()) { 243 mRequestPermissionLauncher.launch(DATA_TYPE_PERMISSIONS) 244 return 245 } 246 Toast.makeText( 247 this.requireContext(), 248 R.string.all_permissions_already_granted_toast, 249 Toast.LENGTH_LONG) 250 .show() 251 } 252 253 private fun requestAdditionalPermissions() { 254 if (isAdditionalPermissionMissing()) { 255 mRequestPermissionLauncher.launch(ADDITIONAL_PERMISSIONS) 256 return 257 } 258 Toast.makeText( 259 this.requireContext(), 260 R.string.all_permissions_already_granted_toast, 261 Toast.LENGTH_LONG) 262 .show() 263 } 264 265 private fun requestBgReadPermission() { 266 if (!isPermissionGranted(READ_HEALTH_DATA_IN_BACKGROUND)) { 267 mRequestPermissionLauncher.launch(arrayOf(READ_HEALTH_DATA_IN_BACKGROUND)) 268 } 269 270 Toast.makeText( 271 this.requireContext(), 272 R.string.all_permissions_already_granted_toast, 273 Toast.LENGTH_LONG) 274 .show() 275 } 276 277 private fun requestHistoryReadPermission() { 278 if (!isPermissionGranted(READ_HEALTH_DATA_HISTORY)) { 279 mRequestPermissionLauncher.launch(arrayOf(READ_HEALTH_DATA_HISTORY)) 280 } 281 282 Toast.makeText( 283 this.requireContext(), 284 R.string.all_permissions_already_granted_toast, 285 Toast.LENGTH_LONG) 286 .show() 287 } 288 289 private fun goToRequestRoute() { 290 mNavigationController.navigate(R.id.action_homeFragment_to_routeRequest) 291 } 292 293 private fun goToCategoryListPage() { 294 mNavigationController.navigate(R.id.action_homeFragment_to_categoryList) 295 } 296 297 private fun goToReadDataInBackgroundPage() { 298 mNavigationController.navigate(R.id.action_homeFragment_to_readDataInBackground) 299 } 300 301 private fun goToReadDataInForegroundPage() { 302 mNavigationController.navigate(R.id.action_homeFragment_to_readDataInForeground) 303 } 304 305 private fun goToPhrOptions() { 306 mNavigationController.navigate(R.id.action_homeFragment_to_phrOptions) 307 } 308 } 309