diff --git a/native/android/app/src/main/java/app/comm/android/MainActivity.java b/native/android/app/src/main/java/app/comm/android/MainActivity.java --- a/native/android/app/src/main/java/app/comm/android/MainActivity.java +++ b/native/android/app/src/main/java/app/comm/android/MainActivity.java @@ -1,13 +1,18 @@ package app.comm.android; +import android.Manifest; import android.content.Intent; +import android.content.pm.PackageManager; import android.os.Bundle; +import androidx.core.app.ActivityCompat; +import app.comm.android.notifications.CommAndroidNotifications; import com.facebook.react.ReactActivity; import com.facebook.react.ReactActivityDelegate; import com.facebook.react.ReactRootView; import expo.modules.ReactActivityDelegateWrapper; -public class MainActivity extends ReactActivity { +public class MainActivity extends ReactActivity + implements ActivityCompat.OnRequestPermissionsResultCallback { /** * Returns the name of the main component registered from JavaScript. @@ -66,4 +71,24 @@ public void invokeDefaultOnBackPressed() { moveTaskToBack(true); } + + @Override + public void onRequestPermissionsResult( + int requestCode, + String[] permissions, + int[] grantResults) { + + for (int permissionIndex = 0; permissionIndex < grantResults.length; + permissionIndex++) { + String permissionName = permissions[permissionIndex]; + if (requestCode == + CommAndroidNotifications + .COMM_ANDROID_NOTIFICATIONS_REQUEST_CODE && + permissionName.equals(Manifest.permission.POST_NOTIFICATIONS)) { + CommAndroidNotifications.resolveNotificationsPermissionRequestPromise( + this, + grantResults[permissionIndex] == PackageManager.PERMISSION_GRANTED); + } + } + } } diff --git a/native/android/app/src/main/java/app/comm/android/notifications/CommAndroidNotifications.java b/native/android/app/src/main/java/app/comm/android/notifications/CommAndroidNotifications.java --- a/native/android/app/src/main/java/app/comm/android/notifications/CommAndroidNotifications.java +++ b/native/android/app/src/main/java/app/comm/android/notifications/CommAndroidNotifications.java @@ -1,10 +1,13 @@ package app.comm.android.notifications; +import android.Manifest; +import android.app.Activity; import android.app.NotificationChannel; import android.app.NotificationManager; import android.content.Context; import android.os.Bundle; import android.service.notification.StatusBarNotification; +import androidx.core.app.ActivityCompat; import androidx.core.app.NotificationManagerCompat; import com.facebook.react.bridge.NativeModule; import com.facebook.react.bridge.Promise; @@ -17,11 +20,17 @@ import com.google.firebase.messaging.RemoteMessage; import java.util.HashMap; import java.util.Map; +import java.util.concurrent.atomic.AtomicReference; import me.leolin.shortcutbadger.ShortcutBadger; public class CommAndroidNotifications extends ReactContextBaseJavaModule { + private static AtomicReference + notificationsPermissionRequestResultPromise = new AtomicReference(null); + private NotificationManager notificationManager; + public static final int COMM_ANDROID_NOTIFICATIONS_REQUEST_CODE = 11111; + CommAndroidNotifications(ReactApplicationContext reactContext) { super(reactContext); Context context = reactContext.getApplicationContext(); @@ -122,6 +131,37 @@ }); } + @ReactMethod + public void requestNotificationsPermission(Promise promise) { + if (android.os.Build.VERSION.SDK_INT < + android.os.Build.VERSION_CODES.TIRAMISU) { + // Application has to explicitly request notifications permission from + // user since Android 13. Older versions grant them by default. Details: + // https://developer.android.com/develop/ui/views/notifications/notification-permission + promise.resolve(null); + return; + } + + if (!notificationsPermissionRequestResultPromise.compareAndSet( + null, promise)) { + promise.resolve(null); + return; + } + + ActivityCompat.requestPermissions( + getCurrentActivity(), + new String[] {Manifest.permission.POST_NOTIFICATIONS}, + CommAndroidNotifications.COMM_ANDROID_NOTIFICATIONS_REQUEST_CODE); + } + + public static void resolveNotificationsPermissionRequestPromise( + Activity mainActivity, + boolean isPermissionGranted) { + notificationsPermissionRequestResultPromise.get().resolve( + isPermissionGranted); + notificationsPermissionRequestResultPromise.set(null); + } + @Override public Map getConstants() { final Map constants = new HashMap<>(); diff --git a/native/push/android.js b/native/push/android.js --- a/native/push/android.js +++ b/native/push/android.js @@ -18,6 +18,7 @@ +removeAllDeliveredNotifications: () => void, +hasPermission: () => Promise, +getToken: () => Promise, + +requestNotificationsPermission: () => Promise, +NOTIFICATIONS_IMPORTANCE_HIGH: string, }; export type AndroidForegroundMessage = {