mirror of
https://github.com/oxen-io/session-android.git
synced 2025-02-19 19:38:45 +00:00
Support for robust delivery.
1) If a message fails to be delivered, post a notification in the status bar if that thread is not active and visible. 2) If a message fails to be delivered because there is no service, keep retrying every time service becomes available again.
This commit is contained in:
parent
71f43075a9
commit
471ef16a5b
@ -163,6 +163,15 @@
|
||||
<data android:mimeType="application/vnd.wap.mms-message" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
<receiver android:name=".service.SystemStateListener"
|
||||
android:enabled="true"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.SERVICE_STATE"></action>
|
||||
<action android:name="android.net.conn.CONNECTIVITY_CHANGE"></action>
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
<provider android:name=".providers.PartProvider"
|
||||
android:authorities="org.thoughtcrime.provider.securesms" />
|
||||
|
@ -221,6 +221,9 @@
|
||||
<string name="MmsMessageRecord_bad_encrypted_mms_message">Bad encrypted MMS message...</string>
|
||||
<string name="MmsMessageRecord_mms_message_encrypted_for_non_existing_session">MMS message encrypted for non-existing session...</string>
|
||||
|
||||
<!-- MmsSender -->
|
||||
<string name="MmsSender_currently_unable_to_send_your_mms_message">Currently unable to send your MMS message. It will be sent once service becomes available.</string>
|
||||
|
||||
<!-- ApplicationMigrationService -->
|
||||
<string name="ApplicationMigrationService_migrating">Migrating</string>
|
||||
<string name="ApplicationMigrationService_migrating_system_text_messages">Migrating System Text Messages</string>
|
||||
@ -236,7 +239,12 @@
|
||||
<string name="MessageNotifier_encrypted_message">Encrypted message...</string>
|
||||
<string name="MessageNotifier_corrupted_ciphertext">Corrupted ciphertext</string>
|
||||
<string name="MessageNotifier_no_subject">(No Subject)</string>
|
||||
<string name="MessageNotifier_message_delivery_failed">Message delivery failed.</string>
|
||||
<string name="MessageNotifier_failed_to_deliver_message">Failed to deliver message.</string>
|
||||
<string name="MessageNotifier_error_delivering_message">Error delivering message.</string>
|
||||
|
||||
<!-- SmsReceiver -->
|
||||
<string name="SmsReceiver_currently_unable_to_send_your_sms_message">Currently unable to send your SMS message. It will be sent once service becomes available.</string>
|
||||
|
||||
<!-- auto_initiate_activity -->
|
||||
<string name="auto_initiate_activity__you_have_received_a_message_from_someone_who_supports_textsecure_encrypted_sessions_would_you_like_to_initiate_a_secure_session">You have received a message from someone who supports TextSecure encrypted sessions. Would you like to initiate a secure session?</string>
|
||||
|
@ -24,6 +24,7 @@ import android.database.sqlite.SQLiteOpenHelper;
|
||||
import android.util.Log;
|
||||
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientFactory;
|
||||
import org.thoughtcrime.securesms.recipients.Recipients;
|
||||
|
||||
import java.util.Arrays;
|
||||
@ -313,6 +314,25 @@ public class ThreadDatabase extends Database {
|
||||
}
|
||||
}
|
||||
|
||||
public Recipients getRecipientsForThreadId(Context context, long threadId) {
|
||||
SQLiteDatabase db = databaseHelper.getReadableDatabase();
|
||||
Cursor cursor = null;
|
||||
|
||||
try {
|
||||
cursor = db.query(TABLE_NAME, null, ID + " = ?", new String[] {threadId+""}, null, null, null);
|
||||
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
String recipientIds = cursor.getString(cursor.getColumnIndexOrThrow(RECIPIENT_IDS));
|
||||
return RecipientFactory.getRecipientsForIds(context, recipientIds, false);
|
||||
}
|
||||
} finally {
|
||||
if (cursor != null)
|
||||
cursor.close();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public void update(long threadId) {
|
||||
MmsSmsDatabase mmsSmsDatabase = DatabaseFactory.getMmsSmsDatabase(context);
|
||||
long count = mmsSmsDatabase.getConversationCount(threadId);
|
||||
|
@ -39,6 +39,7 @@ import android.util.Log;
|
||||
import org.thoughtcrime.securesms.ApplicationPreferencesActivity;
|
||||
import org.thoughtcrime.securesms.ConversationListActivity;
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.contacts.ContactPhotoFactory;
|
||||
import org.thoughtcrime.securesms.crypto.MasterCipher;
|
||||
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
||||
import org.thoughtcrime.securesms.crypto.MessageDisplayHelper;
|
||||
@ -74,6 +75,33 @@ public class MessageNotifier {
|
||||
visibleThread = threadId;
|
||||
}
|
||||
|
||||
public static void notifyMessageDeliveryFailed(Context context, Recipients recipients, long threadId) {
|
||||
if (visibleThread == threadId) {
|
||||
sendInThreadNotification(context);
|
||||
} else {
|
||||
Intent intent = new Intent(context, ConversationListActivity.class);
|
||||
intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
|
||||
intent.putExtra("recipients", recipients);
|
||||
intent.putExtra("thread_id", threadId);
|
||||
intent.setData((Uri.parse("custom://"+System.currentTimeMillis())));
|
||||
|
||||
NotificationCompat.Builder builder = new NotificationCompat.Builder(context);
|
||||
builder.setSmallIcon(R.drawable.icon_notification);
|
||||
builder.setLargeIcon(BitmapFactory.decodeResource(context.getResources(),
|
||||
R.drawable.ic_list_alert_sms_failed));
|
||||
builder.setContentTitle(context.getString(R.string.MessageNotifier_message_delivery_failed));
|
||||
builder.setContentText(context.getString(R.string.MessageNotifier_failed_to_deliver_message));
|
||||
builder.setTicker(context.getString(R.string.MessageNotifier_error_delivering_message));
|
||||
builder.setContentIntent(PendingIntent.getActivity(context, 0, intent, 0));
|
||||
builder.setAutoCancel(true);
|
||||
setNotificationAlarms(context, builder, true);
|
||||
|
||||
((NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE))
|
||||
.notify((int)threadId, builder.build());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static void updateNotification(Context context, MasterSecret masterSecret) {
|
||||
updateNotification(context, masterSecret, false);
|
||||
}
|
||||
@ -286,7 +314,9 @@ public class MessageNotifier {
|
||||
return getMmsRecipient(context, cursor);
|
||||
}
|
||||
} catch (RecipientFormattingException e) {
|
||||
return new Recipients(new Recipient("Unknown", null, null));
|
||||
Log.w("MessageNotifier", e);
|
||||
return new Recipients(new Recipient("Unknown", "Unknown", null,
|
||||
ContactPhotoFactory.getDefaultContactPhoto(context)));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -18,17 +18,21 @@ package org.thoughtcrime.securesms.service;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Handler;
|
||||
import android.telephony.TelephonyManager;
|
||||
import android.util.Log;
|
||||
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
||||
import org.thoughtcrime.securesms.crypto.SessionCipher;
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||
import org.thoughtcrime.securesms.database.MmsDatabase;
|
||||
import org.thoughtcrime.securesms.mms.MmsSendHelper;
|
||||
import org.thoughtcrime.securesms.mms.TextTransport;
|
||||
import org.thoughtcrime.securesms.notifications.MessageNotifier;
|
||||
import org.thoughtcrime.securesms.protocol.WirePrefix;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.Recipients;
|
||||
import org.thoughtcrime.securesms.util.Hex;
|
||||
|
||||
import ws.com.google.android.mms.ContentType;
|
||||
@ -49,9 +53,11 @@ import java.util.LinkedList;
|
||||
public class MmsSender extends MmscProcessor {
|
||||
|
||||
private final LinkedList<SendReq[]> pendingMessages = new LinkedList<SendReq[]>();
|
||||
private final Handler toastHandler;
|
||||
|
||||
public MmsSender(Context context) {
|
||||
public MmsSender(Context context, Handler toastHandler) {
|
||||
super(context);
|
||||
this.toastHandler = toastHandler;
|
||||
}
|
||||
|
||||
public void process(MasterSecret masterSecret, Intent intent) {
|
||||
@ -69,8 +75,8 @@ public class MmsSender extends MmscProcessor {
|
||||
sendRequests[0] = database.getSendRequest(messageId);
|
||||
}
|
||||
|
||||
if (sendRequests.length > 0)
|
||||
handleSendMms(sendRequests);
|
||||
if (sendRequests != null && sendRequests.length > 0)
|
||||
handleSendMms(sendRequests, messageId != -1);
|
||||
|
||||
} catch (MmsException me) {
|
||||
Log.w("MmsSender", me);
|
||||
@ -90,10 +96,15 @@ public class MmsSender extends MmscProcessor {
|
||||
else finishConnectivity();
|
||||
}
|
||||
|
||||
private void handleSendMms(SendReq[] sendRequests) {
|
||||
private void handleSendMms(SendReq[] sendRequests, boolean targeted) {
|
||||
if (!isConnectivityPossible()) {
|
||||
for (int i=0;i<sendRequests.length;i++)
|
||||
DatabaseFactory.getMmsDatabase(context).markAsSentFailed(sendRequests[i].getDatabaseMessageId());
|
||||
if (targeted) {
|
||||
toastHandler
|
||||
.obtainMessage(0, context.getString(R.string.MmsSender_currently_unable_to_send_your_mms_message))
|
||||
.sendToTarget();
|
||||
}
|
||||
// for (int i=0;i<sendRequests.length;i++)
|
||||
// DatabaseFactory.getMmsDatabase(context).markAsSentFailed(sendRequests[i].getDatabaseMessageId());
|
||||
} else {
|
||||
pendingMessages.add(sendRequests);
|
||||
issueConnectivityRequest();
|
||||
@ -146,17 +157,23 @@ public class MmsSender extends MmscProcessor {
|
||||
Log.w("MmsSender", "Sent MMS part of content-type: " + new String(pdu.getBody().getPart(i).getContentType()));
|
||||
}
|
||||
|
||||
long threadId = DatabaseFactory.getMmsDatabase(context).getThreadIdForMessage(messageId);
|
||||
Recipients recipients = DatabaseFactory.getThreadDatabase(context).getRecipientsForThreadId(context, threadId);
|
||||
|
||||
if (conf == null) {
|
||||
db.markAsSentFailed(messageId);
|
||||
MessageNotifier.notifyMessageDeliveryFailed(context, recipients, threadId);
|
||||
Log.w("MmsSender", "No M-Send.conf received in response to send.");
|
||||
return;
|
||||
} else if (conf.getResponseStatus() != PduHeaders.RESPONSE_STATUS_OK) {
|
||||
Log.w("MmsSender", "Got bad response: " + conf.getResponseStatus());
|
||||
db.updateResponseStatus(messageId, conf.getResponseStatus());
|
||||
db.markAsSentFailed(messageId);
|
||||
MessageNotifier.notifyMessageDeliveryFailed(context, recipients, threadId);
|
||||
return;
|
||||
} else if (isInconsistentResponse(pdu, conf)) {
|
||||
db.markAsSentFailed(messageId);
|
||||
MessageNotifier.notifyMessageDeliveryFailed(context, recipients, threadId);
|
||||
Log.w("MmsSender", "Got a response for the wrong transaction?");
|
||||
return;
|
||||
} else {
|
||||
|
@ -131,10 +131,10 @@ public class SendReceiveService extends Service {
|
||||
}
|
||||
|
||||
private void initializeProcessors() {
|
||||
smsReceiver = new SmsReceiver(this);
|
||||
smsReceiver = new SmsReceiver(this, toastHandler);
|
||||
smsSender = new SmsSender(this);
|
||||
mmsReceiver = new MmsReceiver(this);
|
||||
mmsSender = new MmsSender(this);
|
||||
mmsSender = new MmsSender(this, toastHandler);
|
||||
mmsDownloader = new MmsDownloader(this, toastHandler);
|
||||
}
|
||||
|
||||
|
@ -21,10 +21,12 @@ import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.telephony.SmsManager;
|
||||
import android.telephony.SmsMessage;
|
||||
import android.util.Log;
|
||||
|
||||
import org.thoughtcrime.securesms.ApplicationPreferencesActivity;
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.crypto.DecryptingQueue;
|
||||
import org.thoughtcrime.securesms.crypto.InvalidKeyException;
|
||||
import org.thoughtcrime.securesms.crypto.InvalidVersionException;
|
||||
@ -37,6 +39,8 @@ import org.thoughtcrime.securesms.notifications.MessageNotifier;
|
||||
import org.thoughtcrime.securesms.protocol.Prefix;
|
||||
import org.thoughtcrime.securesms.protocol.WirePrefix;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.Recipients;
|
||||
import org.thoughtcrime.securesms.service.SendReceiveService.ToastHandler;
|
||||
import org.thoughtcrime.securesms.sms.MultipartMessageHandler;
|
||||
|
||||
public class SmsReceiver {
|
||||
@ -44,9 +48,11 @@ public class SmsReceiver {
|
||||
private MultipartMessageHandler multipartMessageHandler = new MultipartMessageHandler();
|
||||
|
||||
private final Context context;
|
||||
private final ToastHandler toastHandler;
|
||||
|
||||
public SmsReceiver(Context context) {
|
||||
this.context = context;
|
||||
public SmsReceiver(Context context, ToastHandler toastHandler) {
|
||||
this.context = context;
|
||||
this.toastHandler = toastHandler;
|
||||
}
|
||||
|
||||
private String assembleSecureMessageFragments(String sender, String messageBody) {
|
||||
@ -169,14 +175,24 @@ public class SmsReceiver {
|
||||
private void handleSentMessage(Intent intent) {
|
||||
long messageId = intent.getLongExtra("message_id", -1);
|
||||
long type = intent.getLongExtra("type", -1);
|
||||
int result = intent.getIntExtra("ResultCode", -31337);
|
||||
|
||||
Log.w("SMSReceiverService", "Intent resultcode: " + intent.getIntExtra("ResultCode", 42));
|
||||
Log.w("SMSReceiverService", "Intent resultcode: " + result);
|
||||
Log.w("SMSReceiverService", "Running sent callback: " + messageId + "," + type);
|
||||
|
||||
if (intent.getIntExtra("ResultCode", -31337) == Activity.RESULT_OK)
|
||||
if (result == Activity.RESULT_OK) {
|
||||
DatabaseFactory.getSmsDatabase(context).markAsSent(messageId, type);
|
||||
else
|
||||
} else if (result == SmsManager.RESULT_ERROR_NO_SERVICE || result == SmsManager.RESULT_ERROR_RADIO_OFF) {
|
||||
toastHandler
|
||||
.obtainMessage(0, context.getString(R.string.SmsReceiver_currently_unable_to_send_your_sms_message))
|
||||
.sendToTarget();
|
||||
} else {
|
||||
long threadId = DatabaseFactory.getSmsDatabase(context).getThreadIdForMessage(messageId);
|
||||
Recipients recipients = DatabaseFactory.getThreadDatabase(context).getRecipientsForThreadId(context, threadId);
|
||||
|
||||
DatabaseFactory.getSmsDatabase(context).markAsSentFailed(messageId);
|
||||
MessageNotifier.notifyMessageDeliveryFailed(context, recipients, threadId);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleDeliveredMessage(Intent intent) {
|
||||
|
@ -0,0 +1,57 @@
|
||||
package org.thoughtcrime.securesms.service;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.net.ConnectivityManager;
|
||||
import android.net.NetworkInfo;
|
||||
import android.telephony.ServiceState;
|
||||
|
||||
public class SystemStateListener extends BroadcastReceiver {
|
||||
|
||||
private static final String ACTION_SERVICE_STATE = "android.intent.action.SERVICE_STATE";
|
||||
private static final String ACTION_CONNECTIVITY_CHANGE = "android.net.conn.CONNECTIVITY_CHANGE";
|
||||
|
||||
private void sendSmsOutbox(Context context) {
|
||||
Intent smsSenderIntent = new Intent(SendReceiveService.SEND_SMS_ACTION, null, context,
|
||||
SendReceiveService.class);
|
||||
context.startService(smsSenderIntent);
|
||||
}
|
||||
|
||||
private void sendMmsOutbox(Context context) {
|
||||
Intent mmsSenderIntent = new Intent(SendReceiveService.SEND_MMS_ACTION, null, context,
|
||||
SendReceiveService.class);
|
||||
context.startService(mmsSenderIntent);
|
||||
}
|
||||
|
||||
private void handleRadioServiceStateChange(Context context, Intent intent) {
|
||||
int state = intent.getIntExtra("state", -31337);
|
||||
|
||||
if (state == ServiceState.STATE_IN_SERVICE) {
|
||||
sendSmsOutbox(context);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleDataServiceStateChange(Context context, Intent intent) {
|
||||
ConnectivityManager connectivityManager
|
||||
= (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||
|
||||
NetworkInfo networkInfo = connectivityManager.getNetworkInfo(MmscProcessor.TYPE_MOBILE_MMS);
|
||||
|
||||
if (networkInfo != null && networkInfo.isAvailable()) {
|
||||
sendMmsOutbox(context);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
if (intent == null) return;
|
||||
|
||||
if (intent.getAction().equals(ACTION_SERVICE_STATE)) {
|
||||
handleRadioServiceStateChange(context, intent);
|
||||
} else if (intent.getAction().equals(ACTION_CONNECTIVITY_CHANGE)) {
|
||||
handleDataServiceStateChange(context, intent);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user