diff --git a/src/org/thoughtcrime/securesms/dependencies/ApplicationDependencyProvider.java b/src/org/thoughtcrime/securesms/dependencies/ApplicationDependencyProvider.java index dd4612cd86..37027136c4 100644 --- a/src/org/thoughtcrime/securesms/dependencies/ApplicationDependencyProvider.java +++ b/src/org/thoughtcrime/securesms/dependencies/ApplicationDependencyProvider.java @@ -23,13 +23,13 @@ import org.thoughtcrime.securesms.push.SecurityEventListener; import org.thoughtcrime.securesms.push.SignalServiceNetworkAccess; import org.thoughtcrime.securesms.recipients.LiveRecipientCache; import org.thoughtcrime.securesms.service.IncomingMessageObserver; +import org.thoughtcrime.securesms.util.AlarmSleepTimer; import org.thoughtcrime.securesms.util.TextSecurePreferences; import org.whispersystems.libsignal.util.guava.Optional; import org.whispersystems.signalservice.api.SignalServiceAccountManager; import org.whispersystems.signalservice.api.SignalServiceMessageReceiver; import org.whispersystems.signalservice.api.SignalServiceMessageSender; import org.whispersystems.signalservice.api.util.CredentialsProvider; -import org.whispersystems.signalservice.api.util.RealtimeSleepTimer; import org.whispersystems.signalservice.api.util.SleepTimer; import org.whispersystems.signalservice.api.util.UptimeSleepTimer; import org.whispersystems.signalservice.api.websocket.ConnectivityListener; @@ -72,7 +72,7 @@ public class ApplicationDependencyProvider implements ApplicationDependencies.Pr @Override public @NonNull SignalServiceMessageReceiver provideSignalServiceMessageReceiver() { - SleepTimer sleepTimer = TextSecurePreferences.isFcmDisabled(context) ? new RealtimeSleepTimer(context) + SleepTimer sleepTimer = TextSecurePreferences.isFcmDisabled(context) ? new AlarmSleepTimer(context) : new UptimeSleepTimer(); return new SignalServiceMessageReceiver(networkAccess.getConfiguration(context), new DynamicCredentialsProvider(context), diff --git a/src/org/thoughtcrime/securesms/util/AlarmSleepTimer.java b/src/org/thoughtcrime/securesms/util/AlarmSleepTimer.java new file mode 100644 index 0000000000..8d38fb062c --- /dev/null +++ b/src/org/thoughtcrime/securesms/util/AlarmSleepTimer.java @@ -0,0 +1,98 @@ +package org.thoughtcrime.securesms.util; + +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.Build; +import android.os.SystemClock; +import android.util.Log; + +import java.util.concurrent.ConcurrentSkipListSet; + +import org.whispersystems.signalservice.api.util.SleepTimer; + +/** + * A sleep timer that is based on elapsed realtime, so + * that it works properly, even in low-power sleep modes. + * + */ +public class AlarmSleepTimer implements SleepTimer { + private static final String TAG = AlarmSleepTimer.class.getSimpleName(); + private static ConcurrentSkipListSet actionIdList = new ConcurrentSkipListSet<>(); + + private final Context context; + + public AlarmSleepTimer(Context context) { + this.context = context; + } + + @Override + public void sleep(long millis) { + final AlarmReceiver alarmReceiver = new AlarmSleepTimer.AlarmReceiver(); + int actionId = 0; + while (!actionIdList.add(actionId)){ + actionId++; + } + try { + context.registerReceiver(alarmReceiver, + new IntentFilter(AlarmReceiver.WAKE_UP_THREAD_ACTION + "." + actionId)); + + final long startTime = System.currentTimeMillis(); + alarmReceiver.setAlarm(millis, AlarmReceiver.WAKE_UP_THREAD_ACTION + "." + actionId); + + while (System.currentTimeMillis() - startTime < millis) { + try { + synchronized (this) { + wait(millis - System.currentTimeMillis() + startTime); + } + } catch (InterruptedException e) { + Log.w(TAG, e); + } + } + context.unregisterReceiver(alarmReceiver); + } catch(Exception e) { + Log.w(TAG, "Exception during sleep ...",e); + }finally { + actionIdList.remove(actionId); + } + } + + private class AlarmReceiver extends BroadcastReceiver { + private static final String WAKE_UP_THREAD_ACTION = "org.thoughtcrime.securesms.util.AlarmSleepTimer.AlarmReceiver.WAKE_UP_THREAD"; + + private void setAlarm(long millis, String action) { + final Intent intent = new Intent(action); + final PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent, 0); + final AlarmManager alarmManager = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE); + + Log.w(TAG, "Setting alarm to wake up in " + millis + "ms."); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + alarmManager.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP, + SystemClock.elapsedRealtime() + millis, + pendingIntent); + } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { + alarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP, + SystemClock.elapsedRealtime() + millis, + pendingIntent); + } else { + alarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, + SystemClock.elapsedRealtime() + millis, + pendingIntent); + } + } + + @Override + public void onReceive(Context context, Intent intent) { + Log.w(TAG, "Waking up."); + + synchronized (AlarmSleepTimer.this) { + AlarmSleepTimer.this.notifyAll(); + } + } + } +} +