Support for retrieving stored messages via websocket.
1) When registering with server, indicate that the server should store messages and send notifications. 2) Process notification GCM messages, and connect to the server to retrieve actual message content.pull/1/head
parent
023195dd4b
commit
d3271f548c
@ -1,3 +1,3 @@
|
||||
|
||||
all:
|
||||
protoc --java_out=../src/main/java/ IncomingPushMessageSignal.proto Provisioning.proto
|
||||
protoc --java_out=../src/main/java/ IncomingPushMessageSignal.proto Provisioning.proto WebSocketResources.proto
|
||||
|
@ -0,0 +1,46 @@
|
||||
/**
|
||||
* Copyright (C) 2014-2015 Open WhisperSystems
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package textsecure;
|
||||
|
||||
option java_package = "org.whispersystems.textsecure.internal.websocket";
|
||||
option java_outer_classname = "WebSocketProtos";
|
||||
|
||||
message WebSocketRequestMessage {
|
||||
optional string verb = 1;
|
||||
optional string path = 2;
|
||||
optional bytes body = 3;
|
||||
optional uint64 id = 4;
|
||||
}
|
||||
|
||||
message WebSocketResponseMessage {
|
||||
optional uint64 id = 1;
|
||||
optional uint32 status = 2;
|
||||
optional string message = 3;
|
||||
optional bytes body = 4;
|
||||
}
|
||||
|
||||
message WebSocketMessage {
|
||||
enum Type {
|
||||
UNKNOWN = 0;
|
||||
REQUEST = 1;
|
||||
RESPONSE = 2;
|
||||
}
|
||||
|
||||
optional Type type = 1;
|
||||
optional WebSocketRequestMessage request = 2;
|
||||
optional WebSocketResponseMessage response = 3;
|
||||
}
|
@ -0,0 +1,87 @@
|
||||
package org.whispersystems.textsecure.api;
|
||||
|
||||
import org.whispersystems.libaxolotl.InvalidVersionException;
|
||||
import org.whispersystems.textsecure.api.messages.TextSecureEnvelope;
|
||||
import org.whispersystems.textsecure.api.util.CredentialsProvider;
|
||||
import org.whispersystems.textsecure.internal.websocket.WebSocketConnection;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import static org.whispersystems.textsecure.internal.websocket.WebSocketProtos.WebSocketRequestMessage;
|
||||
import static org.whispersystems.textsecure.internal.websocket.WebSocketProtos.WebSocketResponseMessage;
|
||||
|
||||
public class TextSecureMessagePipe {
|
||||
|
||||
private final WebSocketConnection websocket;
|
||||
private final CredentialsProvider credentialsProvider;
|
||||
|
||||
public TextSecureMessagePipe(WebSocketConnection websocket, CredentialsProvider credentialsProvider) {
|
||||
this.websocket = websocket;
|
||||
this.credentialsProvider = credentialsProvider;
|
||||
|
||||
this.websocket.connect();
|
||||
}
|
||||
|
||||
public TextSecureEnvelope read(long timeout, TimeUnit unit)
|
||||
throws InvalidVersionException, IOException, TimeoutException
|
||||
{
|
||||
return read(timeout, unit, new NullMessagePipeCallback());
|
||||
}
|
||||
|
||||
public TextSecureEnvelope read(long timeout, TimeUnit unit, MessagePipeCallback callback)
|
||||
throws TimeoutException, IOException, InvalidVersionException
|
||||
{
|
||||
while (true) {
|
||||
WebSocketRequestMessage request = websocket.readRequest(unit.toMillis(timeout));
|
||||
WebSocketResponseMessage response = createWebSocketResponse(request);
|
||||
|
||||
try {
|
||||
if (isTextSecureEnvelope(request)) {
|
||||
TextSecureEnvelope envelope = new TextSecureEnvelope(request.getBody().toByteArray(),
|
||||
credentialsProvider.getSignalingKey());
|
||||
|
||||
callback.onMessage(envelope);
|
||||
return envelope;
|
||||
}
|
||||
} finally {
|
||||
websocket.sendResponse(response);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void shutdown() throws IOException {
|
||||
websocket.disconnect();
|
||||
}
|
||||
|
||||
private boolean isTextSecureEnvelope(WebSocketRequestMessage message) {
|
||||
return "PUT".equals(message.getVerb()) && "/api/v1/message".equals(message.getPath());
|
||||
}
|
||||
|
||||
private WebSocketResponseMessage createWebSocketResponse(WebSocketRequestMessage request) {
|
||||
if (isTextSecureEnvelope(request)) {
|
||||
return WebSocketResponseMessage.newBuilder()
|
||||
.setId(request.getId())
|
||||
.setStatus(200)
|
||||
.setMessage("OK")
|
||||
.build();
|
||||
} else {
|
||||
return WebSocketResponseMessage.newBuilder()
|
||||
.setId(request.getId())
|
||||
.setStatus(400)
|
||||
.setMessage("Unknown")
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
public static interface MessagePipeCallback {
|
||||
public void onMessage(TextSecureEnvelope envelope);
|
||||
}
|
||||
|
||||
private static class NullMessagePipeCallback implements MessagePipeCallback {
|
||||
@Override
|
||||
public void onMessage(TextSecureEnvelope envelope) {}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
package org.whispersystems.textsecure.api.util;
|
||||
|
||||
public interface CredentialsProvider {
|
||||
public String getUser();
|
||||
public String getPassword();
|
||||
public String getSignalingKey();
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
package org.whispersystems.textsecure.internal.util;
|
||||
|
||||
import org.whispersystems.textsecure.api.util.CredentialsProvider;
|
||||
|
||||
public class StaticCredentialsProvider implements CredentialsProvider {
|
||||
|
||||
private final String user;
|
||||
private final String password;
|
||||
private final String signalingKey;
|
||||
|
||||
public StaticCredentialsProvider(String user, String password, String signalingKey) {
|
||||
this.user = user;
|
||||
this.password = password;
|
||||
this.signalingKey = signalingKey;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUser() {
|
||||
return user;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSignalingKey() {
|
||||
return signalingKey;
|
||||
}
|
||||
}
|
@ -0,0 +1,292 @@
|
||||
package org.whispersystems.textsecure.internal.websocket;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import com.google.protobuf.InvalidProtocolBufferException;
|
||||
import com.squareup.okhttp.OkHttpClient;
|
||||
import com.squareup.okhttp.Request;
|
||||
import com.squareup.okhttp.Response;
|
||||
import com.squareup.okhttp.internal.ws.WebSocket;
|
||||
import com.squareup.okhttp.internal.ws.WebSocketListener;
|
||||
|
||||
import org.whispersystems.textsecure.api.push.TrustStore;
|
||||
import org.whispersystems.textsecure.api.util.CredentialsProvider;
|
||||
import org.whispersystems.textsecure.internal.util.BlacklistingTrustManager;
|
||||
import org.whispersystems.textsecure.internal.util.Util;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.security.KeyManagementException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.LinkedList;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.SSLSocketFactory;
|
||||
|
||||
import okio.Buffer;
|
||||
import okio.BufferedSource;
|
||||
|
||||
import static org.whispersystems.textsecure.internal.websocket.WebSocketProtos.WebSocketMessage;
|
||||
import static org.whispersystems.textsecure.internal.websocket.WebSocketProtos.WebSocketRequestMessage;
|
||||
import static org.whispersystems.textsecure.internal.websocket.WebSocketProtos.WebSocketResponseMessage;
|
||||
|
||||
public class WebSocketConnection {
|
||||
|
||||
private static final String TAG = WebSocketConnection.class.getSimpleName();
|
||||
|
||||
private final LinkedList<WebSocketRequestMessage> incomingRequests = new LinkedList<>();
|
||||
|
||||
private final String wsUri;
|
||||
private final TrustStore trustStore;
|
||||
private final CredentialsProvider credentialsProvider;
|
||||
|
||||
private Client client;
|
||||
private KeepAliveSender keepAliveSender;
|
||||
|
||||
public WebSocketConnection(String httpUri, TrustStore trustStore, CredentialsProvider credentialsProvider) {
|
||||
this.trustStore = trustStore;
|
||||
this.credentialsProvider = credentialsProvider;
|
||||
this.wsUri = httpUri.replace("https://", "wss://")
|
||||
.replace("http://", "ws://") + "/v1/websocket/?login=%s&password=%s";
|
||||
}
|
||||
|
||||
public synchronized void connect() {
|
||||
Log.w(TAG, "WSC connect()...");
|
||||
|
||||
if (client == null) {
|
||||
client = new Client(wsUri, trustStore, credentialsProvider);
|
||||
client.connect();
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void disconnect() throws IOException {
|
||||
Log.w(TAG, "WSC disconnect()...");
|
||||
|
||||
if (client != null) {
|
||||
client.disconnect();
|
||||
client = null;
|
||||
}
|
||||
|
||||
if (keepAliveSender != null) {
|
||||
keepAliveSender.shutdown();
|
||||
keepAliveSender = null;
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized WebSocketRequestMessage readRequest(long timeoutMillis)
|
||||
throws TimeoutException, IOException
|
||||
{
|
||||
if (client == null) {
|
||||
throw new IOException("Connection closed!");
|
||||
}
|
||||
|
||||
long startTime = System.currentTimeMillis();
|
||||
|
||||
while (client != null && incomingRequests.isEmpty() && elapsedTime(startTime) < timeoutMillis) {
|
||||
Util.wait(this, Math.max(1, timeoutMillis - elapsedTime(startTime)));
|
||||
}
|
||||
|
||||
if (incomingRequests.isEmpty() && client == null) throw new IOException("Connection closed!");
|
||||
else if (incomingRequests.isEmpty()) throw new TimeoutException("Timeout exceeded");
|
||||
else return incomingRequests.removeFirst();
|
||||
}
|
||||
|
||||
public synchronized void sendResponse(WebSocketResponseMessage response) throws IOException {
|
||||
if (client == null) {
|
||||
throw new IOException("Connection closed!");
|
||||
}
|
||||
|
||||
WebSocketMessage message = WebSocketMessage.newBuilder()
|
||||
.setType(WebSocketMessage.Type.RESPONSE)
|
||||
.setResponse(response)
|
||||
.build();
|
||||
|
||||
client.sendMessage(message.toByteArray());
|
||||
}
|
||||
|
||||
private synchronized void sendKeepAlive() throws IOException {
|
||||
if (keepAliveSender != null) {
|
||||
client.sendMessage(WebSocketMessage.newBuilder()
|
||||
.setType(WebSocketMessage.Type.REQUEST)
|
||||
.setRequest(WebSocketRequestMessage.newBuilder()
|
||||
.setId(System.currentTimeMillis())
|
||||
.setPath("/v1/keepalive")
|
||||
.setVerb("GET")
|
||||
.build()).build()
|
||||
.toByteArray());
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized void onMessage(byte[] payload) {
|
||||
Log.w(TAG, "WSC onMessage()");
|
||||
try {
|
||||
WebSocketMessage message = WebSocketMessage.parseFrom(payload);
|
||||
|
||||
Log.w(TAG, "Message Type: " + message.getType().getNumber());
|
||||
|
||||
if (message.getType().getNumber() == WebSocketMessage.Type.REQUEST_VALUE) {
|
||||
incomingRequests.add(message.getRequest());
|
||||
}
|
||||
|
||||
notifyAll();
|
||||
} catch (InvalidProtocolBufferException e) {
|
||||
Log.w(TAG, e);
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized void onClose() {
|
||||
Log.w(TAG, "onClose()...");
|
||||
|
||||
if (client != null) {
|
||||
client = null;
|
||||
connect();
|
||||
}
|
||||
|
||||
if (keepAliveSender != null) {
|
||||
keepAliveSender.shutdown();
|
||||
keepAliveSender = null;
|
||||
}
|
||||
|
||||
notifyAll();
|
||||
}
|
||||
|
||||
private synchronized void onConnected() {
|
||||
if (client != null) {
|
||||
keepAliveSender = new KeepAliveSender();
|
||||
keepAliveSender.start();
|
||||
}
|
||||
}
|
||||
|
||||
private long elapsedTime(long startTime) {
|
||||
return System.currentTimeMillis() - startTime;
|
||||
}
|
||||
|
||||
private class Client implements WebSocketListener {
|
||||
|
||||
private final String uri;
|
||||
private final TrustStore trustStore;
|
||||
private final CredentialsProvider credentialsProvider;
|
||||
|
||||
private WebSocket webSocket;
|
||||
private boolean closed;
|
||||
|
||||
public Client(String uri, TrustStore trustStore, CredentialsProvider credentialsProvider) {
|
||||
Log.w(TAG, "Connecting to: " + uri);
|
||||
|
||||
this.uri = uri;
|
||||
this.trustStore = trustStore;
|
||||
this.credentialsProvider = credentialsProvider;
|
||||
}
|
||||
|
||||
public void connect() {
|
||||
new Thread() {
|
||||
@Override
|
||||
public void run() {
|
||||
int attempt = 0;
|
||||
|
||||
while (newSocket()) {
|
||||
try {
|
||||
Response response = webSocket.connect(Client.this);
|
||||
|
||||
if (response.code() == 101) {
|
||||
onConnected();
|
||||
return;
|
||||
}
|
||||
|
||||
Log.w(TAG, "WebSocket Response: " + response.code());
|
||||
} catch (IOException e) {
|
||||
Log.w(TAG, e);
|
||||
}
|
||||
|
||||
Util.sleep(Math.min(++attempt * 200, TimeUnit.SECONDS.toMillis(15)));
|
||||
}
|
||||
}
|
||||
}.start();
|
||||
}
|
||||
|
||||
public synchronized void disconnect() {
|
||||
Log.w(TAG, "Calling disconnect()...");
|
||||
try {
|
||||
closed = true;
|
||||
if (webSocket != null) {
|
||||
webSocket.close(1000, "OK");
|
||||
}
|
||||
} catch (IOException e) {
|
||||
Log.w(TAG, e);
|
||||
}
|
||||
}
|
||||
|
||||
public void sendMessage(byte[] message) throws IOException {
|
||||
webSocket.sendMessage(WebSocket.PayloadType.BINARY, new Buffer().write(message));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMessage(BufferedSource payload, WebSocket.PayloadType type) throws IOException {
|
||||
Log.w(TAG, "onMessage: " + type);
|
||||
if (type.equals(WebSocket.PayloadType.BINARY)) {
|
||||
WebSocketConnection.this.onMessage(payload.readByteArray());
|
||||
}
|
||||
|
||||
payload.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClose(int code, String reason) {
|
||||
Log.w(TAG, String.format("onClose(%d, %s)", code, reason));
|
||||
WebSocketConnection.this.onClose();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(IOException e) {
|
||||
Log.w(TAG, e);
|
||||
WebSocketConnection.this.onClose();
|
||||
}
|
||||
|
||||
private synchronized boolean newSocket() {
|
||||
if (closed) return false;
|
||||
|
||||
String filledUri = String.format(uri, credentialsProvider.getUser(), credentialsProvider.getPassword());
|
||||
SSLSocketFactory socketFactory = createTlsSocketFactory(trustStore);
|
||||
|
||||
this.webSocket = WebSocket.newWebSocket(new OkHttpClient().setSslSocketFactory(socketFactory),
|
||||
new Request.Builder().url(filledUri).build());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private SSLSocketFactory createTlsSocketFactory(TrustStore trustStore) {
|
||||
try {
|
||||
SSLContext context = SSLContext.getInstance("TLS");
|
||||
context.init(null, BlacklistingTrustManager.createFor(trustStore), null);
|
||||
|
||||
return context.getSocketFactory();
|
||||
} catch (NoSuchAlgorithmException | KeyManagementException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class KeepAliveSender extends Thread {
|
||||
|
||||
private AtomicBoolean stop = new AtomicBoolean(false);
|
||||
|
||||
public void run() {
|
||||
while (!stop.get()) {
|
||||
try {
|
||||
Thread.sleep(TimeUnit.SECONDS.toMillis(15));
|
||||
|
||||
Log.w(TAG, "Sending keep alive...");
|
||||
sendKeepAlive();
|
||||
} catch (Throwable e) {
|
||||
Log.w(TAG, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void shutdown() {
|
||||
stop.set(true);
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,180 @@
|
||||
package org.thoughtcrime.securesms.service;
|
||||
|
||||
import android.app.Service;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.IBinder;
|
||||
import android.util.Log;
|
||||
|
||||
import org.thoughtcrime.securesms.ApplicationContext;
|
||||
import org.thoughtcrime.securesms.dependencies.InjectableType;
|
||||
import org.thoughtcrime.securesms.jobs.PushReceiveJob;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
import org.whispersystems.jobqueue.requirements.NetworkRequirement;
|
||||
import org.whispersystems.jobqueue.requirements.NetworkRequirementProvider;
|
||||
import org.whispersystems.jobqueue.requirements.RequirementListener;
|
||||
import org.whispersystems.libaxolotl.InvalidVersionException;
|
||||
import org.whispersystems.textsecure.api.TextSecureMessagePipe;
|
||||
import org.whispersystems.textsecure.api.TextSecureMessageReceiver;
|
||||
import org.whispersystems.textsecure.api.messages.TextSecureEnvelope;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
public class MessageRetrievalService extends Service implements Runnable, 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";
|
||||
private static final long REQUEST_TIMEOUT_MINUTES = 1;
|
||||
|
||||
private NetworkRequirement networkRequirement;
|
||||
private NetworkRequirementProvider networkRequirementProvider;
|
||||
|
||||
@Inject
|
||||
public TextSecureMessageReceiver receiver;
|
||||
|
||||
private int activeActivities = 0;
|
||||
private boolean pushPending = false;
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
ApplicationContext.getInstance(this).injectDependencies(this);
|
||||
|
||||
networkRequirement = new NetworkRequirement(this);
|
||||
networkRequirementProvider = new NetworkRequirementProvider(this);
|
||||
|
||||
networkRequirementProvider.setListener(this);
|
||||
new Thread(this, "MessageRetrievalService").start();
|
||||
}
|
||||
|
||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||
if (intent == null) return START_STICKY;
|
||||
|
||||
if (ACTION_ACTIVITY_STARTED.equals(intent.getAction())) incrementActive();
|
||||
else if (ACTION_ACTIVITY_FINISHED.equals(intent.getAction())) decrementActive();
|
||||
else if (ACTION_PUSH_RECEIVED.equals(intent.getAction())) incrementPushReceived();
|
||||
|
||||
return START_STICKY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
while (true) {
|
||||
Log.w(TAG, "Waiting for websocket state change....");
|
||||
waitForConnectionNecessary();
|
||||
|
||||
Log.w(TAG, "Making websocket connection....");
|
||||
TextSecureMessagePipe pipe = receiver.createMessagePipe();
|
||||
|
||||
try {
|
||||
while (isConnectionNecessary()) {
|
||||
try {
|
||||
Log.w(TAG, "Reading message...");
|
||||
pipe.read(REQUEST_TIMEOUT_MINUTES, TimeUnit.MINUTES,
|
||||
new TextSecureMessagePipe.MessagePipeCallback() {
|
||||
@Override
|
||||
public void onMessage(TextSecureEnvelope envelope) {
|
||||
Log.w(TAG, "Retrieved envelope! " + envelope.getSource());
|
||||
|
||||
PushReceiveJob receiveJob = new PushReceiveJob(MessageRetrievalService.this);
|
||||
receiveJob.handle(envelope, false);
|
||||
|
||||
decrementPushReceived();
|
||||
}
|
||||
});
|
||||
} catch (TimeoutException | InvalidVersionException e) {
|
||||
Log.w(TAG, e);
|
||||
}
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
Log.w(TAG, e);
|
||||
} finally {
|
||||
Log.w(TAG, "Shutting down pipe...");
|
||||
shutdown(pipe);
|
||||
}
|
||||
|
||||
Log.w(TAG, "Looping...");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequirementStatusChanged() {
|
||||
synchronized (this) {
|
||||
notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) {
|
||||
return null;
|
||||
}
|
||||
|
||||
private synchronized void incrementActive() {
|
||||
activeActivities++;
|
||||
Log.w(TAG, "Active Count: " + activeActivities);
|
||||
notifyAll();
|
||||
}
|
||||
|
||||
private synchronized void decrementActive() {
|
||||
activeActivities--;
|
||||
Log.w(TAG, "Active Count: " + activeActivities);
|
||||
notifyAll();
|
||||
}
|
||||
|
||||
private synchronized void incrementPushReceived() {
|
||||
pushPending = true;
|
||||
notifyAll();
|
||||
}
|
||||
|
||||
private synchronized void decrementPushReceived() {
|
||||
pushPending = false;
|
||||
notifyAll();
|
||||
}
|
||||
|
||||
private synchronized boolean isConnectionNecessary() {
|
||||
Log.w(TAG, "Network requirement: " + networkRequirement.isPresent());
|
||||
return TextSecurePreferences.isWebsocketRegistered(this) &&
|
||||
(activeActivities > 0 || pushPending) &&
|
||||
networkRequirement.isPresent();
|
||||
}
|
||||
|
||||
private synchronized void waitForConnectionNecessary() {
|
||||
try {
|
||||
while (!isConnectionNecessary()) wait();
|
||||
} catch (InterruptedException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
private void shutdown(TextSecureMessagePipe pipe) {
|
||||
try {
|
||||
pipe.shutdown();
|
||||
} catch (Throwable t) {
|
||||
Log.w(TAG, t);
|
||||
}
|
||||
}
|
||||
|
||||
public static void registerActivityStarted(Context activity) {
|
||||
Intent intent = new Intent(activity, MessageRetrievalService.class);
|
||||
intent.setAction(MessageRetrievalService.ACTION_ACTIVITY_STARTED);
|
||||
activity.startService(intent);
|
||||
}
|
||||
|
||||
public static void registerActivityStopped(Context activity) {
|
||||
Intent intent = new Intent(activity, MessageRetrievalService.class);
|
||||
intent.setAction(MessageRetrievalService.ACTION_ACTIVITY_FINISHED);
|
||||
activity.startService(intent);
|
||||
}
|
||||
|
||||
public static void registerPushReceived(Context context) {
|
||||
Intent intent = new Intent(context, MessageRetrievalService.class);
|
||||
intent.setAction(MessageRetrievalService.ACTION_PUSH_RECEIVED);
|
||||
context.startService(intent);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue