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