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.navigation 20 21 import android.content.Intent 22 import android.content.Intent.EXTRA_PACKAGE_NAME 23 import android.content.Intent.EXTRA_REASON 24 import android.health.connect.HealthConnectManager 25 import android.os.Bundle 26 import android.util.Log 27 import android.view.WindowManager 28 import androidx.fragment.app.FragmentActivity 29 import com.android.healthconnect.controller.MainActivity 30 import com.android.healthconnect.controller.data.DataManagementActivity 31 import com.android.healthconnect.controller.onboarding.OnboardingActivity 32 import com.android.healthconnect.controller.onboarding.OnboardingActivity.Companion.shouldRedirectToOnboardingActivity 33 import com.android.healthconnect.controller.onboarding.SkipOnboardingActivity 34 import com.android.healthconnect.controller.onboarding.SkipOnboardingActivity.Companion.SKIP_HEALTH_CONNECT_ONBOARDING 35 import com.android.healthconnect.controller.permissions.app.wear.WearViewAppInfoPermissionsActivity 36 import com.android.healthconnect.controller.permissions.connectedapps.wear.WearSettingsPermissionActivity 37 import com.android.healthconnect.controller.permissions.shared.SettingsActivity 38 import com.android.healthconnect.controller.utils.DeviceInfoUtils 39 import com.android.healthconnect.controller.utils.activity.EmbeddingUtils.maybeRedirectIntoTwoPaneSettings 40 import dagger.hilt.android.AndroidEntryPoint 41 import javax.inject.Inject 42 43 /** 44 * A proxy activity that starts health connect screens. This activity validates intents and handles 45 * errors starting health connect screens. 46 */ 47 @AndroidEntryPoint(FragmentActivity::class) 48 class TrampolineActivity : Hilt_TrampolineActivity() { 49 50 companion object { 51 private const val TAG = "TrampolineActivity" 52 private const val REASON_PRIVACY_DASHBOARD = "privacy_dashboard" 53 } 54 55 @Inject lateinit var deviceInfoUtils: DeviceInfoUtils 56 onCreatenull57 override fun onCreate(savedInstanceState: Bundle?) { 58 super.onCreate(savedInstanceState) 59 // This flag ensures a non system app cannot show an overlay on Health Connect. b/313425281 60 window.addSystemFlags( 61 WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS 62 ) 63 // Handles unsupported devices and user profiles. 64 if (!deviceInfoUtils.isHealthConnectAvailable(this)) { 65 Log.e(TAG, "Health connect is not available for this user or hardware, finishing!") 66 finish() 67 return 68 } 69 val isOnWatch = deviceInfoUtils.isOnWatch(this) 70 71 // Handles large screen support in settings. 72 if (!isOnWatch && maybeRedirectIntoTwoPaneSettings(this)) { 73 finish() 74 return 75 } 76 77 val targetIntent = 78 if (isOnWatch) { 79 getWearTargetIntent() 80 } else { 81 getHandheldTargetIntent() 82 } 83 84 if (SKIP_HEALTH_CONNECT_ONBOARDING == intent.action) { 85 startActivity( 86 Intent(this, SkipOnboardingActivity::class.java).apply { 87 action = SKIP_HEALTH_CONNECT_ONBOARDING 88 } 89 ) 90 finish() 91 return 92 } 93 94 // Handles showing Health Connect Onboarding. 95 // Do not show onboarding UI on watch. 96 if (!isOnWatch && shouldRedirectToOnboardingActivity(this)) { 97 startActivity(OnboardingActivity.createIntent(this, targetIntent)) 98 finish() 99 return 100 } 101 102 startActivity(targetIntent) 103 finish() 104 } 105 getHandheldTargetIntentnull106 private fun getHandheldTargetIntent(): Intent { 107 return when (intent.action) { 108 HealthConnectManager.ACTION_HEALTH_HOME_SETTINGS -> { 109 Intent(this, MainActivity::class.java) 110 } 111 HealthConnectManager.ACTION_MANAGE_HEALTH_DATA -> { 112 Intent(this, DataManagementActivity::class.java) 113 } 114 HealthConnectManager.ACTION_MANAGE_HEALTH_PERMISSIONS -> { 115 val extraPackageName: String? = intent.getStringExtra(EXTRA_PACKAGE_NAME) 116 117 Intent(this, SettingsActivity::class.java).apply { 118 if (extraPackageName != null) { 119 putExtra(EXTRA_PACKAGE_NAME, extraPackageName) 120 } 121 } 122 } 123 else -> { 124 // Default to open Health Connect MainActivity 125 Intent(this, MainActivity::class.java) 126 } 127 } 128 } 129 130 // Returns an intent to handle Wear request. getWearTargetIntentnull131 private fun getWearTargetIntent(): Intent { 132 if (intent.action != HealthConnectManager.ACTION_MANAGE_HEALTH_PERMISSIONS) { 133 Log.e(TAG, "getWearTargetIntent() has unexpected intent action: " + intent.action) 134 // If unexpected intent, fall default to WearPermissionManagerActivity. 135 } 136 val extraPackageName: String? = intent.getStringExtra(EXTRA_PACKAGE_NAME) 137 val extraReason: String? = intent.getStringExtra(EXTRA_REASON) 138 139 return if (extraPackageName != null) { 140 // AppInfo page. 141 Intent(this, WearViewAppInfoPermissionsActivity::class.java).apply { 142 putExtra(EXTRA_PACKAGE_NAME, extraPackageName) 143 } 144 } else if (extraReason == REASON_PRIVACY_DASHBOARD) { 145 // PrivacyDashboard page. 146 Intent(this, WearSettingsPermissionActivity::class.java).apply { 147 putExtra(EXTRA_REASON, REASON_PRIVACY_DASHBOARD) 148 } 149 } else { 150 // PermissionManager page. 151 Intent(this, WearSettingsPermissionActivity::class.java) 152 } 153 } 154 } 155