diff --git a/native/android/app/build.gradle b/native/android/app/build.gradle --- a/native/android/app/build.gradle +++ b/native/android/app/build.gradle @@ -671,6 +671,8 @@ implementation project(':reactnativekeyboardinput') implementation "androidx.multidex:multidex:2.0.1" + implementation "androidx.lifecycle:lifecycle-process:2.5.1" + implementation 'com.facebook.fresco:fresco:2.2.0' implementation 'com.facebook.fresco:animated-gif:2.2.0' implementation 'com.facebook.fresco:animated-webp:2.2.0' diff --git a/native/android/app/src/main/java/app/comm/android/MainApplication.java b/native/android/app/src/main/java/app/comm/android/MainApplication.java --- a/native/android/app/src/main/java/app/comm/android/MainApplication.java +++ b/native/android/app/src/main/java/app/comm/android/MainApplication.java @@ -28,6 +28,7 @@ extends MultiDexApplication implements ReactApplication { static { + System.loadLibrary("fbjni"); System.loadLibrary("comm_jni_module"); } diff --git a/native/android/app/src/main/java/app/comm/android/notifications/CommNotificationsHandler.java b/native/android/app/src/main/java/app/comm/android/notifications/CommNotificationsHandler.java --- a/native/android/app/src/main/java/app/comm/android/notifications/CommNotificationsHandler.java +++ b/native/android/app/src/main/java/app/comm/android/notifications/CommNotificationsHandler.java @@ -1,10 +1,18 @@ package app.comm.android.notifications; +import android.app.Notification; import android.app.NotificationManager; import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.os.Bundle; import android.service.notification.StatusBarNotification; import android.util.Log; +import androidx.core.app.NotificationCompat; +import androidx.lifecycle.Lifecycle; +import androidx.lifecycle.ProcessLifecycleOwner; import app.comm.android.ExpoUtils; +import app.comm.android.R; import app.comm.android.fbjni.CommSecureStore; import app.comm.android.fbjni.GlobalDBSingleton; import app.comm.android.fbjni.MessageOperationsUtilities; @@ -49,6 +57,14 @@ private static final String THREAD_ID_KEY = "threadID"; private static final String SET_UNREAD_STATUS_KEY = "setUnreadStatus"; private static final String MESSAGE_INFOS_KEY = "messageInfos"; + private static final String NOTIF_ID_KEY = "id"; + private static final String TITLE_KEY = "title"; + private static final String PREFIX_KEY = "prefix"; + private static final String BODY_KEY = "body"; + + private static final String CHANNEL_ID = "default"; + private static final long[] VIBRATION_SPEC = {500, 500}; + private Bitmap displayableNotificationLargeIcon; private NotificationManager notificationManager; @Override @@ -58,6 +74,8 @@ ExpoUtils.createExpoSecureStoreSupplier(this.getApplicationContext())); notificationManager = (NotificationManager)this.getSystemService( Context.NOTIFICATION_SERVICE); + displayableNotificationLargeIcon = BitmapFactory.decodeResource( + this.getApplicationContext().getResources(), R.mipmap.ic_launcher); } @Override @@ -102,7 +120,16 @@ Log.w("COMM", "Database not existing yet. Skipping notification"); } - super.onMessageReceived(message); + if (this.isAppInForeground()) { + super.onMessageReceived(message); + return; + } + this.displayNotification(message); + } + + private boolean isAppInForeground() { + return ProcessLifecycleOwner.get().getLifecycle().getCurrentState() == + Lifecycle.State.RESUMED; } private void handleNotificationRescind(RemoteMessage message) { @@ -131,4 +158,38 @@ } } } + + private void displayNotification(RemoteMessage message) { + if (message.getData().get(RESCIND_KEY) != null) { + // don't attempt to display rescinds + return; + } + String id = message.getData().get(NOTIF_ID_KEY); + String title = message.getData().get(TITLE_KEY); + String prefix = message.getData().get(PREFIX_KEY); + String body = message.getData().get(BODY_KEY); + String threadID = message.getData().get(THREAD_ID_KEY); + + if (prefix != null) { + body = prefix + " " + body; + } + + Bundle data = new Bundle(); + data.putString(THREAD_ID_KEY, threadID); + + NotificationCompat.Builder notificationBuilder = + new NotificationCompat.Builder(this.getApplicationContext()) + .setDefaults(Notification.DEFAULT_ALL) + .setContentText(body) + .setExtras(data) + .setChannelId(CHANNEL_ID) + .setVibrate(VIBRATION_SPEC) + .setSmallIcon(R.drawable.notif_icon) + .setLargeIcon(displayableNotificationLargeIcon) + .setAutoCancel(true); + if (title != null) { + notificationBuilder = notificationBuilder.setContentTitle(title); + } + notificationManager.notify(id, id.hashCode(), notificationBuilder.build()); + } } diff --git a/native/push/android.js b/native/push/android.js --- a/native/push/android.js +++ b/native/push/android.js @@ -6,9 +6,6 @@ import { mergePrefixIntoBody } from 'lib/shared/notif-utils'; -import { store } from '../redux/redux-setup'; -import { getFirebase } from './firebase'; - type CommAndroidNotificationsModuleType = { +removeAllActiveNotificationsForThread: (threadID: string) => void, ... @@ -17,7 +14,6 @@ const CommAndroidNotifications: CommAndroidNotificationsModuleType = NativeModules.CommAndroidNotifications; const androidNotificationChannelID = 'default'; -const vibrationSpec = [500, 500]; function handleAndroidMessage( message: RemoteMessage, @@ -27,7 +23,6 @@ texts: { body: string, title: ?string }, ) => boolean, ) { - const firebase = getFirebase(); const { data } = message; const { rescind, rescindID } = data; @@ -36,7 +31,7 @@ return; } - const { id, title, prefix, threadID } = data; + const { title, prefix, threadID } = data; let { body } = data; ({ body } = mergePrefixIntoBody({ body, title, prefix })); @@ -47,32 +42,10 @@ return; } } - - const notification = new firebase.notifications.Notification() - .setNotificationId(id) - .setBody(body) - .setData({ threadID }) - .android.setTag(id) - .android.setChannelId(androidNotificationChannelID) - .android.setDefaults([firebase.notifications.Android.Defaults.All]) - .android.setVibrate(vibrationSpec) - .android.setAutoCancel(true) - .android.setLargeIcon('@mipmap/ic_launcher') - .android.setSmallIcon('@drawable/notif_icon'); - if (title) { - notification.setTitle(title); - } - firebase.notifications().displayNotification(notification); -} - -async function androidBackgroundMessageTask(message: RemoteMessage) { - const { updatesCurrentAsOf } = store.getState(); - handleAndroidMessage(message, updatesCurrentAsOf); } export { androidNotificationChannelID, handleAndroidMessage, - androidBackgroundMessageTask, CommAndroidNotifications, }; diff --git a/native/push/push-handler.react.js b/native/push/push-handler.react.js --- a/native/push/push-handler.react.js +++ b/native/push/push-handler.react.js @@ -2,7 +2,7 @@ import * as Haptics from 'expo-haptics'; import * as React from 'react'; -import { AppRegistry, Platform, Alert, LogBox } from 'react-native'; +import { Platform, Alert, LogBox } from 'react-native'; import type { RemoteMessage, NotificationOpen } from 'react-native-firebase'; import { Notification as InAppNotification } from 'react-native-in-app-message'; import { useDispatch } from 'react-redux'; @@ -49,7 +49,6 @@ import { androidNotificationChannelID, handleAndroidMessage, - androidBackgroundMessageTask, CommAndroidNotifications, } from './android'; import { @@ -578,11 +577,6 @@ } } -AppRegistry.registerHeadlessTask( - 'RNFirebaseBackgroundMessage', - () => androidBackgroundMessageTask, -); - const ConnectedPushHandler: React.ComponentType = React.memo( function ConnectedPushHandler(props: BaseProps) { const navContext = React.useContext(NavContext);