<lambda>null1 package expo.modules.notifications.permissions
2 
3 import android.Manifest
4 import android.app.NotificationManager
5 import android.content.Context
6 import android.os.Build
7 import androidx.annotation.RequiresApi
8 import androidx.core.app.NotificationManagerCompat
9 import androidx.core.os.bundleOf
10 import expo.modules.core.arguments.ReadableArguments
11 import expo.modules.interfaces.permissions.Permissions
12 import expo.modules.interfaces.permissions.PermissionsResponse
13 import expo.modules.interfaces.permissions.PermissionsStatus
14 import expo.modules.kotlin.Promise
15 import expo.modules.kotlin.exception.Exceptions
16 import expo.modules.kotlin.modules.Module
17 import expo.modules.kotlin.modules.ModuleDefinition
18 import expo.modules.notifications.ModuleNotFoundException
19 
20 private const val ANDROID_RESPONSE_KEY = "android"
21 private const val IMPORTANCE_KEY = "importance"
22 private const val INTERRUPTION_FILTER_KEY = "interruptionFilter"
23 private val PERMISSIONS: Array<String> = arrayOf(Manifest.permission.POST_NOTIFICATIONS)
24 
25 class NotificationPermissionsModule : Module() {
26   private val permissions: Permissions
27     get() = appContext.permissions ?: throw ModuleNotFoundException(Permissions::class)
28 
29   private val context: Context
30     get() = appContext.reactContext ?: throw Exceptions.ReactContextLost()
31 
32   override fun definition() = ModuleDefinition {
33     Name("ExpoNotificationPermissionsModule")
34 
35     AsyncFunction("getPermissionsAsync") { promise: Promise ->
36       if (context.applicationContext.applicationInfo.targetSdkVersion >= 33 && Build.VERSION.SDK_INT >= 33) {
37         getPermissionsWithPromiseImplApi33(promise)
38       } else {
39         getPermissionsWithPromiseImplClassic(promise)
40       }
41     }
42 
43     AsyncFunction("requestPermissionsAsync") { _: ReadableArguments?, promise: Promise ->
44       if (context.applicationContext.applicationInfo.targetSdkVersion >= 33 && Build.VERSION.SDK_INT >= 33) {
45         requestPermissionsWithPromiseImplApi33(promise)
46       } else {
47         getPermissionsWithPromiseImplClassic(promise)
48       }
49     }
50   }
51 
52   @RequiresApi(33)
53   private fun getPermissionsWithPromiseImplApi33(promise: Promise) {
54     permissions.getPermissions(
55       { permissionsMap: Map<String, PermissionsResponse> ->
56         val managerCompat = NotificationManagerCompat.from(context)
57         val areEnabled = managerCompat.areNotificationsEnabled()
58         val platformBundle = bundleOf(
59           IMPORTANCE_KEY to managerCompat.importance,
60         ).apply {
61           val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as? NotificationManager
62           if (notificationManager != null) {
63             putInt(INTERRUPTION_FILTER_KEY, notificationManager.currentInterruptionFilter)
64           }
65         }
66 
67         val areAllGranted = permissionsMap.all { (_, response) -> response.status == PermissionsStatus.GRANTED }
68         val areAllDenied = permissionsMap.all { (_, response) -> response.status == PermissionsStatus.DENIED }
69         val canAskAgain = permissionsMap.all { (_, response) -> response.canAskAgain }
70         val status = when {
71           areAllDenied -> PermissionsStatus.DENIED.status
72           !areEnabled -> PermissionsStatus.DENIED.status
73           areAllGranted -> PermissionsStatus.GRANTED.status
74           else -> PermissionsStatus.UNDETERMINED.status
75         }
76 
77         promise.resolve(
78           bundleOf(
79             PermissionsResponse.EXPIRES_KEY to PermissionsResponse.PERMISSION_EXPIRES_NEVER,
80             PermissionsResponse.STATUS_KEY to status,
81             PermissionsResponse.CAN_ASK_AGAIN_KEY to canAskAgain,
82             PermissionsResponse.GRANTED_KEY to areAllGranted,
83             ANDROID_RESPONSE_KEY to platformBundle,
84           )
85         )
86       },
87       *PERMISSIONS
88     )
89   }
90 
91   private fun getPermissionsWithPromiseImplClassic(promise: Promise) {
92     val managerCompat = NotificationManagerCompat.from(context)
93     val areEnabled = managerCompat.areNotificationsEnabled()
94     val status = if (areEnabled) PermissionsStatus.GRANTED else PermissionsStatus.DENIED
95     val platformBundle = bundleOf(
96       IMPORTANCE_KEY to managerCompat.importance,
97     ).apply {
98       val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as? NotificationManager
99       if (notificationManager != null) {
100         putInt(INTERRUPTION_FILTER_KEY, notificationManager.currentInterruptionFilter)
101       }
102     }
103 
104     promise.resolve(
105       bundleOf(
106         PermissionsResponse.EXPIRES_KEY to PermissionsResponse.PERMISSION_EXPIRES_NEVER,
107         PermissionsResponse.STATUS_KEY to status.status,
108         PermissionsResponse.CAN_ASK_AGAIN_KEY to areEnabled,
109         PermissionsResponse.GRANTED_KEY to (status == PermissionsStatus.GRANTED),
110         ANDROID_RESPONSE_KEY to platformBundle,
111       )
112     )
113   }
114 
115   @RequiresApi(33)
116   private fun requestPermissionsWithPromiseImplApi33(promise: Promise) {
117     permissions.askForPermissions(
118       {
119         getPermissionsWithPromiseImplApi33(promise)
120       },
121       *PERMISSIONS
122     )
123   }
124 }
125