diff --git a/src/org/thoughtcrime/securesms/MessageDetailsActivity.java b/src/org/thoughtcrime/securesms/MessageDetailsActivity.java index c187af3566..3de789d491 100644 --- a/src/org/thoughtcrime/securesms/MessageDetailsActivity.java +++ b/src/org/thoughtcrime/securesms/MessageDetailsActivity.java @@ -23,7 +23,6 @@ import android.content.Context; import android.database.Cursor; import android.graphics.drawable.ColorDrawable; import android.os.AsyncTask; -import android.os.Build; import android.os.Bundle; import android.support.annotation.NonNull; import android.support.annotation.Nullable; @@ -48,6 +47,7 @@ import org.thoughtcrime.securesms.database.SmsDatabase; import org.thoughtcrime.securesms.database.loaders.MessageDetailsLoader; import org.thoughtcrime.securesms.database.model.MessageRecord; import org.thoughtcrime.securesms.logging.Log; +import org.thoughtcrime.securesms.loki.LokiMessageDatabase; import org.thoughtcrime.securesms.mms.GlideApp; import org.thoughtcrime.securesms.mms.GlideRequests; import org.thoughtcrime.securesms.notifications.MessageNotifier; @@ -158,10 +158,6 @@ public class MessageDetailsActivity extends PassphraseRequiredActionBarActivity private void setActionBarColor(MaterialColor color) { assert getSupportActionBar() != null; getSupportActionBar().setBackgroundDrawable(new ColorDrawable(color.toActionBarColor(this))); - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - // getWindow().setStatusBarColor(color.toStatusBarColor(this)); - } } @Override @@ -403,6 +399,12 @@ public class MessageDetailsActivity extends PassphraseRequiredActionBarActivity boolean isGroupNetworkFailure = messageRecord.isFailed() && !messageRecord.getNetworkFailures().isEmpty(); boolean isIndividualNetworkFailure = messageRecord.isFailed() && !isPushGroup && messageRecord.getIdentityKeyMismatches().isEmpty(); + LokiMessageDatabase lokiMessageDatabase = DatabaseFactory.getLokiMessageDatabase(getContext()); + String errorMessage = lokiMessageDatabase.getErrorMessage(messageRecord.id); + if (errorMessage != null) { + errorText.setText(errorMessage); + } + if (isGroupNetworkFailure || isIndividualNetworkFailure) { errorText.setVisibility(View.VISIBLE); resendButton.setVisibility(View.VISIBLE); diff --git a/src/org/thoughtcrime/securesms/database/helpers/SQLCipherOpenHelper.java b/src/org/thoughtcrime/securesms/database/helpers/SQLCipherOpenHelper.java index 5d06fb1bc6..38ff02ee8a 100644 --- a/src/org/thoughtcrime/securesms/database/helpers/SQLCipherOpenHelper.java +++ b/src/org/thoughtcrime/securesms/database/helpers/SQLCipherOpenHelper.java @@ -80,8 +80,9 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper { private static final int lokiV4 = 25; private static final int lokiV5 = 26; private static final int lokiV6 = 27; + private static final int lokiV7 = 28; - private static final int DATABASE_VERSION = lokiV6; // Loki - onUpgrade(...) must be updated to use Loki version numbers if Signal makes any database changes + private static final int DATABASE_VERSION = lokiV7; // Loki - onUpgrade(...) must be updated to use Loki version numbers if Signal makes any database changes private static final String DATABASE_NAME = "signal.db"; private final Context context; @@ -141,6 +142,7 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper { db.execSQL(LokiPreKeyRecordDatabase.getCreateTableCommand()); db.execSQL(LokiMessageDatabase.getCreateMessageFriendRequestTableCommand()); db.execSQL(LokiMessageDatabase.getCreateMessageToThreadMappingTableCommand()); + db.execSQL(LokiMessageDatabase.getCreateErrorMessageTableCommand()); db.execSQL(LokiThreadDatabase.getCreateFriendRequestTableCommand()); db.execSQL(LokiThreadDatabase.getCreateSessionResetTableCommand()); db.execSQL(LokiThreadDatabase.getCreatePublicChatTableCommand()); @@ -570,6 +572,10 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper { db.execSQL("ALTER TABLE groups ADD COLUMN admins TEXT"); } + if (oldVersion < lokiV7) { + db.execSQL(LokiMessageDatabase.getCreateErrorMessageTableCommand()); + } + db.setTransactionSuccessful(); } finally { db.endTransaction(); diff --git a/src/org/thoughtcrime/securesms/jobs/PushTextSendJob.java b/src/org/thoughtcrime/securesms/jobs/PushTextSendJob.java index 7c0f04834a..3c6e10f346 100644 --- a/src/org/thoughtcrime/securesms/jobs/PushTextSendJob.java +++ b/src/org/thoughtcrime/securesms/jobs/PushTextSendJob.java @@ -1,6 +1,7 @@ package org.thoughtcrime.securesms.jobs; import android.support.annotation.NonNull; +import android.util.Log; import org.thoughtcrime.securesms.ApplicationContext; import org.thoughtcrime.securesms.crypto.UnidentifiedAccessUtil; @@ -14,6 +15,7 @@ import org.thoughtcrime.securesms.database.model.SmsMessageRecord; import org.thoughtcrime.securesms.dependencies.InjectableType; import org.thoughtcrime.securesms.jobmanager.Data; import org.thoughtcrime.securesms.jobmanager.Job; +import org.thoughtcrime.securesms.loki.LokiMessageDatabase; import org.thoughtcrime.securesms.notifications.MessageNotifier; import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.service.ExpiringMessageManager; @@ -25,11 +27,15 @@ import org.whispersystems.libsignal.util.guava.Optional; import org.whispersystems.signalservice.api.SignalServiceMessageSender; import org.whispersystems.signalservice.api.crypto.UnidentifiedAccessPair; import org.whispersystems.signalservice.api.crypto.UntrustedIdentityException; +import org.whispersystems.signalservice.api.messages.SendMessageResult; import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage; import org.whispersystems.signalservice.api.messages.multidevice.SignalServiceSyncMessage; import org.whispersystems.signalservice.api.push.SignalServiceAddress; import org.whispersystems.signalservice.api.push.exceptions.UnregisteredUserException; +import org.whispersystems.signalservice.loki.api.LokiAPI; import org.whispersystems.signalservice.loki.api.LokiDeviceLinkUtilities; +import org.whispersystems.signalservice.loki.api.LokiDotNetAPI; +import org.whispersystems.signalservice.loki.api.LokiSnodeProxy; import org.whispersystems.signalservice.loki.messaging.LokiSyncMessage; import org.whispersystems.signalservice.loki.utilities.PromiseUtil; @@ -116,6 +122,8 @@ public class PushTextSendJob extends PushSendJob implements InjectableType { return; } + LokiMessageDatabase lokiMessageDatabase = DatabaseFactory.getLokiMessageDatabase(context); + try { log(TAG, "Sending message: " + templateMessageId + (hasSameDestination ? "" : "to another device.")); @@ -170,6 +178,21 @@ public class PushTextSendJob extends PushSendJob implements InjectableType { database.markAsSentFailed(record.getId()); database.markAsPush(record.getId()); } + } catch (LokiAPI.Error e) { + Log.d("Loki", "Couldn't send message due to error: " + e.getDescription()); + if (messageId < 0) { return; } + lokiMessageDatabase.setErrorMessage(record.getId(), e.getDescription()); + database.markAsSentFailed(record.getId()); + } catch (LokiDotNetAPI.Error e) { + Log.d("Loki", "Couldn't send message due to error: " + e.getDescription()); + if (messageId < 0) { return; } + lokiMessageDatabase.setErrorMessage(record.getId(), e.getDescription()); + database.markAsSentFailed(record.getId()); + } catch (LokiSnodeProxy.Error e) { + Log.d("Loki", "Couldn't send message due to error: " + e.getDescription()); + if (messageId < 0) { return; } + lokiMessageDatabase.setErrorMessage(record.getId(), e.getDescription()); + database.markAsSentFailed(record.getId()); } } @@ -196,7 +219,7 @@ public class PushTextSendJob extends PushSendJob implements InjectableType { } private boolean deliver(SmsMessageRecord message) - throws UntrustedIdentityException, InsecureFallbackApprovalException, RetryLaterException + throws UntrustedIdentityException, InsecureFallbackApprovalException, RetryLaterException, LokiAPI.Error, LokiDotNetAPI.Error, LokiSnodeProxy.Error { try { // rotateSenderCertificateIfNecessary(); @@ -241,7 +264,21 @@ public class PushTextSendJob extends PushSendJob implements InjectableType { // We also need to use the original message ID and not -1 syncMessage = new LokiSyncMessage(masterAddress, templateMessageId); } - return messageSender.sendMessage(messageId, address, unidentifiedAccess, textSecureMessage, Optional.fromNullable(syncMessage)).getSuccess().isUnidentified(); + SendMessageResult result = messageSender.sendMessage(messageId, address, unidentifiedAccess, textSecureMessage, Optional.fromNullable(syncMessage)); + if (result.getException() != null) { + Throwable exception = result.getException(); + if (exception instanceof LokiAPI.Error) { + throw (LokiAPI.Error) exception; + } else if (exception instanceof LokiDotNetAPI.Error) { + throw (LokiDotNetAPI.Error) exception; + } else if (exception instanceof LokiSnodeProxy.Error) { + throw (LokiSnodeProxy.Error) exception; + } else { + return result.getSuccess().isUnidentified(); + } + } else { + return result.getSuccess().isUnidentified(); + } } } catch (UnregisteredUserException e) { warn(TAG, "Failure", e); diff --git a/src/org/thoughtcrime/securesms/loki/LokiMessageDatabase.kt b/src/org/thoughtcrime/securesms/loki/LokiMessageDatabase.kt index 1c98d62612..7195e4a2ee 100644 --- a/src/org/thoughtcrime/securesms/loki/LokiMessageDatabase.kt +++ b/src/org/thoughtcrime/securesms/loki/LokiMessageDatabase.kt @@ -8,6 +8,7 @@ import org.thoughtcrime.securesms.database.DatabaseFactory import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper import org.thoughtcrime.securesms.loki.redesign.utilities.get import org.thoughtcrime.securesms.loki.redesign.utilities.getInt +import org.thoughtcrime.securesms.loki.redesign.utilities.getString import org.thoughtcrime.securesms.loki.redesign.utilities.insertOrUpdate import org.whispersystems.signalservice.loki.messaging.LokiMessageDatabaseProtocol import org.whispersystems.signalservice.loki.messaging.LokiMessageFriendRequestStatus @@ -17,12 +18,15 @@ class LokiMessageDatabase(context: Context, helper: SQLCipherOpenHelper) : Datab companion object { private val messageFriendRequestTableName = "loki_message_friend_request_database" private val messageThreadMappingTableName = "loki_message_thread_mapping_database" + private val errorMessageTableName = "loki_error_message_database" private val messageID = "message_id" private val serverID = "server_id" private val friendRequestStatus = "friend_request_status" private val threadID = "thread_id" + private val errorMessage = "error_message" @JvmStatic val createMessageFriendRequestTableCommand = "CREATE TABLE $messageFriendRequestTableName ($messageID INTEGER PRIMARY KEY, $serverID INTEGER DEFAULT 0, $friendRequestStatus INTEGER DEFAULT 0);" @JvmStatic val createMessageToThreadMappingTableCommand = "CREATE TABLE IF NOT EXISTS $messageThreadMappingTableName ($messageID INTEGER PRIMARY KEY, $threadID INTEGER);" + @JvmStatic val createErrorMessageTableCommand = "CREATE TABLE IF NOT EXISTS $errorMessageTableName ($messageID INTEGER PRIMARY KEY, $errorMessage STRING);" } override fun getQuoteServerID(quoteID: Long, quoteeHexEncodedPublicKey: String): Long? { @@ -92,4 +96,19 @@ class LokiMessageDatabase(context: Context, helper: SQLCipherOpenHelper) : Datab fun isFriendRequest(messageID: Long): Boolean { return getFriendRequestStatus(messageID) != LokiMessageFriendRequestStatus.NONE } + + fun getErrorMessage(messageID: Long): String? { + val database = databaseHelper.readableDatabase + return database.get(errorMessageTableName, "${Companion.messageID} = ?", arrayOf( messageID.toString() )) { cursor -> + cursor.getString(errorMessage) + } + } + + fun setErrorMessage(messageID: Long, errorMessage: String) { + val database = databaseHelper.writableDatabase + val contentValues = ContentValues(2) + contentValues.put(Companion.messageID, messageID) + contentValues.put(Companion.errorMessage, errorMessage) + database.insertOrUpdate(errorMessageTableName, contentValues, "${Companion.messageID} = ?", arrayOf( messageID.toString() )) + } } \ No newline at end of file