@@ -49,6 +49,10 @@ public class RegistrationProgressActivity extends BaseActionBarActivity {

private static final String TAG = RegistrationProgressActivity.class.getSimpleName();

public static final String NUMBER_EXTRA = "e164number";
public static final String MASTER_SECRET_EXTRA = "master_secret";
public static final String GCM_SUPPORTED_EXTRA = "gcm_supported";

private static final int FOCUSED_COLOR = Color.parseColor("#ff333333");
private static final int UNFOCUSED_COLOR = Color.parseColor("#ff808080");

@@ -89,6 +93,7 @@ public class RegistrationProgressActivity extends BaseActionBarActivity {
private EditText codeEditText;

private MasterSecret masterSecret;
private boolean gcmSupported;
private volatile boolean visible;

@Override
@@ -131,7 +136,8 @@ private void initializeServiceBinding() {
}

private void initializeResources() {
this.masterSecret = getIntent().getParcelableExtra("master_secret");
this.masterSecret = getIntent().getParcelableExtra(MASTER_SECRET_EXTRA);
this.gcmSupported = getIntent().getBooleanExtra(GCM_SUPPORTED_EXTRA, true);
this.registrationLayout = (LinearLayout)findViewById(R.id.registering_layout);
this.verificationFailureLayout = (LinearLayout)findViewById(R.id.verification_failure_layout);
this.connectivityFailureLayout = (LinearLayout)findViewById(R.id.connectivity_failure_layout);
@@ -199,8 +205,9 @@ private void handleStateIdle() {
if (hasNumberDirective()) {
Intent intent = new Intent(this, RegistrationService.class);
intent.setAction(RegistrationService.REGISTER_NUMBER_ACTION);
intent.putExtra("e164number", getNumberDirective());
intent.putExtra("master_secret", masterSecret);
intent.putExtra(RegistrationService.NUMBER_EXTRA, getNumberDirective());
intent.putExtra(RegistrationService.MASTER_SECRET_EXTRA, masterSecret);
intent.putExtra(RegistrationService.GCM_SUPPORTED_EXTRA, gcmSupported);
startService(intent);
} else {
Intent intent = new Intent(this, RegistrationActivity.class);
@@ -295,7 +302,7 @@ private void handleGcmTimeout(RegistrationState state) {

private void handleVerificationRequestedVoice(RegistrationState state) {
handleVerificationTimeout(state);
verifyButton.setOnClickListener(new VerifyClickListener(state.number, state.password));
verifyButton.setOnClickListener(new VerifyClickListener(state.number, state.password, gcmSupported));
verifyButton.setEnabled(true);
codeEditText.setEnabled(true);
}
@@ -354,11 +361,11 @@ private void handleTimerUpdate() {
}

private boolean hasNumberDirective() {
return getIntent().getStringExtra("e164number") != null;
return getIntent().getStringExtra(NUMBER_EXTRA) != null;
}

private String getNumberDirective() {
return getIntent().getStringExtra("e164number");
return getIntent().getStringExtra(NUMBER_EXTRA);
}

private void shutdownServiceBinding() {
@@ -426,7 +433,8 @@ public void onClick(View v) {
shutdownService();

Intent activityIntent = new Intent(RegistrationProgressActivity.this, RegistrationActivity.class);
activityIntent.putExtra("master_secret", masterSecret);
activityIntent.putExtra(RegistrationProgressActivity.MASTER_SECRET_EXTRA, masterSecret);
activityIntent.putExtra(RegistrationProgressActivity.GCM_SUPPORTED_EXTRA, gcmSupported);
startActivity(activityIntent);
finish();
}
@@ -447,17 +455,19 @@ private class VerifyClickListener implements View.OnClickListener {
private static final int VERIFICATION_ERROR = 3;
private static final int MULTI_REGISTRATION_ERROR = 4;

private final String e164number;
private final String password;
private final String signalingKey;
private final String e164number;
private final String password;
private final String signalingKey;
private final boolean gcmSupported;
private final Context context;

private ProgressDialog progressDialog;

public VerifyClickListener(String e164number, String password) {
public VerifyClickListener(String e164number, String password, boolean gcmSupported) {
this.e164number = e164number;
this.password = password;
this.signalingKey = Util.getSecret(52);
this.gcmSupported = gcmSupported;
this.context = RegistrationProgressActivity.this;
}

@@ -490,10 +500,11 @@ protected void onPostExecute(Integer result) {
case SUCCESS:
Intent intent = new Intent(context, RegistrationService.class);
intent.setAction(RegistrationService.VOICE_REGISTER_ACTION);
intent.putExtra("e164number", e164number);
intent.putExtra("password", password);
intent.putExtra("signaling_key", signalingKey);
intent.putExtra("master_secret", masterSecret);
intent.putExtra(RegistrationService.NUMBER_EXTRA, e164number);
intent.putExtra(RegistrationService.PASSWORD_EXTRA, password);
intent.putExtra(RegistrationService.SIGNALING_KEY_EXTRA, signalingKey);
intent.putExtra(RegistrationService.MASTER_SECRET_EXTRA, masterSecret);
intent.putExtra(RegistrationService.GCM_SUPPORTED_EXTRA, gcmSupported);
startService(intent);
break;
case NETWORK_ERROR:
@@ -522,7 +533,7 @@ protected Integer doInBackground(Void... params) {
int registrationId = TextSecurePreferences.getLocalRegistrationId(context);
boolean video = TextSecurePreferences.isWebrtcCallingEnabled(context);

accountManager.verifyAccountWithCode(code, signalingKey, registrationId, true, video);
accountManager.verifyAccountWithCode(code, signalingKey, registrationId, true, video, !gcmSupported);

return SUCCESS;
} catch (ExpectationFailedException e) {
@@ -578,9 +589,10 @@ protected void onPostExecute(Integer result) {
case SUCCESS:
Intent intent = new Intent(context, RegistrationService.class);
intent.setAction(RegistrationService.VOICE_REQUESTED_ACTION);
intent.putExtra("e164number", e164number);
intent.putExtra("password", password);
intent.putExtra("master_secret", masterSecret);
intent.putExtra(RegistrationService.NUMBER_EXTRA, e164number);
intent.putExtra(RegistrationService.PASSWORD_EXTRA, password);
intent.putExtra(RegistrationService.MASTER_SECRET_EXTRA, masterSecret);
intent.putExtra(RegistrationService.GCM_SUPPORTED_EXTRA, gcmSupported);
startService(intent);

callButton.setEnabled(false);
@@ -0,0 +1,48 @@
package org.thoughtcrime.securesms.components.reminder;


import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.os.PowerManager;
import android.provider.Settings;
import android.support.annotation.NonNull;
import android.support.annotation.RequiresApi;
import android.view.View;

import org.thoughtcrime.securesms.util.TextSecurePreferences;

public class DozeReminder extends Reminder {

@RequiresApi(api = Build.VERSION_CODES.M)
public DozeReminder(@NonNull final Context context) {
super("Optimize for missing Play Services",
"This device does not support Play Services. Tap to disable system battery optimizations that prevent Signal from retrieving messages while inactive.");

setOkListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
TextSecurePreferences.setPromptedOptimizeDoze(context, true);
Intent intent = new Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS,
Uri.parse("package:" + context.getPackageName()));
context.startActivity(intent);
}
});

setDismissListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
TextSecurePreferences.setPromptedOptimizeDoze(context, true);
}
});
}

public static boolean isEligible(Context context) {
return TextSecurePreferences.isGcmDisabled(context) &&
!TextSecurePreferences.hasPromptedOptimizeDoze(context) &&
Build.VERSION.SDK_INT >= Build.VERSION_CODES.M &&
!((PowerManager)context.getSystemService(Context.POWER_SERVICE)).isIgnoringBatteryOptimizations(context.getPackageName());
}

}
@@ -60,6 +60,8 @@ public void onAdded() {}

@Override
public void onRun() throws Exception {
if (TextSecurePreferences.isGcmDisabled(context)) return;

String registrationId = TextSecurePreferences.getGcmRegistrationId(context);

if (registrationId == null) {
@@ -43,11 +43,12 @@ public void onRun() throws IOException {
String gcmRegistrationId = TextSecurePreferences.getGcmRegistrationId(context);
int registrationId = TextSecurePreferences.getLocalRegistrationId(context);
boolean video = TextSecurePreferences.isWebrtcCallingEnabled(context);
boolean fetchesMessages = TextSecurePreferences.isGcmDisabled(context);

String token = signalAccountManager.getAccountVerificationToken();

redPhoneAccountManager.createAccount(token, new RedPhoneAccountAttributes(signalingKey, gcmRegistrationId));
signalAccountManager.setAccountAttributes(signalingKey, registrationId, true, video);
signalAccountManager.setAccountAttributes(signalingKey, registrationId, true, video || fetchesMessages, fetchesMessages);
}

@Override
@@ -58,9 +58,11 @@
import org.thoughtcrime.securesms.recipients.RecipientFactory;
import org.thoughtcrime.securesms.recipients.Recipients;
import org.thoughtcrime.securesms.service.KeyCachingService;
import org.thoughtcrime.securesms.service.MessageRetrievalService;
import org.thoughtcrime.securesms.util.ServiceUtil;
import org.thoughtcrime.securesms.util.SpanUtil;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.webrtc.CallNotificationManager;
import org.whispersystems.signalservice.api.messages.SignalServiceEnvelope;

import java.util.HashSet;
@@ -155,7 +157,12 @@ private static void cancelOrphanedNotifications(@NonNull Context context, Notifi
for (StatusBarNotification notification : activeNotifications) {
boolean validNotification = false;

if (notification.getId() != SUMMARY_NOTIFICATION_ID && notification.getId() != NotificationBarManager.RED_PHONE_NOTIFICATION) {
if (notification.getId() != SUMMARY_NOTIFICATION_ID &&
notification.getId() != NotificationBarManager.RED_PHONE_NOTIFICATION &&
notification.getId() != CallNotificationManager.WEBRTC_NOTIFICATION &&
notification.getId() != KeyCachingService.SERVICE_RUNNING_ID &&
notification.getId() != MessageRetrievalService.FOREGROUND_ID)
{
for (NotificationItem item : notificationState.getNotifications()) {
if (notification.getId() == (SUMMARY_NOTIFICATION_ID + item.getThreadId())) {
validNotification = true;
@@ -99,7 +99,9 @@ private void initializePushMessagingToggle() {
}

private void initializeWebrtcCallingToggle() {
if (Build.VERSION.SDK_INT >= 11) {
if (TextSecurePreferences.isGcmDisabled(getContext())) {
getPreferenceScreen().removePreference(findPreference(TextSecurePreferences.WEBRTC_CALLING_PREF));
} else if (Build.VERSION.SDK_INT >= 11) {
this.findPreference(TextSecurePreferences.WEBRTC_CALLING_PREF)
.setOnPreferenceChangeListener(new WebRtcClickListener());
} else {
@@ -5,9 +5,11 @@
import android.content.Intent;
import android.os.IBinder;
import android.support.annotation.Nullable;
import android.support.v4.app.NotificationCompat;
import android.util.Log;

import org.thoughtcrime.securesms.ApplicationContext;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.dependencies.InjectableType;
import org.thoughtcrime.securesms.gcm.GcmBroadcastReceiver;
import org.thoughtcrime.securesms.jobs.PushContentReceiveJob;
@@ -24,16 +26,20 @@
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicBoolean;

import javax.inject.Inject;

public class MessageRetrievalService extends Service implements Runnable, InjectableType, RequirementListener {
public class MessageRetrievalService extends Service implements InjectableType, RequirementListener {

private static final String TAG = MessageRetrievalService.class.getSimpleName();

public static final String ACTION_ACTIVITY_STARTED = "ACTIVITY_STARTED";
public static final String ACTION_ACTIVITY_FINISHED = "ACTIVITY_FINISHED";
public static final String ACTION_PUSH_RECEIVED = "PUSH_RECEIVED";
public static final String ACTION_INITIALIZE = "INITIALIZE";
public static final int FOREGROUND_ID = 313399;

private static final long REQUEST_TIMEOUT_MINUTES = 1;

private NetworkRequirement networkRequirement;
@@ -42,8 +48,9 @@ public class MessageRetrievalService extends Service implements Runnable, Inject
@Inject
public SignalServiceMessageReceiver receiver;

private int activeActivities = 0;
private List<Intent> pushPending = new LinkedList<>();
private int activeActivities = 0;
private List<Intent> pushPending = new LinkedList<>();
private MessageRetrievalThread retrievalThread = null;

public static SignalServiceMessagePipe pipe = null;

@@ -56,7 +63,11 @@ public void onCreate() {
networkRequirementProvider = new NetworkRequirementProvider(this);

networkRequirementProvider.setListener(this);
new Thread(this, "MessageRetrievalService").start();

retrievalThread = new MessageRetrievalThread();
retrievalThread.start();

setForegroundIfNecessary();
}

public int onStartCommand(Intent intent, int flags, int startId) {
@@ -70,44 +81,11 @@ public int onStartCommand(Intent intent, int flags, int startId) {
}

@Override
public void run() {
while (true) {
Log.w(TAG, "Waiting for websocket state change....");
waitForConnectionNecessary();

Log.w(TAG, "Making websocket connection....");
pipe = receiver.createMessagePipe();

try {
while (isConnectionNecessary()) {
try {
Log.w(TAG, "Reading message...");
pipe.read(REQUEST_TIMEOUT_MINUTES, TimeUnit.MINUTES,
new SignalServiceMessagePipe.MessagePipeCallback() {
@Override
public void onMessage(SignalServiceEnvelope envelope) {
Log.w(TAG, "Retrieved envelope! " + envelope.getSource());

PushContentReceiveJob receiveJob = new PushContentReceiveJob(MessageRetrievalService.this);
receiveJob.handle(envelope, false);

decrementPushReceived();
}
});
} catch (TimeoutException e) {
Log.w(TAG, "Application level read timeout...");
} catch (InvalidVersionException e) {
Log.w(TAG, e);
}
}
} catch (Throwable e) {
Log.w(TAG, e);
} finally {
Log.w(TAG, "Shutting down pipe...");
shutdown(pipe);
}
public void onDestroy() {
super.onDestroy();

Log.w(TAG, "Looping...");
if (retrievalThread != null) {
retrievalThread.stopThread();
}
}

@@ -123,6 +101,18 @@ public IBinder onBind(Intent intent) {
return null;
}

private void setForegroundIfNecessary() {
if (TextSecurePreferences.isGcmDisabled(this)) {
NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
builder.setContentTitle(getString(R.string.MessageRetrievalService_signal));
builder.setContentText(getString(R.string.MessageRetrievalService_background_connection_enabled));
builder.setPriority(NotificationCompat.PRIORITY_MIN);
builder.setWhen(0);
builder.setSmallIcon(R.drawable.ic_signal_grey_24dp);
startForeground(FOREGROUND_ID, builder.build());
}
}

private synchronized void incrementActive() {
activeActivities++;
Log.w(TAG, "Active Count: " + activeActivities);
@@ -149,11 +139,13 @@ private synchronized void decrementPushReceived() {
}

private synchronized boolean isConnectionNecessary() {
Log.w(TAG, String.format("Network requirement: %s, active activities: %s, push pending: %s",
networkRequirement.isPresent(), activeActivities, pushPending.size()));
boolean isGcmDisabled = TextSecurePreferences.isGcmDisabled(this);

Log.w(TAG, String.format("Network requirement: %s, active activities: %s, push pending: %s, gcm disabled: %b",
networkRequirement.isPresent(), activeActivities, pushPending.size(), isGcmDisabled));

return TextSecurePreferences.isWebsocketRegistered(this) &&
(activeActivities > 0 || !pushPending.isEmpty()) &&
return TextSecurePreferences.isWebsocketRegistered(this) &&
(activeActivities > 0 || !pushPending.isEmpty() || isGcmDisabled) &&
networkRequirement.isPresent();
}

@@ -188,4 +180,59 @@ public static void registerActivityStopped(Context activity) {
public static @Nullable SignalServiceMessagePipe getPipe() {
return pipe;
}

private class MessageRetrievalThread extends Thread {

private AtomicBoolean stopThread = new AtomicBoolean(false);

@Override
public void run() {
while (!stopThread.get()) {
Log.w(TAG, "Waiting for websocket state change....");
waitForConnectionNecessary();

Log.w(TAG, "Making websocket connection....");
pipe = receiver.createMessagePipe();

SignalServiceMessagePipe localPipe = pipe;

try {
while (isConnectionNecessary() && !stopThread.get()) {
try {
Log.w(TAG, "Reading message...");
localPipe.read(REQUEST_TIMEOUT_MINUTES, TimeUnit.MINUTES,
new SignalServiceMessagePipe.MessagePipeCallback() {
@Override
public void onMessage(SignalServiceEnvelope envelope) {
Log.w(TAG, "Retrieved envelope! " + envelope.getSource());

PushContentReceiveJob receiveJob = new PushContentReceiveJob(MessageRetrievalService.this);
receiveJob.handle(envelope, false);

decrementPushReceived();
}
});
} catch (TimeoutException e) {
Log.w(TAG, "Application level read timeout...");
} catch (InvalidVersionException e) {
Log.w(TAG, e);
}
}
} catch (Throwable e) {
Log.w(TAG, e);
} finally {
Log.w(TAG, "Shutting down pipe...");
shutdown(localPipe);
}

Log.w(TAG, "Looping...");
}

Log.w(TAG, "Exiting...");
}

public void stopThread() {
stopThread.set(true);
}
}
}
@@ -0,0 +1,19 @@
package org.thoughtcrime.securesms.service;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;

import org.thoughtcrime.securesms.util.TextSecurePreferences;


public class PersistentConnectionBootListener extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if (TextSecurePreferences.isGcmDisabled(context)) {
Intent serviceIntent = new Intent(context, MessageRetrievalService.class);
serviceIntent.setAction(MessageRetrievalService.ACTION_INITIALIZE);
context.startService(serviceIntent);
}
}
}
@@ -71,7 +71,12 @@ public class RegistrationService extends Service {
public static final String CHALLENGE_EVENT = "org.thoughtcrime.securesms.CHALLENGE_EVENT";
public static final String REGISTRATION_EVENT = "org.thoughtcrime.securesms.REGISTRATION_EVENT";

public static final String CHALLENGE_EXTRA = "CAAChallenge";
public static final String NUMBER_EXTRA = "e164number";
public static final String MASTER_SECRET_EXTRA = "master_secret";
public static final String GCM_SUPPORTED_EXTRA = "gcm_supported";
public static final String PASSWORD_EXTRA = "password";
public static final String SIGNALING_KEY_EXTRA = "signaling_key";
public static final String CHALLENGE_EXTRA = "CAAChallenge";

private static final long REGISTRATION_TIMEOUT_MILLIS = 120000;

@@ -149,21 +154,22 @@ private synchronized void shutdownChallengeListener() {

private void handleVoiceRequestedIntent(Intent intent) {
setState(new RegistrationState(RegistrationState.STATE_VOICE_REQUESTED,
intent.getStringExtra("e164number"),
intent.getStringExtra("password")));
intent.getStringExtra(NUMBER_EXTRA),
intent.getStringExtra(PASSWORD_EXTRA)));
}

private void handleVoiceRegistrationIntent(Intent intent) {
markAsVerifying(true);

String number = intent.getStringExtra("e164number");
String password = intent.getStringExtra("password");
String signalingKey = intent.getStringExtra("signaling_key");
String number = intent.getStringExtra(NUMBER_EXTRA);
String password = intent.getStringExtra(PASSWORD_EXTRA);
String signalingKey = intent.getStringExtra(SIGNALING_KEY_EXTRA);
boolean supportsGcm = intent.getBooleanExtra(GCM_SUPPORTED_EXTRA, true);

try {
SignalServiceAccountManager accountManager = AccountManagerFactory.createManager(this, number, password);

handleCommonRegistration(accountManager, number, password, signalingKey);
handleCommonRegistration(accountManager, number, password, signalingKey, supportsGcm);

markAsVerified(number, password, signalingKey);

@@ -183,8 +189,10 @@ private void handleVoiceRegistrationIntent(Intent intent) {
private void handleSmsRegistrationIntent(Intent intent) {
markAsVerifying(true);

String number = intent.getStringExtra("e164number");
int registrationId = TextSecurePreferences.getLocalRegistrationId(this);
String number = intent.getStringExtra(NUMBER_EXTRA);
boolean supportsGcm = intent.getBooleanExtra(GCM_SUPPORTED_EXTRA, true);
int registrationId = TextSecurePreferences.getLocalRegistrationId(this);
boolean supportsVideo = TextSecurePreferences.isWebrtcCallingEnabled(this) || !supportsGcm;

if (registrationId == 0) {
registrationId = KeyHelper.generateRegistrationId(false);
@@ -203,9 +211,9 @@ private void handleSmsRegistrationIntent(Intent intent) {

setState(new RegistrationState(RegistrationState.STATE_VERIFYING, number));
String challenge = waitForChallenge();
accountManager.verifyAccountWithCode(challenge, signalingKey, registrationId, true, TextSecurePreferences.isWebrtcCallingEnabled(this));
accountManager.verifyAccountWithCode(challenge, signalingKey, registrationId, true, supportsVideo, !supportsGcm);

handleCommonRegistration(accountManager, number, password, signalingKey);
handleCommonRegistration(accountManager, number, password, signalingKey, supportsGcm);
markAsVerified(number, password, signalingKey);

setState(new RegistrationState(RegistrationState.STATE_COMPLETE, number));
@@ -231,7 +239,7 @@ private void handleSmsRegistrationIntent(Intent intent) {
}
}

private void handleCommonRegistration(SignalServiceAccountManager accountManager, String number, String password, String signalingKey)
private void handleCommonRegistration(SignalServiceAccountManager accountManager, String number, String password, String signalingKey, boolean supportsGcm)
throws IOException
{
setState(new RegistrationState(RegistrationState.STATE_GENERATING_KEYS, number));
@@ -244,21 +252,29 @@ private void handleCommonRegistration(SignalServiceAccountManager accountManager

setState(new RegistrationState(RegistrationState.STATE_GCM_REGISTERING, number));

String gcmRegistrationId = GoogleCloudMessaging.getInstance(this).register(GcmRefreshJob.REGISTRATION_ID);
accountManager.setGcmId(Optional.of(gcmRegistrationId));
if (supportsGcm) {
String gcmRegistrationId = GoogleCloudMessaging.getInstance(this).register(GcmRefreshJob.REGISTRATION_ID);
accountManager.setGcmId(Optional.of(gcmRegistrationId));

TextSecurePreferences.setGcmRegistrationId(this, gcmRegistrationId);
TextSecurePreferences.setGcmDisabled(this, false);
} else {
TextSecurePreferences.setGcmDisabled(this, true);
}

TextSecurePreferences.setGcmRegistrationId(this, gcmRegistrationId);
TextSecurePreferences.setWebsocketRegistered(this, true);

DatabaseFactory.getIdentityDatabase(this).saveIdentity(self.getRecipientId(), identityKey.getPublicKey());
DirectoryHelper.refreshDirectory(this, accountManager, number);

RedPhoneAccountManager redPhoneAccountManager = new RedPhoneAccountManager(BuildConfig.REDPHONE_MASTER_URL,
new RedPhoneTrustStore(this),
number, password);
if (supportsGcm) {
RedPhoneAccountManager redPhoneAccountManager = new RedPhoneAccountManager(BuildConfig.REDPHONE_MASTER_URL,
new RedPhoneTrustStore(this),
number, password);

String verificationToken = accountManager.getAccountVerificationToken();
redPhoneAccountManager.createAccount(verificationToken, new RedPhoneAccountAttributes(signalingKey, gcmRegistrationId));
String verificationToken = accountManager.getAccountVerificationToken();
redPhoneAccountManager.createAccount(verificationToken, new RedPhoneAccountAttributes(signalingKey, TextSecurePreferences.getGcmRegistrationId(this)));
}

DirectoryRefreshListener.schedule(this);
RotateSignedPreKeyListener.schedule(this);
@@ -69,6 +69,7 @@ public class TextSecurePreferences {
private static final String GCM_PASSWORD_PREF = "pref_gcm_password";
private static final String PROMPTED_PUSH_REGISTRATION_PREF = "pref_prompted_push_registration";
private static final String PROMPTED_DEFAULT_SMS_PREF = "pref_prompted_default_sms";
private static final String PROMPTED_OPTIMIZE_DOZE_PREF = "pref_prompted_optimize_doze";
private static final String PROMPTED_SHARE_PREF = "pref_prompted_share";
private static final String SIGNALING_KEY_PREF = "pref_signaling_key";
private static final String DIRECTORY_FRESH_TIME_PREF = "pref_directory_refresh_time";
@@ -80,6 +81,7 @@ public class TextSecurePreferences {
private static final String SIGNED_PREKEY_REGISTERED_PREF = "pref_signed_prekey_registered";
private static final String WIFI_SMS_PREF = "pref_wifi_sms";

private static final String GCM_DISABLED_PREF = "pref_gcm_disabled";
private static final String GCM_REGISTRATION_ID_PREF = "pref_gcm_registration_id";
private static final String GCM_REGISTRATION_ID_VERSION_PREF = "pref_gcm_registration_id_version";
private static final String WEBSOCKET_REGISTERED_PREF = "pref_websocket_registered";
@@ -105,6 +107,14 @@ public static boolean isTurnOnly(Context context) {
return getBooleanPreference(context, ALWAYS_RELAY_CALLS_PREF, false);
}

public static boolean isGcmDisabled(Context context) {
return getBooleanPreference(context, GCM_DISABLED_PREF, false);
}

public static void setGcmDisabled(Context context, boolean disabled) {
setBooleanPreference(context, GCM_DISABLED_PREF, disabled);
}

public static boolean isWebrtcCallingEnabled(Context context) {
return getBooleanPreference(context, WEBRTC_CALLING_PREF, false);
}
@@ -481,6 +491,14 @@ public static void setPromptedDefaultSmsProvider(Context context, boolean value)
setBooleanPreference(context, PROMPTED_DEFAULT_SMS_PREF, value);
}

public static void setPromptedOptimizeDoze(Context context, boolean value) {
setBooleanPreference(context, PROMPTED_OPTIMIZE_DOZE_PREF, value);
}

public static boolean hasPromptedOptimizeDoze(Context context) {
return getBooleanPreference(context, PROMPTED_OPTIMIZE_DOZE_PREF, false);
}

public static boolean hasPromptedShare(Context context) {
return getBooleanPreference(context, PROMPTED_SHARE_PREF, false);
}