Signal-Android/src/org/thoughtcrime/securesms/gcm/FcmService.java

160 lines
6.0 KiB
Java

package org.thoughtcrime.securesms.gcm;
import android.content.Context;
import android.os.PowerManager;
import android.support.annotation.NonNull;
import com.google.firebase.messaging.FirebaseMessagingService;
import com.google.firebase.messaging.RemoteMessage;
import org.thoughtcrime.securesms.ApplicationContext;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.dependencies.InjectableType;
import org.thoughtcrime.securesms.jobmanager.requirements.NetworkRequirement;
import org.thoughtcrime.securesms.jobs.FcmRefreshJob;
import org.thoughtcrime.securesms.jobs.PushNotificationReceiveJob;
import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.notifications.NotificationChannels;
import org.thoughtcrime.securesms.service.GenericForegroundService;
import org.thoughtcrime.securesms.util.PowerManagerCompat;
import org.thoughtcrime.securesms.util.ServiceUtil;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.WakeLockUtil;
import org.thoughtcrime.securesms.util.concurrent.SignalExecutors;
import org.whispersystems.signalservice.api.SignalServiceAccountManager;
import org.whispersystems.signalservice.api.SignalServiceMessageReceiver;
import org.whispersystems.signalservice.internal.util.Util;
import java.io.IOException;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.inject.Inject;
public class FcmService extends FirebaseMessagingService implements InjectableType {
private static final String TAG = FcmService.class.getSimpleName();
private static final Executor MESSAGE_EXECUTOR = SignalExecutors.newCachedSingleThreadExecutor("FcmMessageProcessing");
private static final String WAKE_LOCK_TAG = "FcmMessageProcessing";
@Inject SignalServiceMessageReceiver messageReceiver;
private static int activeCount;
@Override
public void onMessageReceived(RemoteMessage remoteMessage) {
Log.i(TAG, "FCM message... Original Priority: " + remoteMessage.getOriginalPriority() + ", Actual Priority: " + remoteMessage.getPriority());
ApplicationContext.getInstance(getApplicationContext()).injectDependencies(this);
WakeLockUtil.runWithLock(getApplicationContext(), PowerManager.PARTIAL_WAKE_LOCK, 60000, WAKE_LOCK_TAG, () -> {
handleReceivedNotification(getApplicationContext());
});
}
@Override
public void onNewToken(String token) {
Log.i(TAG, "onNewToken()");
if (!TextSecurePreferences.isPushRegistered(getApplicationContext())) {
Log.i(TAG, "Got a new FCM token, but the user isn't registered.");
return;
}
ApplicationContext.getInstance(getApplicationContext())
.getJobManager()
.add(new FcmRefreshJob(getApplicationContext()));
}
private void handleReceivedNotification(Context context) {
if (!incrementActiveGcmCount()) {
Log.i(TAG, "Skipping FCM processing -- there's already one enqueued.");
return;
}
TextSecurePreferences.setNeedsMessagePull(context, true);
long startTime = System.currentTimeMillis();
PowerManager powerManager = ServiceUtil.getPowerManager(getApplicationContext());
boolean doze = PowerManagerCompat.isDeviceIdleMode(powerManager);
boolean network = new NetworkRequirement(context).isPresent();
final Object foregroundLock = new Object();
final AtomicBoolean foregroundRunning = new AtomicBoolean(false);
final AtomicBoolean taskCompleted = new AtomicBoolean(false);
final CountDownLatch latch = new CountDownLatch(1);
if (doze || !network) {
Log.i(TAG, "Starting a foreground task because we may be operating in a constrained environment. Doze: " + doze + " Network: " + network);
showForegroundNotification(context);
foregroundRunning.set(true);
latch.countDown();
}
MESSAGE_EXECUTOR.execute(() -> {
try {
new PushNotificationReceiveJob(context).pullAndProcessMessages(messageReceiver, TAG, startTime);
} catch (IOException e) {
Log.i(TAG, "Failed to retrieve the envelope. Scheduling on JobManager.", e);
ApplicationContext.getInstance(context)
.getJobManager()
.add(new PushNotificationReceiveJob(context));
} finally {
synchronized (foregroundLock) {
if (foregroundRunning.getAndSet(false)) {
GenericForegroundService.stopForegroundTask(context);
} else {
latch.countDown();
}
taskCompleted.set(true);
}
decrementActiveGcmCount();
Log.i(TAG, "Processing complete.");
}
});
if (!foregroundRunning.get()) {
new Thread("FcmForegroundServiceTimer") {
@Override
public void run() {
Util.sleep(7000);
synchronized (foregroundLock) {
if (!taskCompleted.get() && !foregroundRunning.getAndSet(true)) {
Log.i(TAG, "Starting a foreground task because the job is running long.");
showForegroundNotification(context);
latch.countDown();
}
}
}
}.start();
}
try {
latch.await();
} catch (InterruptedException e) {
Log.w(TAG, "Latch was interrupted.", e);
}
}
private void showForegroundNotification(@NonNull Context context) {
GenericForegroundService.startForegroundTask(context,
context.getString(R.string.GcmBroadcastReceiver_retrieving_a_message),
NotificationChannels.OTHER,
R.drawable.ic_signal_downloading);
}
private static synchronized boolean incrementActiveGcmCount() {
if (activeCount < 2) {
activeCount++;
return true;
}
return false;
}
private static synchronized void decrementActiveGcmCount() {
activeCount--;
}
}