Differential D7106 Diff 24278 native/android/app/src/main/java/app/comm/android/notifications/CommAndroidNotifications.java
Changeset View
Changeset View
Standalone View
Standalone View
native/android/app/src/main/java/app/comm/android/notifications/CommAndroidNotifications.java
package app.comm.android.notifications; | package app.comm.android.notifications; | ||||
import android.Manifest; | |||||
import android.app.Activity; | |||||
import android.app.NotificationChannel; | import android.app.NotificationChannel; | ||||
import android.app.NotificationManager; | import android.app.NotificationManager; | ||||
import android.content.Context; | import android.content.Context; | ||||
import android.os.Bundle; | import android.os.Bundle; | ||||
import android.service.notification.StatusBarNotification; | import android.service.notification.StatusBarNotification; | ||||
import androidx.core.app.ActivityCompat; | |||||
import androidx.core.app.NotificationManagerCompat; | import androidx.core.app.NotificationManagerCompat; | ||||
import com.facebook.react.bridge.NativeModule; | import com.facebook.react.bridge.NativeModule; | ||||
import com.facebook.react.bridge.Promise; | import com.facebook.react.bridge.Promise; | ||||
import com.facebook.react.bridge.ReactApplicationContext; | import com.facebook.react.bridge.ReactApplicationContext; | ||||
import com.facebook.react.bridge.ReactContext; | import com.facebook.react.bridge.ReactContext; | ||||
import com.facebook.react.bridge.ReactContextBaseJavaModule; | import com.facebook.react.bridge.ReactContextBaseJavaModule; | ||||
import com.facebook.react.bridge.ReactMethod; | import com.facebook.react.bridge.ReactMethod; | ||||
import com.facebook.react.bridge.WritableMap; | import com.facebook.react.bridge.WritableMap; | ||||
import com.google.firebase.messaging.FirebaseMessaging; | import com.google.firebase.messaging.FirebaseMessaging; | ||||
import com.google.firebase.messaging.RemoteMessage; | import com.google.firebase.messaging.RemoteMessage; | ||||
import java.util.HashMap; | import java.util.HashMap; | ||||
import java.util.Map; | import java.util.Map; | ||||
import java.util.concurrent.atomic.AtomicReference; | |||||
import me.leolin.shortcutbadger.ShortcutBadger; | import me.leolin.shortcutbadger.ShortcutBadger; | ||||
public class CommAndroidNotifications extends ReactContextBaseJavaModule { | public class CommAndroidNotifications extends ReactContextBaseJavaModule { | ||||
private static AtomicReference<Promise> | |||||
notificationsPermissionRequestPromise = new AtomicReference(null); | |||||
private NotificationManager notificationManager; | private NotificationManager notificationManager; | ||||
// Application can request multiple permission, but all | |||||
// will be resolved via `onRequestPermissionsResult` callback | |||||
// in MainActivity. Therefore we use custom request codes | |||||
// to differentiate between different permission requests | |||||
public static final int COMM_ANDROID_NOTIFICATIONS_REQUEST_CODE = 11111; | |||||
CommAndroidNotifications(ReactApplicationContext reactContext) { | CommAndroidNotifications(ReactApplicationContext reactContext) { | ||||
super(reactContext); | super(reactContext); | ||||
Context context = reactContext.getApplicationContext(); | Context context = reactContext.getApplicationContext(); | ||||
this.notificationManager = (NotificationManager)context.getSystemService( | this.notificationManager = (NotificationManager)context.getSystemService( | ||||
Context.NOTIFICATION_SERVICE); | Context.NOTIFICATION_SERVICE); | ||||
} | } | ||||
@Override | @Override | ||||
▲ Show 20 Lines • Show All 67 Lines • ▼ Show 20 Lines | public class CommAndroidNotifications extends ReactContextBaseJavaModule { | ||||
@ReactMethod | @ReactMethod | ||||
public void removeAllDeliveredNotifications() { | public void removeAllDeliveredNotifications() { | ||||
notificationManager.cancelAll(); | notificationManager.cancelAll(); | ||||
} | } | ||||
@ReactMethod | @ReactMethod | ||||
public void hasPermission(Promise promise) { | public void hasPermission(Promise promise) { | ||||
boolean enabled = | promise.resolve(hasPermissionInternal()); | ||||
NotificationManagerCompat.from(getReactApplicationContext()) | |||||
.areNotificationsEnabled(); | |||||
promise.resolve(enabled); | |||||
} | } | ||||
@ReactMethod | @ReactMethod | ||||
public void getToken(Promise promise) { | public void getToken(Promise promise) { | ||||
FirebaseMessaging.getInstance().getToken().addOnCompleteListener(task -> { | FirebaseMessaging.getInstance().getToken().addOnCompleteListener(task -> { | ||||
if (task.isSuccessful()) { | if (task.isSuccessful()) { | ||||
promise.resolve(task.getResult()); | promise.resolve(task.getResult()); | ||||
} else { | } else { | ||||
promise.reject(task.getException()); | promise.reject(task.getException()); | ||||
} | } | ||||
}); | }); | ||||
} | } | ||||
@ReactMethod | |||||
public void canRequestNotificationsPermissionFromUser(Promise promise) { | |||||
promise.resolve(canRequestNotificationsPermissionInternal()); | |||||
} | |||||
@ReactMethod | |||||
public void requestNotificationsPermission(Promise promise) { | |||||
if (!canRequestNotificationsPermissionInternal()) { | |||||
// If this method is erroneously called on older Android we should | |||||
// resolve to the value from notifications settings. | |||||
promise.resolve(hasPermissionInternal()); | |||||
return; | |||||
} | |||||
if (ActivityCompat.shouldShowRequestPermissionRationale( | |||||
getCurrentActivity(), Manifest.permission.POST_NOTIFICATIONS)) { | |||||
// Since Android 13 user has to deny notifications permission | |||||
// twice to remove possibility to show the prompt again. Details: | |||||
// https://developer.android.com/training/permissions/requesting#handle-denial | |||||
// On iOS user has to deny notifications permission once to disable the | |||||
// prompt. We use the method above to mimic iOS behavior on Android. | |||||
// Details: | |||||
// https://developer.android.com/topic/performance/vitals/permissions#explain | |||||
promise.resolve(hasPermissionInternal()); | |||||
return; | |||||
} | |||||
if (!notificationsPermissionRequestPromise.compareAndSet(null, promise)) { | |||||
promise.reject( | |||||
"Programmer error: permission request already in progress."); | |||||
return; | |||||
} | |||||
ActivityCompat.requestPermissions( | |||||
getCurrentActivity(), | |||||
new String[] {Manifest.permission.POST_NOTIFICATIONS}, | |||||
CommAndroidNotifications.COMM_ANDROID_NOTIFICATIONS_REQUEST_CODE); | |||||
} | |||||
@Override | @Override | ||||
public Map<String, Object> getConstants() { | public Map<String, Object> getConstants() { | ||||
final Map<String, Object> constants = new HashMap<>(); | final Map<String, Object> constants = new HashMap<>(); | ||||
constants.put( | constants.put( | ||||
"NOTIFICATIONS_IMPORTANCE_HIGH", NotificationManager.IMPORTANCE_HIGH); | "NOTIFICATIONS_IMPORTANCE_HIGH", NotificationManager.IMPORTANCE_HIGH); | ||||
return constants; | return constants; | ||||
} | } | ||||
public static void resolveNotificationsPermissionRequestPromise( | |||||
Activity mainActivity, | |||||
boolean isPermissionGranted) { | |||||
if (notificationsPermissionRequestPromise.get() == null) { | |||||
return; | |||||
} | |||||
notificationsPermissionRequestPromise.getAndSet(null).resolve( | |||||
isPermissionGranted); | |||||
} | |||||
private boolean hasPermissionInternal() { | |||||
return NotificationManagerCompat.from(getReactApplicationContext()) | |||||
.areNotificationsEnabled(); | |||||
} | |||||
private boolean canRequestNotificationsPermissionInternal() { | |||||
// 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 | |||||
return android.os.Build.VERSION.SDK_INT >= | |||||
android.os.Build.VERSION_CODES.TIRAMISU; | |||||
} | |||||
} | } |