diff --git a/src/org/thoughtcrime/securesms/service/MessageRetrievalService.java b/src/org/thoughtcrime/securesms/service/MessageRetrievalService.java index c7b0a6c6d24..296d0316aa0 100644 --- a/src/org/thoughtcrime/securesms/service/MessageRetrievalService.java +++ b/src/org/thoughtcrime/securesms/service/MessageRetrievalService.java @@ -1,9 +1,14 @@ package org.thoughtcrime.securesms.service; import android.app.Service; +import android.app.AlarmManager; +import android.app.PendingIntent; +import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; +import android.content.IntentFilter; import android.os.IBinder; +import android.os.SystemClock; import android.support.annotation.Nullable; import android.support.v4.app.NotificationCompat; import android.util.Log; @@ -20,6 +25,7 @@ import org.whispersystems.libsignal.InvalidVersionException; import org.whispersystems.signalservice.api.SignalServiceMessagePipe; import org.whispersystems.signalservice.api.SignalServiceMessageReceiver; +import org.whispersystems.signalservice.api.util.SignalThread; import java.util.LinkedList; import java.util.List; @@ -43,6 +49,7 @@ public class MessageRetrievalService extends Service implements InjectableType, private NetworkRequirement networkRequirement; private NetworkRequirementProvider networkRequirementProvider; + private KeepAliveAlarmReceiver keepAliveAlarmReceiver = null; @Inject public SignalServiceMessageReceiver receiver; @@ -67,6 +74,7 @@ public void onCreate() { retrievalThread.start(); setForegroundIfNecessary(); + enableKeepAliveAlarmIfNecessary(); } public int onStartCommand(Intent intent, int flags, int startId) { @@ -87,6 +95,11 @@ public void onDestroy() { retrievalThread.stopThread(); } + if (keepAliveAlarmReceiver != null) { + keepAliveAlarmReceiver.stop(); + unregisterReceiver(keepAliveAlarmReceiver); + } + sendBroadcast(new Intent("org.thoughtcrime.securesms.RESTART")); } @@ -114,6 +127,14 @@ private void setForegroundIfNecessary() { } } + private void enableKeepAliveAlarmIfNecessary() { + if (TextSecurePreferences.isGcmDisabled(this)) { + keepAliveAlarmReceiver = new KeepAliveAlarmReceiver(); + registerReceiver(keepAliveAlarmReceiver, + new IntentFilter(KeepAliveAlarmReceiver.WAKE_UP_THREADS_ACTION)); + } + } + private synchronized void incrementActive() { activeActivities++; Log.w(TAG, "Active Count: " + activeActivities); @@ -183,6 +204,72 @@ public static void registerActivityStopped(Context activity) { return pipe; } + public class KeepAliveAlarmReceiver extends BroadcastReceiver { + + private final int KEEPALIVE_TIMEOUT_SECONDS = 55; + + private int pipes; + + public static final String WAKE_UP_THREADS_ACTION = "org.thoughtcrime.securesms.KeepAliveAlarmReceiver.WAKE_UP_THREADS"; + + private void setOrCancelAlarm(Context context, boolean set) { + Intent intent = new Intent(WAKE_UP_THREADS_ACTION); + PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent, 0); + AlarmManager alarmManager = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE); + + alarmManager.cancel(pendingIntent); + + if (set) { + Log.w(TAG, "Setting repeating alarm to trigger KeepAlive message."); + + alarmManager.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, + SystemClock.elapsedRealtime() + TimeUnit.SECONDS.toMillis(KEEPALIVE_TIMEOUT_SECONDS), + TimeUnit.SECONDS.toMillis(KEEPALIVE_TIMEOUT_SECONDS), + pendingIntent); + } else { + Log.w(TAG, "Canceling KeepAlive message alarm."); + } + } + + public synchronized void incrementPipes() { + if (pipes < 0) { + return; + } + + pipes++; + + if (pipes == 1) { + setOrCancelAlarm(MessageRetrievalService.this, true); + } + } + + public synchronized void decrementPipes() { + if (pipes < 0) { + return; + } + + pipes--; + + assert (pipes >= 0); + + if (pipes == 0) { + setOrCancelAlarm(MessageRetrievalService.this, false); + } + } + + public synchronized void stop() { + pipes = -1; + setOrCancelAlarm(MessageRetrievalService.this, false); + } + + @Override + public void onReceive(Context context, Intent intent) { + Log.w(TAG, "Triggering KeepAlive message."); + SignalThread.onTrigger(); + } + + } + private class MessageRetrievalThread extends Thread implements Thread.UncaughtExceptionHandler { private AtomicBoolean stopThread = new AtomicBoolean(false); @@ -203,6 +290,10 @@ public void run() { SignalServiceMessagePipe localPipe = pipe; + if (keepAliveAlarmReceiver != null) { + keepAliveAlarmReceiver.incrementPipes(); + } + try { while (isConnectionNecessary() && !stopThread.get()) { try { @@ -227,6 +318,9 @@ public void run() { } finally { Log.w(TAG, "Shutting down pipe..."); shutdown(localPipe); + if (keepAliveAlarmReceiver != null) { + keepAliveAlarmReceiver.decrementPipes(); + } } Log.w(TAG, "Looping...");