diff --git a/app/src/main/java/org/thoughtcrime/securesms/gcm/FcmFetchService.java b/app/src/main/java/org/thoughtcrime/securesms/gcm/FcmFetchService.java index 3f39ed4af9..b54c1fa08a 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/gcm/FcmFetchService.java +++ b/app/src/main/java/org/thoughtcrime/securesms/gcm/FcmFetchService.java @@ -1,5 +1,6 @@ package org.thoughtcrime.securesms.gcm; +import android.app.PendingIntent; import android.app.Service; import android.content.Context; import android.content.Intent; @@ -8,15 +9,21 @@ import android.os.IBinder; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.core.app.NotificationCompat; import com.google.firebase.messaging.RemoteMessage; +import org.signal.core.util.ThreadUtil; import org.signal.core.util.concurrent.SignalExecutors; import org.signal.core.util.logging.Log; +import org.thoughtcrime.securesms.MainActivity; +import org.thoughtcrime.securesms.R; import org.thoughtcrime.securesms.dependencies.ApplicationDependencies; import org.thoughtcrime.securesms.jobs.PushNotificationReceiveJob; import org.thoughtcrime.securesms.messages.BackgroundMessageRetriever; import org.thoughtcrime.securesms.messages.RestStrategy; +import org.thoughtcrime.securesms.notifications.NotificationChannels; +import org.thoughtcrime.securesms.notifications.NotificationIds; import org.thoughtcrime.securesms.util.concurrent.SerialMonoLifoExecutor; import java.util.concurrent.atomic.AtomicInteger; @@ -43,10 +50,18 @@ public class FcmFetchService extends Service { private static final String TAG = Log.tag(FcmFetchService.class); + static final String KEY_FOREGROUND = "is_foreground"; + private static final SerialMonoLifoExecutor EXECUTOR = new SerialMonoLifoExecutor(SignalExecutors.UNBOUNDED); private final AtomicInteger activeCount = new AtomicInteger(0); + public static @NonNull Intent buildIntent(@NonNull Context context, boolean foreground) { + Intent intent = new Intent(context, FcmFetchService.class); + intent.putExtra(KEY_FOREGROUND, foreground); + return intent; + } + @Override public int onStartCommand(Intent intent, int flags, int startId) { boolean performedReplace = EXECUTOR.enqueue(this::fetch); @@ -58,6 +73,18 @@ public class FcmFetchService extends Service { Log.i(TAG, "Incrementing active count to " + count); } + if (intent.getBooleanExtra(KEY_FOREGROUND, false)) { + Log.i(TAG, "Launching in the foreground."); + startForeground(NotificationIds.FCM_FETCH, new NotificationCompat.Builder(this, NotificationChannels.OTHER) + .setSmallIcon(R.drawable.ic_notification) + .setContentTitle(getString(R.string.BackgroundMessageRetriever_checking_for_messages)) + .setCategory(NotificationCompat.CATEGORY_SERVICE) + .setProgress(0, 0, true) + .setContentIntent(PendingIntent.getActivity(this, 0, MainActivity.clearTop(this), 0)) + .setVibrate(new long[] { 0 }) + .build()); + } + return START_NOT_STICKY; } diff --git a/app/src/main/java/org/thoughtcrime/securesms/gcm/FcmReceiveService.java b/app/src/main/java/org/thoughtcrime/securesms/gcm/FcmReceiveService.java index decede38c7..fe57f237ce 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/gcm/FcmReceiveService.java +++ b/app/src/main/java/org/thoughtcrime/securesms/gcm/FcmReceiveService.java @@ -2,8 +2,11 @@ package org.thoughtcrime.securesms.gcm; import android.content.Context; import android.content.Intent; +import android.os.Build; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.core.content.ContextCompat; import com.google.firebase.messaging.FirebaseMessagingService; import com.google.firebase.messaging.RemoteMessage; @@ -16,11 +19,13 @@ import org.thoughtcrime.securesms.keyvalue.SignalStore; import org.thoughtcrime.securesms.registration.PushChallengeRequest; import java.util.Locale; +import java.util.concurrent.TimeUnit; public class FcmReceiveService extends FirebaseMessagingService { private static final String TAG = Log.tag(FcmReceiveService.class); + private static final long FCM_FOREGROUND_INTERVAL = TimeUnit.MINUTES.toMillis(3); @Override public void onMessageReceived(RemoteMessage remoteMessage) { @@ -38,15 +43,15 @@ public class FcmReceiveService extends FirebaseMessagingService { handleRegistrationPushChallenge(registrationChallenge); } else if (rateLimitChallenge != null) { handleRateLimitPushChallenge(rateLimitChallenge); - }else { - handleReceivedNotification(ApplicationDependencies.getApplication()); + } else { + handleReceivedNotification(ApplicationDependencies.getApplication(), remoteMessage); } } @Override public void onDeletedMessages() { Log.w(TAG, "onDeleteMessages() -- Messages may have been dropped. Doing a normal message fetch."); - handleReceivedNotification(ApplicationDependencies.getApplication()); + handleReceivedNotification(ApplicationDependencies.getApplication(), null); } @Override @@ -71,11 +76,17 @@ public class FcmReceiveService extends FirebaseMessagingService { Log.w(TAG, "onSendError()", e); } - private static void handleReceivedNotification(Context context) { + private static void handleReceivedNotification(Context context, @Nullable RemoteMessage remoteMessage) { try { - context.startService(new Intent(context, FcmFetchService.class)); + long timeSinceLastRefresh = System.currentTimeMillis() - SignalStore.misc().getLastFcmForegroundServiceTime(); + if (Build.VERSION.SDK_INT >= 31 && remoteMessage != null && remoteMessage.getPriority() == RemoteMessage.PRIORITY_HIGH && timeSinceLastRefresh > FCM_FOREGROUND_INTERVAL) { + ContextCompat.startForegroundService(context, FcmFetchService.buildIntent(context, true)); + SignalStore.misc().setLastFcmForegroundServiceTime(System.currentTimeMillis()); + } else { + context.startService(FcmFetchService.buildIntent(context, false)); + } } catch (Exception e) { - Log.w(TAG, "Failed to start service. Falling back to legacy approach."); + Log.w(TAG, "Failed to start service. Falling back to legacy approach.", e); FcmFetchService.retrieveMessages(context); } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/keyvalue/MiscellaneousValues.java b/app/src/main/java/org/thoughtcrime/securesms/keyvalue/MiscellaneousValues.java index a2370bb146..f5f9e30cf2 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/keyvalue/MiscellaneousValues.java +++ b/app/src/main/java/org/thoughtcrime/securesms/keyvalue/MiscellaneousValues.java @@ -21,6 +21,7 @@ public final class MiscellaneousValues extends SignalStoreValues { private static final String CENSORSHIP_SERVICE_REACHABLE = "misc.censorship.service_reachable"; private static final String LAST_GV2_PROFILE_CHECK_TIME = "misc.last_gv2_profile_check_time"; private static final String CDS_TOKEN = "misc.cds_token"; + private static final String LAST_FCM_FOREGROUND_TIME = "misc.last_fcm_foreground_time"; MiscellaneousValues(@NonNull KeyValueStore store) { super(store); @@ -149,4 +150,12 @@ public final class MiscellaneousValues extends SignalStoreValues { .putBlob(CDS_TOKEN, token) .commit(); } + + public long getLastFcmForegroundServiceTime() { + return getLong(LAST_FCM_FOREGROUND_TIME, 0); + } + + public void setLastFcmForegroundServiceTime(long time) { + putLong(LAST_FCM_FOREGROUND_TIME, time); + } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/notifications/NotificationIds.java b/app/src/main/java/org/thoughtcrime/securesms/notifications/NotificationIds.java index ebec892283..3057efd830 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/notifications/NotificationIds.java +++ b/app/src/main/java/org/thoughtcrime/securesms/notifications/NotificationIds.java @@ -14,6 +14,7 @@ public final class NotificationIds { public static final int USER_NOTIFICATION_MIGRATION = 525600; public static final int DEVICE_TRANSFER = 625420; public static final int DONOR_BADGE_FAILURE = 630001; + public static final int FCM_FETCH = 630002; private NotificationIds() { }