• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package com.android.healthconnect.controller.utils
2 
3 import android.content.ActivityNotFoundException
4 import android.content.Context
5 import android.content.Intent
6 import android.content.pm.PackageManager
7 import android.net.Uri
8 import android.os.Build
9 import android.os.UserManager
10 import android.text.TextUtils
11 import android.util.Log
12 import androidx.fragment.app.FragmentActivity
13 import com.android.healthconnect.controller.R
14 import com.android.healthconnect.controller.permissions.shared.HelpAndFeedbackFragment.Companion.FEEDBACK_INTENT_RESULT_CODE
15 import com.android.healthconnect.controller.permissions.shared.HelpAndFeedbackFragment.Companion.USER_INITIATED_FEEDBACK_BUCKET_ID
16 import com.android.healthfitness.flags.Flags
17 import com.android.settingslib.HelpUtils
18 import dagger.Module
19 import dagger.Provides
20 import dagger.hilt.EntryPoint
21 import dagger.hilt.InstallIn
22 import dagger.hilt.components.SingletonComponent
23 import javax.inject.Inject
24 
25 interface DeviceInfoUtils {
26 
isHealthConnectAvailablenull27     fun isHealthConnectAvailable(context: Context): Boolean
28 
29     fun isSendFeedbackAvailable(context: Context): Boolean
30 
31     fun isPlayStoreAvailable(context: Context): Boolean
32 
33     fun openHCGetStartedLink(activity: FragmentActivity)
34 
35     fun openHealthFitnessPermissionsLearnMoreLink(activity: FragmentActivity)
36 
37     fun openHCBackupAndRestoreLink(activity: FragmentActivity)
38 
39     fun openSendFeedbackActivity(activity: FragmentActivity)
40 
41     fun isIntentHandlerAvailable(context: Context, intent: Intent): Boolean
42 
43     fun isOnWatch(context: Context): Boolean
44 }
45 
46 class DeviceInfoUtilsImpl @Inject constructor() : DeviceInfoUtils {
47 
48     companion object {
49         private val TAG = "DeviceInfoUtils"
50     }
51 
52     override fun isSendFeedbackAvailable(context: Context): Boolean {
53         return isIntentHandlerAvailable(context, Intent(Intent.ACTION_BUG_REPORT))
54     }
55 
56     override fun isPlayStoreAvailable(context: Context): Boolean {
57         val playStorePackageName = context.resources?.getString(R.string.playstore_collection_url)
58         val vendingPackageName = context.resources?.getString(R.string.playstore_package_name)
59         if (TextUtils.isEmpty(playStorePackageName) || playStorePackageName == null) {
60             // Package name not configured. Return.
61             return false
62         }
63         return isIntentHandlerAvailable(
64             context,
65             Intent(Intent.ACTION_VIEW).apply {
66                 data = Uri.parse(playStorePackageName)
67                 setPackage(vendingPackageName)
68             },
69         )
70     }
71 
72     override fun openHCGetStartedLink(activity: FragmentActivity) {
73         openHealthConnectHelpCenterLink(activity, R.string.hc_get_started_link)
74     }
75 
76     override fun openHCBackupAndRestoreLink(activity: FragmentActivity) {
77         openHealthConnectHelpCenterLink(activity, R.string.hc_backup_and_restore_link)
78     }
79 
80     override fun openHealthFitnessPermissionsLearnMoreLink(activity: FragmentActivity) {
81         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.BAKLAVA) {
82             openHealthConnectHelpCenterLink(
83                 activity,
84                 R.string.health_fitness_permissions_learn_more_link,
85             )
86         } else {
87             Log.e(
88                 TAG,
89                 "attempting to open health fitness permissions URL on Build ${Build.VERSION.SDK_INT}",
90             )
91         }
92     }
93 
94     private fun openHealthConnectHelpCenterLink(activity: FragmentActivity, resourceId: Int) {
95         val helpUrlString = activity.getString(resourceId)
96         val fullUri = HelpUtils.uriWithAddedParameters(activity, Uri.parse(helpUrlString))
97         val intent =
98             Intent(Intent.ACTION_VIEW, fullUri).apply {
99                 flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
100             }
101         try {
102             activity.startActivity(intent)
103         } catch (e: ActivityNotFoundException) {
104             Log.e(TAG, "Unable to open help center URL.", e)
105         }
106     }
107 
108     override fun openSendFeedbackActivity(activity: FragmentActivity) {
109         val intent = Intent(Intent.ACTION_BUG_REPORT)
110         intent.putExtra("category_tag", USER_INITIATED_FEEDBACK_BUCKET_ID)
111         activity.startActivityForResult(intent, FEEDBACK_INTENT_RESULT_CODE)
112     }
113 
114     override fun isIntentHandlerAvailable(context: Context, intent: Intent): Boolean {
115         val packageManager = context.packageManager
116         if (intent.resolveActivity(packageManager) != null) {
117             return true
118         }
119         return false
120     }
121 
122     override fun isHealthConnectAvailable(context: Context): Boolean {
123         return isHardwareSupported(context) && !isProfile(context)
124     }
125 
126     override fun isOnWatch(context: Context): Boolean {
127         val pm: PackageManager = context.packageManager
128         return pm.hasSystemFeature(PackageManager.FEATURE_WATCH)
129     }
130 
131     private fun isHardwareSupported(context: Context): Boolean {
132         val pm: PackageManager = context.packageManager
133         val disabledOnWatch = isOnWatch(context) && !Flags.replaceBodySensorPermissionEnabled()
134         return (!pm.hasSystemFeature(PackageManager.FEATURE_EMBEDDED) &&
135             !disabledOnWatch &&
136             !pm.hasSystemFeature(PackageManager.FEATURE_LEANBACK) &&
137             !pm.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE))
138     }
139 
140     private fun isProfile(context: Context): Boolean {
141         return (context.getSystemService(Context.USER_SERVICE) as UserManager).isProfile
142     }
143 }
144 
145 @EntryPoint
146 @InstallIn(SingletonComponent::class)
147 interface DeviceInfoUtilsEntryPoint {
deviceInfoUtilsnull148     fun deviceInfoUtils(): DeviceInfoUtils
149 }
150 
151 @Module
152 @InstallIn(SingletonComponent::class)
153 class DeviceInfoUtilsModule {
154     @Provides
155     fun providesDeviceInfoUtils(): DeviceInfoUtils {
156         return DeviceInfoUtilsImpl()
157     }
158 }
159