clean up: signal service protocols

This commit is contained in:
Ryan ZHAO
2021-02-22 10:41:27 +11:00
parent 88bbc0b677
commit 1db9ccdf27
39 changed files with 2 additions and 1936 deletions

View File

@@ -81,7 +81,6 @@ import org.thoughtcrime.securesms.notifications.DefaultMessageNotifier;
import org.thoughtcrime.securesms.notifications.NotificationChannels;
import org.thoughtcrime.securesms.notifications.OptimizedMessageNotifier;
import org.thoughtcrime.securesms.providers.BlobProvider;
import org.thoughtcrime.securesms.push.SignalServiceNetworkAccess;
import org.thoughtcrime.securesms.service.ExpiringMessageManager;
import org.thoughtcrime.securesms.service.KeyCachingService;
import org.thoughtcrime.securesms.service.LocalBackupListener;

View File

@@ -2,11 +2,8 @@ package org.thoughtcrime.securesms.dependencies;
import android.content.Context;
import org.session.libsignal.libsignal.util.guava.Optional;
import org.session.libsignal.service.api.SignalServiceMessageReceiver;
import org.session.libsignal.service.api.SignalServiceMessageSender;
import org.session.libsignal.service.api.util.CredentialsProvider;
import org.session.libsignal.service.api.websocket.ConnectivityListener;
import org.thoughtcrime.securesms.ApplicationContext;
import org.thoughtcrime.securesms.crypto.storage.SignalProtocolStoreImpl;
import org.thoughtcrime.securesms.database.DatabaseFactory;
@@ -24,15 +21,12 @@ import org.thoughtcrime.securesms.jobs.SendDeliveryReceiptJob;
import org.thoughtcrime.securesms.jobs.SendReadReceiptJob;
import org.thoughtcrime.securesms.jobs.TypingSendJob;
import org.thoughtcrime.securesms.linkpreview.LinkPreviewRepository;
import org.session.libsignal.utilities.logging.Log;
import org.thoughtcrime.securesms.loki.api.SessionProtocolImpl;
import org.thoughtcrime.securesms.preferences.AppProtectionPreferenceFragment;
import org.thoughtcrime.securesms.util.RealtimeSleepTimer;
import org.session.libsession.utilities.TextSecurePreferences;
import dagger.Module;
import dagger.Provides;
import network.loki.messenger.BuildConfig;
@Module(complete = false, injects = {PushGroupSendJob.class,
PushTextSendJob.class,
@@ -52,8 +46,6 @@ import network.loki.messenger.BuildConfig;
public class SignalCommunicationModule {
private static final String TAG = SignalCommunicationModule.class.getSimpleName();
private final Context context;
private SignalServiceMessageSender messageSender;
@@ -66,8 +58,7 @@ public class SignalCommunicationModule {
@Provides
public synchronized SignalServiceMessageSender provideSignalMessageSender() {
if (this.messageSender == null) {
this.messageSender = new SignalServiceMessageSender(new DynamicCredentialsProvider(context),
new SignalProtocolStoreImpl(context),
this.messageSender = new SignalServiceMessageSender(new SignalProtocolStoreImpl(context),
TextSecurePreferences.getLocalNumber(context),
DatabaseFactory.getLokiAPIDatabase(context),
DatabaseFactory.getLokiThreadDatabase(context),
@@ -89,54 +80,4 @@ public class SignalCommunicationModule {
return this.messageReceiver;
}
private static class DynamicCredentialsProvider implements CredentialsProvider {
private final Context context;
private DynamicCredentialsProvider(Context context) {
this.context = context.getApplicationContext();
}
@Override
public String getUser() {
return TextSecurePreferences.getLocalNumber(context);
}
@Override
public String getPassword() {
return TextSecurePreferences.getPushServerPassword(context);
}
@Override
public String getSignalingKey() {
return TextSecurePreferences.getSignalingKey(context);
}
}
private class PipeConnectivityListener implements ConnectivityListener {
@Override
public void onConnected() {
Log.i(TAG, "onConnected()");
}
@Override
public void onConnecting() {
Log.i(TAG, "onConnecting()");
}
@Override
public void onDisconnected() {
Log.w(TAG, "onDisconnected()");
}
@Override
public void onAuthenticationFailure() {
Log.w(TAG, "onAuthenticationFailure()");
TextSecurePreferences.setUnauthorizedReceived(context, true);
}
}
}

View File

@@ -25,7 +25,6 @@ import org.thoughtcrime.securesms.mms.OutgoingGroupMediaMessage;
import org.thoughtcrime.securesms.providers.BlobProvider;
import org.thoughtcrime.securesms.sms.MessageSender;
import org.thoughtcrime.securesms.util.BitmapUtil;
import org.session.libsignal.service.api.util.InvalidNumberException;
import org.session.libsignal.service.internal.push.SignalServiceProtos.GroupContext;
import java.util.Collection;
@@ -137,7 +136,6 @@ public class GroupManager {
@Nullable Bitmap avatar,
@Nullable String name,
@NonNull Set<Recipient> admins)
throws InvalidNumberException
{
final GroupDatabase groupDatabase = DatabaseFactory.getGroupDatabase(context);
final Set<Address> memberAddresses = getMemberAddresses(members);

View File

@@ -1,29 +0,0 @@
package org.thoughtcrime.securesms.push;
import android.content.Context;
import network.loki.messenger.R;
import org.session.libsignal.service.api.push.TrustStore;
import java.io.InputStream;
public class DomainFrontingTrustStore implements TrustStore {
private final Context context;
public DomainFrontingTrustStore(Context context) {
this.context = context.getApplicationContext();
}
@Override
public InputStream getKeyStoreInputStream() {
return context.getResources().openRawResource(R.raw.censorship_fronting);
}
@Override
public String getKeyStorePassword() {
return "whisper";
}
}

View File

@@ -1,27 +0,0 @@
package org.thoughtcrime.securesms.push;
import android.content.Context;
import network.loki.messenger.R;
import org.session.libsignal.service.api.push.TrustStore;
import java.io.InputStream;
public class IasTrustStore implements TrustStore {
private final Context context;
public IasTrustStore(Context context) {
this.context = context.getApplicationContext();
}
@Override
public InputStream getKeyStoreInputStream() {
return context.getResources().openRawResource(R.raw.ias);
}
@Override
public String getKeyStorePassword() {
return "whisper";
}
}

View File

@@ -1,20 +0,0 @@
package org.thoughtcrime.securesms.push;
import android.content.Context;
import org.thoughtcrime.securesms.crypto.SecurityEvent;
import org.session.libsignal.service.api.SignalServiceMessageSender;
import org.session.libsignal.service.api.push.SignalServiceAddress;
public class MessageSenderEventListener implements SignalServiceMessageSender.EventListener {
private final Context context;
public MessageSenderEventListener(Context context) {
this.context = context.getApplicationContext();
}
@Override
public void onSecurityEvent(SignalServiceAddress textSecureAddress) {
SecurityEvent.broadcastSecurityUpdateEvent(context);
}
}

View File

@@ -1,171 +0,0 @@
package org.thoughtcrime.securesms.push;
import android.content.Context;
import androidx.annotation.Nullable;
import org.session.libsession.utilities.TextSecurePreferences;
import org.session.libsignal.service.api.push.TrustStore;
import org.session.libsignal.service.internal.configuration.SignalCdnUrl;
import org.session.libsignal.service.internal.configuration.SignalContactDiscoveryUrl;
import org.session.libsignal.service.internal.configuration.SignalServiceConfiguration;
import org.session.libsignal.service.internal.configuration.SignalServiceUrl;
import java.util.HashMap;
import java.util.Map;
import network.loki.messenger.BuildConfig;
import okhttp3.CipherSuite;
import okhttp3.ConnectionSpec;
import okhttp3.TlsVersion;
public class SignalServiceNetworkAccess {
@SuppressWarnings("unused")
private static final String TAG = SignalServiceNetworkAccess.class.getSimpleName();
private static final String COUNTRY_CODE_EGYPT = "+20";
private static final String COUNTRY_CODE_UAE = "+971";
private static final String COUNTRY_CODE_OMAN = "+968";
private static final String COUNTRY_CODE_QATAR = "+974";
private static final String SERVICE_REFLECTOR_HOST = "europe-west1-signal-cdn-reflector.cloudfunctions.net";
private static final ConnectionSpec GMAPS_CONNECTION_SPEC = new ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS)
.tlsVersions(TlsVersion.TLS_1_2)
.cipherSuites(CipherSuite.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
CipherSuite.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
CipherSuite.TLS_RSA_WITH_AES_128_GCM_SHA256,
CipherSuite.TLS_RSA_WITH_AES_256_GCM_SHA384,
CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA,
CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA)
.supportsTlsExtensions(true)
.build();
private static final ConnectionSpec GMAIL_CONNECTION_SPEC = new ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS)
.tlsVersions(TlsVersion.TLS_1_2)
.cipherSuites(CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
CipherSuite.TLS_RSA_WITH_AES_128_GCM_SHA256,
CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA,
CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA)
.supportsTlsExtensions(true)
.build();
private static final ConnectionSpec PLAY_CONNECTION_SPEC = new ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS)
.tlsVersions(TlsVersion.TLS_1_2)
.cipherSuites(CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
CipherSuite.TLS_RSA_WITH_AES_128_GCM_SHA256,
CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA,
CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA)
.supportsTlsExtensions(true)
.build();
private final Map<String, SignalServiceConfiguration> censorshipConfiguration;
private final String[] censoredCountries;
private final SignalServiceConfiguration uncensoredConfiguration;
public SignalServiceNetworkAccess(Context context) {
final TrustStore trustStore = new DomainFrontingTrustStore(context);
final SignalServiceUrl baseGoogleService = new SignalServiceUrl("https://www.google.com/service", SERVICE_REFLECTOR_HOST, trustStore, GMAIL_CONNECTION_SPEC);
final SignalServiceUrl baseAndroidService = new SignalServiceUrl("https://android.clients.google.com/service", SERVICE_REFLECTOR_HOST, trustStore, PLAY_CONNECTION_SPEC);
final SignalServiceUrl mapsOneAndroidService = new SignalServiceUrl("https://clients3.google.com/service", SERVICE_REFLECTOR_HOST, trustStore, GMAPS_CONNECTION_SPEC);
final SignalServiceUrl mapsTwoAndroidService = new SignalServiceUrl("https://clients4.google.com/service", SERVICE_REFLECTOR_HOST, trustStore, GMAPS_CONNECTION_SPEC);
final SignalServiceUrl mailAndroidService = new SignalServiceUrl("https://inbox.google.com/service", SERVICE_REFLECTOR_HOST, trustStore, GMAIL_CONNECTION_SPEC);
final SignalServiceUrl egyptGoogleService = new SignalServiceUrl("https://www.google.com.eg/service", SERVICE_REFLECTOR_HOST, trustStore, GMAIL_CONNECTION_SPEC);
final SignalServiceUrl uaeGoogleService = new SignalServiceUrl("https://www.google.com.ae/service", SERVICE_REFLECTOR_HOST, trustStore, GMAIL_CONNECTION_SPEC);
final SignalServiceUrl omanGoogleService = new SignalServiceUrl("https://www.google.com.om/service", SERVICE_REFLECTOR_HOST, trustStore, GMAIL_CONNECTION_SPEC);
final SignalServiceUrl qatarGoogleService = new SignalServiceUrl("https://www.google.com.qa/service", SERVICE_REFLECTOR_HOST, trustStore, GMAIL_CONNECTION_SPEC);
final SignalCdnUrl baseGoogleCdn = new SignalCdnUrl("https://www.google.com/cdn", SERVICE_REFLECTOR_HOST, trustStore, GMAIL_CONNECTION_SPEC);
final SignalCdnUrl baseAndroidCdn = new SignalCdnUrl("https://android.clients.google.com/cdn", SERVICE_REFLECTOR_HOST, trustStore, PLAY_CONNECTION_SPEC);
final SignalCdnUrl mapsOneAndroidCdn = new SignalCdnUrl("https://clients3.google.com/cdn", SERVICE_REFLECTOR_HOST, trustStore, GMAPS_CONNECTION_SPEC);
final SignalCdnUrl mapsTwoAndroidCdn = new SignalCdnUrl("https://clients4.google.com/cdn", SERVICE_REFLECTOR_HOST, trustStore, GMAPS_CONNECTION_SPEC);
final SignalCdnUrl mailAndroidCdn = new SignalCdnUrl("https://inbox.google.com/cdn", SERVICE_REFLECTOR_HOST, trustStore, GMAIL_CONNECTION_SPEC);
final SignalCdnUrl egyptGoogleCdn = new SignalCdnUrl("https://www.google.com.eg/cdn", SERVICE_REFLECTOR_HOST, trustStore, GMAIL_CONNECTION_SPEC);
final SignalCdnUrl uaeGoogleCdn = new SignalCdnUrl("https://www.google.com.ae/cdn", SERVICE_REFLECTOR_HOST, trustStore, GMAIL_CONNECTION_SPEC);
final SignalCdnUrl omanGoogleCdn = new SignalCdnUrl("https://www.google.com.om/cdn", SERVICE_REFLECTOR_HOST, trustStore, GMAIL_CONNECTION_SPEC);
final SignalCdnUrl qatarGoogleCdn = new SignalCdnUrl("https://www.google.com.qa/cdn", SERVICE_REFLECTOR_HOST, trustStore, GMAIL_CONNECTION_SPEC);
final SignalContactDiscoveryUrl baseGoogleDiscovery = new SignalContactDiscoveryUrl("https://www.google.com/directory", SERVICE_REFLECTOR_HOST, trustStore, GMAIL_CONNECTION_SPEC);
final SignalContactDiscoveryUrl baseAndroidDiscovery = new SignalContactDiscoveryUrl("https://android.clients.google.com/directory", SERVICE_REFLECTOR_HOST, trustStore, PLAY_CONNECTION_SPEC);
final SignalContactDiscoveryUrl mapsOneAndroidDiscovery = new SignalContactDiscoveryUrl("https://clients3.google.com/directory", SERVICE_REFLECTOR_HOST, trustStore, GMAPS_CONNECTION_SPEC);
final SignalContactDiscoveryUrl mapsTwoAndroidDiscovery = new SignalContactDiscoveryUrl("https://clients4.google.com/directory", SERVICE_REFLECTOR_HOST, trustStore, GMAPS_CONNECTION_SPEC);
final SignalContactDiscoveryUrl mailAndroidDiscovery = new SignalContactDiscoveryUrl("https://inbox.google.com/directory", SERVICE_REFLECTOR_HOST, trustStore, GMAIL_CONNECTION_SPEC);
final SignalContactDiscoveryUrl egyptGoogleDiscovery = new SignalContactDiscoveryUrl("https://www.google.com.eg/directory", SERVICE_REFLECTOR_HOST, trustStore, GMAIL_CONNECTION_SPEC);
final SignalContactDiscoveryUrl uaeGoogleDiscovery = new SignalContactDiscoveryUrl("https://www.google.com.ae/directory", SERVICE_REFLECTOR_HOST, trustStore, GMAIL_CONNECTION_SPEC);
final SignalContactDiscoveryUrl omanGoogleDiscovery = new SignalContactDiscoveryUrl("https://www.google.com.om/directory", SERVICE_REFLECTOR_HOST, trustStore, GMAIL_CONNECTION_SPEC);
final SignalContactDiscoveryUrl qatarGoogleDiscovery = new SignalContactDiscoveryUrl("https://www.google.com.qa/directory", SERVICE_REFLECTOR_HOST, trustStore, GMAIL_CONNECTION_SPEC);
this.censorshipConfiguration = new HashMap<String, SignalServiceConfiguration>() {{
put(COUNTRY_CODE_EGYPT, new SignalServiceConfiguration(new SignalServiceUrl[] {egyptGoogleService, baseGoogleService, baseAndroidService, mapsOneAndroidService, mapsTwoAndroidService, mailAndroidService},
new SignalCdnUrl[] {egyptGoogleCdn, baseAndroidCdn, baseGoogleCdn, mapsOneAndroidCdn, mapsTwoAndroidCdn, mailAndroidCdn, mailAndroidCdn},
new SignalContactDiscoveryUrl[] {egyptGoogleDiscovery, baseGoogleDiscovery, baseAndroidDiscovery, mapsOneAndroidDiscovery, mapsTwoAndroidDiscovery, mailAndroidDiscovery}));
put(COUNTRY_CODE_UAE, new SignalServiceConfiguration(new SignalServiceUrl[] {uaeGoogleService, baseAndroidService, baseGoogleService, mapsOneAndroidService, mapsTwoAndroidService, mailAndroidService},
new SignalCdnUrl[] {uaeGoogleCdn, baseAndroidCdn, baseGoogleCdn, mapsOneAndroidCdn, mapsTwoAndroidCdn, mailAndroidCdn},
new SignalContactDiscoveryUrl[] {uaeGoogleDiscovery, baseGoogleDiscovery, baseAndroidDiscovery, mapsOneAndroidDiscovery, mapsTwoAndroidDiscovery, mailAndroidDiscovery}));
put(COUNTRY_CODE_OMAN, new SignalServiceConfiguration(new SignalServiceUrl[] {omanGoogleService, baseAndroidService, baseGoogleService, mapsOneAndroidService, mapsTwoAndroidService, mailAndroidService},
new SignalCdnUrl[] {omanGoogleCdn, baseAndroidCdn, baseGoogleCdn, mapsOneAndroidCdn, mapsTwoAndroidCdn, mailAndroidCdn},
new SignalContactDiscoveryUrl[] {omanGoogleDiscovery, baseGoogleDiscovery, baseAndroidDiscovery, mapsOneAndroidDiscovery, mapsTwoAndroidDiscovery, mailAndroidDiscovery}));
put(COUNTRY_CODE_QATAR, new SignalServiceConfiguration(new SignalServiceUrl[] {qatarGoogleService, baseAndroidService, baseGoogleService, mapsOneAndroidService, mapsTwoAndroidService, mailAndroidService},
new SignalCdnUrl[] {qatarGoogleCdn, baseAndroidCdn, baseGoogleCdn, mapsOneAndroidCdn, mapsTwoAndroidCdn, mailAndroidCdn},
new SignalContactDiscoveryUrl[] {qatarGoogleDiscovery, baseGoogleDiscovery, baseAndroidDiscovery, mapsOneAndroidDiscovery, mapsTwoAndroidDiscovery, mailAndroidDiscovery}));
}};
this.uncensoredConfiguration = new SignalServiceConfiguration(new SignalServiceUrl[] {new SignalServiceUrl(BuildConfig.SIGNAL_URL, new SignalServiceTrustStore(context))},
new SignalCdnUrl[] {new SignalCdnUrl(BuildConfig.SIGNAL_CDN_URL, new SignalServiceTrustStore(context))},
new SignalContactDiscoveryUrl[] {new SignalContactDiscoveryUrl(BuildConfig.SIGNAL_CONTACT_DISCOVERY_URL, new SignalServiceTrustStore(context))});
this.censoredCountries = this.censorshipConfiguration.keySet().toArray(new String[0]);
}
public SignalServiceConfiguration getConfiguration(Context context) {
String localNumber = TextSecurePreferences.getLocalNumber(context);
return getConfiguration(localNumber);
}
public SignalServiceConfiguration getConfiguration(@Nullable String localNumber) {
if (localNumber == null) return this.uncensoredConfiguration;
for (String censoredRegion : this.censoredCountries) {
if (localNumber.startsWith(censoredRegion)) {
return this.censorshipConfiguration.get(censoredRegion);
}
}
return this.uncensoredConfiguration;
}
public boolean isCensored(Context context) {
return getConfiguration(context) != this.uncensoredConfiguration;
}
public boolean isCensored(String number) {
return getConfiguration(number) != this.uncensoredConfiguration;
}
}

View File

@@ -1,27 +0,0 @@
package org.thoughtcrime.securesms.push;
import android.content.Context;
import network.loki.messenger.R;
import org.session.libsignal.service.api.push.TrustStore;
import java.io.InputStream;
public class SignalServiceTrustStore implements TrustStore {
private final Context context;
public SignalServiceTrustStore(Context context) {
this.context = context.getApplicationContext();
}
@Override
public InputStream getKeyStoreInputStream() {
return context.getResources().openRawResource(R.raw.whisper);
}
@Override
public String getKeyStorePassword() {
return "whisper";
}
}

View File

@@ -1,87 +0,0 @@
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 org.session.libsignal.utilities.logging.Log;
import org.session.libsignal.service.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 RealtimeSleepTimer implements SleepTimer {
private static final String TAG = RealtimeSleepTimer.class.getSimpleName();
private final AlarmReceiver alarmReceiver;
private final Context context;
public RealtimeSleepTimer(Context context) {
this.context = context;
alarmReceiver = new RealtimeSleepTimer.AlarmReceiver();
}
@Override
public void sleep(long millis) {
context.registerReceiver(alarmReceiver,
new IntentFilter(AlarmReceiver.WAKE_UP_THREAD_ACTION));
final long startTime = System.currentTimeMillis();
alarmReceiver.setAlarm(millis);
while (System.currentTimeMillis() - startTime < millis) {
try {
synchronized (this) {
wait(millis - System.currentTimeMillis() + startTime);
}
} catch (InterruptedException e) {
Log.w(TAG, e);
}
}
context.unregisterReceiver(alarmReceiver);
}
private class AlarmReceiver extends BroadcastReceiver {
private static final String WAKE_UP_THREAD_ACTION = "org.session.libsignal.service.api.util.RealtimeSleepTimer.AlarmReceiver.WAKE_UP_THREAD";
private void setAlarm(long millis) {
final Intent intent = new Intent(WAKE_UP_THREAD_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 (RealtimeSleepTimer.this) {
RealtimeSleepTimer.this.notifyAll();
}
}
}
}