1 package host.exp.exponent.kernel.services
2 
3 import android.content.Context
4 import android.content.pm.PackageManager
5 import android.content.pm.PermissionInfo
6 import expo.modules.jsonutils.getNullable
7 import host.exp.exponent.Constants
8 import host.exp.exponent.kernel.ExperienceKey
9 import host.exp.exponent.storage.ExponentSharedPreferences
10 import org.json.JSONException
11 import org.json.JSONObject
12 
13 class PermissionsKernelService(
14   context: Context,
15   private val exponentSharedPreferences: ExponentSharedPreferences
16 ) : BaseKernelService(context) {
grantScopedPermissionsnull17   fun grantScopedPermissions(permission: String, experienceKey: ExperienceKey) {
18     try {
19       var metadata = exponentSharedPreferences.getExperienceMetadata(experienceKey)
20       if (metadata == null) {
21         metadata = JSONObject()
22       }
23       val permissions: JSONObject = metadata.getNullable(ExponentSharedPreferences.EXPERIENCE_METADATA_PERMISSIONS) ?: JSONObject()
24       val permissionObject: JSONObject = permissions.getNullable(permission) ?: JSONObject()
25       permissionObject.put("status", "granted")
26       permissions.put(permission, permissionObject)
27       metadata.put(ExponentSharedPreferences.EXPERIENCE_METADATA_PERMISSIONS, permissions)
28       exponentSharedPreferences.updateExperienceMetadata(experienceKey, metadata)
29     } catch (e: JSONException) {
30       e.printStackTrace()
31     }
32   }
33 
revokeScopedPermissionsnull34   fun revokeScopedPermissions(permission: String, experienceKey: ExperienceKey) {
35     try {
36       val metadata = exponentSharedPreferences.getExperienceMetadata(experienceKey) ?: return
37       if (metadata.has(ExponentSharedPreferences.EXPERIENCE_METADATA_PERMISSIONS)) {
38         val permissions =
39           metadata.getJSONObject(ExponentSharedPreferences.EXPERIENCE_METADATA_PERMISSIONS)
40         if (permissions.has(permission)) {
41           permissions.remove(permission)
42           metadata.put(ExponentSharedPreferences.EXPERIENCE_METADATA_PERMISSIONS, permissions)
43           exponentSharedPreferences.updateExperienceMetadata(experienceKey, metadata)
44         }
45       }
46     } catch (e: JSONException) {
47       e.printStackTrace()
48     }
49   }
50 
hasGrantedPermissionsnull51   fun hasGrantedPermissions(permission: String, experienceKey: ExperienceKey): Boolean {
52     // we don't want to worry about per-experience permissions for shell apps
53     if (Constants.isStandaloneApp()) {
54       return true
55     }
56     val metadata = exponentSharedPreferences.getExperienceMetadata(experienceKey) ?: return false
57     try {
58       if (metadata.has(ExponentSharedPreferences.EXPERIENCE_METADATA_PERMISSIONS)) {
59         val permissions =
60           metadata.getJSONObject(ExponentSharedPreferences.EXPERIENCE_METADATA_PERMISSIONS)
61         if (permissions.has(permission)) {
62           val permissionsObject = permissions.getJSONObject(permission)
63           return permissionsObject.getNullable<String>("status") == "granted"
64         }
65       }
66     } catch (e: JSONException) {
67       e.printStackTrace()
68     }
69     return false
70   }
71 
getPermissionsnull72   fun getPermissions(
73     globalPermissionStatus: Int,
74     packageManager: PackageManager,
75     permission: String,
76     experienceKey: ExperienceKey
77   ): Int {
78     // only these permissions, which show a dialog to the user should be scoped.
79     val isDangerousPermission: Boolean = try {
80       isDangerousPermission(permission, packageManager)
81     } catch (e: PackageManager.NameNotFoundException) {
82       return PackageManager.PERMISSION_DENIED
83     }
84     if (Constants.isStandaloneApp() || !isDangerousPermission) {
85       return globalPermissionStatus
86     }
87     return if (globalPermissionStatus == PackageManager.PERMISSION_GRANTED &&
88       hasGrantedPermissions(permission, experienceKey)
89     ) {
90       PackageManager.PERMISSION_GRANTED
91     } else {
92       PackageManager.PERMISSION_DENIED
93     }
94   }
95 
96   @Throws(PackageManager.NameNotFoundException::class)
isDangerousPermissionnull97   private fun isDangerousPermission(permission: String, packageManager: PackageManager): Boolean {
98     val permissionInfo = packageManager.getPermissionInfo(permission, PackageManager.GET_META_DATA)
99     return permissionInfo.protectionLevel and PermissionInfo.PROTECTION_DANGEROUS != 0
100   }
101 
onExperienceForegroundednull102   override fun onExperienceForegrounded(experienceKey: ExperienceKey) {}
onExperienceBackgroundednull103   override fun onExperienceBackgrounded(experienceKey: ExperienceKey) {}
104 }
105