mirror of
https://github.com/oxen-io/session-android.git
synced 2024-11-23 18:15:22 +00:00
Support for read receipts
// FREEBIE
This commit is contained in:
parent
65124fd1f2
commit
cb9bc9659b
@ -63,7 +63,7 @@ dependencies {
|
||||
|
||||
compile 'org.whispersystems:jobmanager:1.0.2'
|
||||
compile 'org.whispersystems:libpastelog:1.0.7'
|
||||
compile 'org.whispersystems:signal-service-android:2.6.5'
|
||||
compile 'org.whispersystems:signal-service-android:2.6.6'
|
||||
compile 'org.whispersystems:webrtc-android:M59-S1'
|
||||
|
||||
compile "me.leolin:ShortcutBadger:1.1.16"
|
||||
@ -138,7 +138,7 @@ dependencyVerification {
|
||||
'com.google.android.exoplayer:exoplayer:955085aa611a8f7cf6c61b88ae03d1a392f4ad94c9bfbc153f3dedb9ffb14718',
|
||||
'org.whispersystems:jobmanager:506f679fc2fcf7bb6d10f00f41d6f6ea0abf75c70dc95b913398661ad538a181',
|
||||
'org.whispersystems:libpastelog:bb331d9a98240fc139101128ba836c1edec3c40e000597cdbb29ebf4cbf34d88',
|
||||
'org.whispersystems:signal-service-android:690e04d53c8b5ec8cda064b242d7c00b0e5321851b811798dd0ec3712f5e1a85',
|
||||
'org.whispersystems:signal-service-android:731fc8c45f38f42b2d0da1053cf32adcd175708e0c126571150690637108971a',
|
||||
'org.whispersystems:webrtc-android:de647643afbbea45a26a4f24db75aa10bc8de45426e8eb0d9d563cc10af4f582',
|
||||
'me.leolin:ShortcutBadger:e3cb3e7625892129b0c92dd5e4bc649faffdd526d5af26d9c45ee31ff8851774',
|
||||
'se.emilsjolander:stickylistheaders:a08ca948aa6b220f09d82f16bbbac395f6b78897e9eeac6a9f0b0ba755928eeb',
|
||||
@ -173,7 +173,7 @@ dependencyVerification {
|
||||
'com.google.android.gms:play-services-basement:95dd882c5ffba15b9a99de3fefb05d3a01946623af67454ca00055d222f85a8d',
|
||||
'com.google.android.gms:play-services-iid:54e919f9957b8b7820da7ee9b83471d00d0cac1cf08ddea8b5b41aea80bb1a70',
|
||||
'org.whispersystems:signal-protocol-android:5b8acded7f2a40178eb90ab8e8cbfec89d170d91b3ff5e78487d1098df6185a1',
|
||||
'org.whispersystems:signal-service-java:438e8330cf806152e7e226d8241dd6388ee4005f0ea7d2aaa99d7ef514012dca',
|
||||
'org.whispersystems:signal-service-java:90aadf941cc31cb0f5af9e1adffa248556f1cfc56a62c141bc62812e7bf3ed52',
|
||||
'com.nineoldandroids:library:68025a14e3e7673d6ad2f95e4b46d78d7d068343aa99256b686fe59de1b3163a',
|
||||
'javax.inject:javax.inject:91c77044a50c481636c32d916fd89c9118a72195390452c81065080f957de7ff',
|
||||
'com.klinkerapps:logger:177e325259a8b111ad6745ec10db5861723c99f402222b80629f576f49408541',
|
||||
|
@ -27,6 +27,18 @@
|
||||
android:paddingBottom="2dp"
|
||||
android:visibility="gone"
|
||||
android:contentDescription="@string/conversation_item_sent__delivered_description"
|
||||
tools:visibility="gone"/>
|
||||
|
||||
<ImageView android:id="@+id/read_indicator"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical|end"
|
||||
android:src="@drawable/ic_done_all_white_18dp"
|
||||
android:paddingLeft="2dp"
|
||||
android:paddingBottom="2dp"
|
||||
android:visibility="gone"
|
||||
android:contentDescription="@string/conversation_item_sent__message_read"
|
||||
android:tint="@color/blue_800"
|
||||
tools:visibility="visible"/>
|
||||
|
||||
</merge>
|
@ -1456,7 +1456,9 @@
|
||||
|
||||
<!-- transport_selection_list_item -->
|
||||
<string name="transport_selection_list_item__transport_icon">Transport icon</string>
|
||||
|
||||
<string name="conversation_item_sent__message_read">Message read</string>
|
||||
<string name="preferences__read_receipts">Read receipts</string>
|
||||
<string name="preferences__if_read_receipts_are_disabled_you_wont_be_able_to_see_read_receipts">If you read receipts are disabled, you won\'t be able to see read receipts from others.</string>
|
||||
|
||||
|
||||
<!-- EOF -->
|
||||
|
@ -40,6 +40,12 @@
|
||||
android:title="@string/preferences_advanced__always_relay_calls"
|
||||
android:summary="@string/preferences_advanced__relay_all_calls_through_the_signal_server_to_avoid_revealing_your_ip_address"/>
|
||||
|
||||
<org.thoughtcrime.securesms.components.SwitchPreferenceCompat
|
||||
android:defaultValue="false"
|
||||
android:key="pref_read_receipts"
|
||||
android:title="@string/preferences__read_receipts"
|
||||
android:summary="@string/preferences__if_read_receipts_are_disabled_you_wont_be_able_to_see_read_receipts"/>
|
||||
|
||||
<Preference android:key="preference_category_blocked"
|
||||
android:title="@string/preferences_app_protection__blocked_contacts" />
|
||||
</PreferenceCategory>
|
||||
|
@ -445,6 +445,7 @@ public class ConversationItem extends LinearLayout
|
||||
|
||||
if (!messageRecord.isOutgoing()) deliveryStatusIndicator.setNone();
|
||||
else if (messageRecord.isPending()) deliveryStatusIndicator.setPending();
|
||||
else if (messageRecord.isRemoteRead()) deliveryStatusIndicator.setRead();
|
||||
else if (messageRecord.isDelivered()) deliveryStatusIndicator.setDelivered();
|
||||
else deliveryStatusIndicator.setSent();
|
||||
}
|
||||
|
@ -215,6 +215,7 @@ public class ConversationListItem extends RelativeLayout
|
||||
alertView.setNone();
|
||||
|
||||
if (thread.isPending()) deliveryStatusIndicator.setPending();
|
||||
else if (thread.isRemoteRead()) deliveryStatusIndicator.setRead();
|
||||
else if (thread.isDelivered()) deliveryStatusIndicator.setDelivered();
|
||||
else deliveryStatusIndicator.setSent();
|
||||
}
|
||||
|
@ -68,6 +68,7 @@ public class PassphraseCreateActivity extends PassphraseActivity {
|
||||
VersionTracker.updateLastSeenVersion(PassphraseCreateActivity.this);
|
||||
TextSecurePreferences.setLastExperienceVersionCode(PassphraseCreateActivity.this, Util.getCurrentApkReleaseVersion(PassphraseCreateActivity.this));
|
||||
TextSecurePreferences.setPasswordDisabled(PassphraseCreateActivity.this, true);
|
||||
TextSecurePreferences.setReadReceiptsEnabled(PassphraseCreateActivity.this, true);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
@ -22,6 +22,7 @@ public class DeliveryStatusView extends FrameLayout {
|
||||
private final ViewGroup pendingIndicatorStub;
|
||||
private final ImageView sentIndicator;
|
||||
private final ImageView deliveredIndicator;
|
||||
private final ImageView readIndicator;
|
||||
|
||||
public DeliveryStatusView(Context context) {
|
||||
this(context, null);
|
||||
@ -39,6 +40,7 @@ public class DeliveryStatusView extends FrameLayout {
|
||||
this.deliveredIndicator = (ImageView) findViewById(R.id.delivered_indicator);
|
||||
this.sentIndicator = (ImageView) findViewById(R.id.sent_indicator);
|
||||
this.pendingIndicatorStub = (ViewGroup) findViewById(R.id.pending_indicator_stub);
|
||||
this.readIndicator = (ImageView) findViewById(R.id.read_indicator);
|
||||
|
||||
int iconColor = Color.GRAY;
|
||||
|
||||
@ -71,6 +73,7 @@ public class DeliveryStatusView extends FrameLayout {
|
||||
pendingIndicatorStub.setVisibility(View.VISIBLE);
|
||||
sentIndicator.setVisibility(View.GONE);
|
||||
deliveredIndicator.setVisibility(View.GONE);
|
||||
readIndicator.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
public void setSent() {
|
||||
@ -78,6 +81,7 @@ public class DeliveryStatusView extends FrameLayout {
|
||||
pendingIndicatorStub.setVisibility(View.GONE);
|
||||
sentIndicator.setVisibility(View.VISIBLE);
|
||||
deliveredIndicator.setVisibility(View.GONE);
|
||||
readIndicator.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
public void setDelivered() {
|
||||
@ -85,5 +89,14 @@ public class DeliveryStatusView extends FrameLayout {
|
||||
pendingIndicatorStub.setVisibility(View.GONE);
|
||||
sentIndicator.setVisibility(View.GONE);
|
||||
deliveredIndicator.setVisibility(View.VISIBLE);
|
||||
readIndicator.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
public void setRead() {
|
||||
this.setVisibility(View.VISIBLE);
|
||||
pendingIndicatorStub.setVisibility(View.GONE);
|
||||
sentIndicator.setVisibility(View.GONE);
|
||||
deliveredIndicator.setVisibility(View.GONE);
|
||||
readIndicator.setVisibility(View.VISIBLE);
|
||||
}
|
||||
}
|
||||
|
@ -106,7 +106,8 @@ public class DatabaseFactory {
|
||||
private static final int PROFILES = 41;
|
||||
private static final int PROFILE_SHARING_APPROVAL = 42;
|
||||
private static final int UNSEEN_NUMBER_OFFER = 43;
|
||||
private static final int DATABASE_VERSION = 43;
|
||||
private static final int READ_RECEIPTS = 44;
|
||||
private static final int DATABASE_VERSION = 44;
|
||||
|
||||
private static final String DATABASE_NAME = "messages.db";
|
||||
private static final Object lock = new Object();
|
||||
@ -1321,6 +1322,12 @@ public class DatabaseFactory {
|
||||
db.execSQL("ALTER TABLE thread ADD COLUMN has_sent INTEGER DEFAULT 0");
|
||||
}
|
||||
|
||||
if (oldVersion < READ_RECEIPTS) {
|
||||
db.execSQL("ALTER TABLE sms ADD COLUMN read_receipt_count INTEGER DEFAULT 0");
|
||||
db.execSQL("ATLER TABLE mms ADD COLUMN read_receipt_count INTEGER DEFAULT 0");
|
||||
db.execSQL("ALTER TABLE thread ADD COLUMN read_receipt_count INTEGER DEFAULT 0");
|
||||
}
|
||||
|
||||
db.setTransactionSuccessful();
|
||||
db.endTransaction();
|
||||
}
|
||||
|
@ -59,6 +59,7 @@ import org.thoughtcrime.securesms.mms.SlideDeck;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientFormattingException;
|
||||
import org.thoughtcrime.securesms.util.JsonUtils;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
import org.whispersystems.jobqueue.JobManager;
|
||||
import org.whispersystems.libsignal.InvalidMessageException;
|
||||
@ -101,10 +102,11 @@ public class MmsDatabase extends MessagingDatabase {
|
||||
STATUS + " INTEGER, " + TRANSACTION_ID + " TEXT, " + "retr_st" + " INTEGER, " +
|
||||
"retr_txt" + " TEXT, " + "retr_txt_cs" + " INTEGER, " + "read_status" + " INTEGER, " +
|
||||
"ct_cls" + " INTEGER, " + "resp_txt" + " TEXT, " + "d_tm" + " INTEGER, " +
|
||||
RECEIPT_COUNT + " INTEGER DEFAULT 0, " + MISMATCHED_IDENTITIES + " TEXT DEFAULT NULL, " +
|
||||
DELIVERY_RECEIPT_COUNT + " INTEGER DEFAULT 0, " + MISMATCHED_IDENTITIES + " TEXT DEFAULT NULL, " +
|
||||
NETWORK_FAILURE + " TEXT DEFAULT NULL," + "d_rpt" + " INTEGER, " +
|
||||
SUBSCRIPTION_ID + " INTEGER DEFAULT -1, " + EXPIRES_IN + " INTEGER DEFAULT 0, " +
|
||||
EXPIRE_STARTED + " INTEGER DEFAULT 0, " + NOTIFIED + " INTEGER DEFAULT 0);";
|
||||
EXPIRE_STARTED + " INTEGER DEFAULT 0, " + NOTIFIED + " INTEGER DEFAULT 0, " +
|
||||
READ_RECEIPT_COUNT + " INTEGER DEFAULT 0);";
|
||||
|
||||
public static final String[] CREATE_INDEXS = {
|
||||
"CREATE INDEX IF NOT EXISTS mms_thread_id_index ON " + TABLE_NAME + " (" + THREAD_ID + ");",
|
||||
@ -123,7 +125,7 @@ public class MmsDatabase extends MessagingDatabase {
|
||||
CONTENT_LOCATION, EXPIRY, MESSAGE_TYPE,
|
||||
MESSAGE_SIZE, STATUS, TRANSACTION_ID,
|
||||
BODY, PART_COUNT, ADDRESS, ADDRESS_DEVICE_ID,
|
||||
RECEIPT_COUNT, MISMATCHED_IDENTITIES, NETWORK_FAILURE, SUBSCRIPTION_ID,
|
||||
DELIVERY_RECEIPT_COUNT, MISMATCHED_IDENTITIES, NETWORK_FAILURE, SUBSCRIPTION_ID,
|
||||
EXPIRES_IN, EXPIRE_STARTED, NOTIFIED,
|
||||
AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.ROW_ID + " AS " + AttachmentDatabase.ATTACHMENT_ID_ALIAS,
|
||||
AttachmentDatabase.UNIQUE_ID,
|
||||
@ -144,7 +146,9 @@ public class MmsDatabase extends MessagingDatabase {
|
||||
|
||||
private static final String RAW_ID_WHERE = TABLE_NAME + "._id = ?";
|
||||
|
||||
private final EarlyReceiptCache earlyReceiptCache = new EarlyReceiptCache();
|
||||
private final EarlyReceiptCache earlyDeliveryReceiptCache = new EarlyReceiptCache();
|
||||
private final EarlyReceiptCache earlyReadReceiptCache = new EarlyReceiptCache();
|
||||
|
||||
private final JobManager jobManager;
|
||||
|
||||
public MmsDatabase(Context context, SQLiteOpenHelper databaseHelper) {
|
||||
@ -190,7 +194,7 @@ public class MmsDatabase extends MessagingDatabase {
|
||||
}
|
||||
}
|
||||
|
||||
public void incrementDeliveryReceiptCount(SyncMessageId messageId) {
|
||||
public void incrementReceiptCount(SyncMessageId messageId, boolean deliveryReceipt, boolean readReceipt) {
|
||||
SQLiteDatabase database = databaseHelper.getWritableDatabase();
|
||||
Cursor cursor = null;
|
||||
boolean found = false;
|
||||
@ -202,6 +206,7 @@ public class MmsDatabase extends MessagingDatabase {
|
||||
if (Types.isOutgoingMessageType(cursor.getLong(cursor.getColumnIndexOrThrow(MESSAGE_BOX)))) {
|
||||
Address theirAddress = Address.fromSerialized(cursor.getString(cursor.getColumnIndexOrThrow(ADDRESS)));
|
||||
Address ourAddress = messageId.getAddress();
|
||||
String columnName = deliveryReceipt ? DELIVERY_RECEIPT_COUNT : READ_RECEIPT_COUNT;
|
||||
|
||||
if (ourAddress.equals(theirAddress) || theirAddress.isGroup()) {
|
||||
long id = cursor.getLong(cursor.getColumnIndexOrThrow(ID));
|
||||
@ -210,7 +215,7 @@ public class MmsDatabase extends MessagingDatabase {
|
||||
found = true;
|
||||
|
||||
database.execSQL("UPDATE " + TABLE_NAME + " SET " +
|
||||
RECEIPT_COUNT + " = " + RECEIPT_COUNT + " + 1 WHERE " + ID + " = ?",
|
||||
columnName + " = " + columnName + " + 1 WHERE " + ID + " = ?",
|
||||
new String[] {String.valueOf(id)});
|
||||
|
||||
DatabaseFactory.getThreadDatabase(context).update(threadId, false);
|
||||
@ -220,7 +225,8 @@ public class MmsDatabase extends MessagingDatabase {
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
earlyReceiptCache.increment(messageId.getTimetamp(), messageId.getAddress());
|
||||
if (deliveryReceipt) earlyDeliveryReceiptCache.increment(messageId.getTimetamp(), messageId.getAddress());
|
||||
if (readReceipt) earlyReadReceiptCache.increment(messageId.getTimetamp(), messageId.getAddress());
|
||||
}
|
||||
} finally {
|
||||
if (cursor != null)
|
||||
@ -803,7 +809,8 @@ public class MmsDatabase extends MessagingDatabase {
|
||||
contentValues.put(SUBSCRIPTION_ID, message.getSubscriptionId());
|
||||
contentValues.put(EXPIRES_IN, message.getExpiresIn());
|
||||
contentValues.put(ADDRESS, message.getRecipient().getAddress().serialize());
|
||||
contentValues.put(RECEIPT_COUNT, earlyReceiptCache.remove(message.getSentTimeMillis(), message.getRecipient().getAddress()));
|
||||
contentValues.put(DELIVERY_RECEIPT_COUNT, earlyDeliveryReceiptCache.remove(message.getSentTimeMillis(), message.getRecipient().getAddress()));
|
||||
contentValues.put(READ_RECEIPT_COUNT, earlyReadReceiptCache.remove(message.getSentTimeMillis(), message.getRecipient().getAddress()));
|
||||
|
||||
long messageId = insertMediaMessage(masterSecret, message.getBody(), message.getAttachments(), contentValues, insertListener);
|
||||
|
||||
@ -1060,7 +1067,7 @@ public class MmsDatabase extends MessagingDatabase {
|
||||
new LinkedList<NetworkFailure>(),
|
||||
message.getSubscriptionId(),
|
||||
message.getExpiresIn(),
|
||||
System.currentTimeMillis());
|
||||
System.currentTimeMillis(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1110,9 +1117,14 @@ public class MmsDatabase extends MessagingDatabase {
|
||||
long messageSize = cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.MESSAGE_SIZE));
|
||||
long expiry = cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.EXPIRY));
|
||||
int status = cursor.getInt(cursor.getColumnIndexOrThrow(MmsDatabase.STATUS));
|
||||
int receiptCount = cursor.getInt(cursor.getColumnIndexOrThrow(MmsDatabase.RECEIPT_COUNT));
|
||||
int deliveryReceiptCount = cursor.getInt(cursor.getColumnIndexOrThrow(MmsDatabase.DELIVERY_RECEIPT_COUNT));
|
||||
int readReceiptCount = cursor.getInt(cursor.getColumnIndexOrThrow(MmsDatabase.READ_RECEIPT_COUNT));
|
||||
int subscriptionId = cursor.getInt(cursor.getColumnIndexOrThrow(MmsDatabase.SUBSCRIPTION_ID));
|
||||
|
||||
if (!TextSecurePreferences.isReadReceiptsEnabled(context)) {
|
||||
readReceiptCount = 0;
|
||||
}
|
||||
|
||||
byte[]contentLocationBytes = null;
|
||||
byte[]transactionIdBytes = null;
|
||||
|
||||
@ -1126,9 +1138,10 @@ public class MmsDatabase extends MessagingDatabase {
|
||||
|
||||
|
||||
return new NotificationMmsMessageRecord(context, id, recipient, recipient,
|
||||
addressDeviceId, dateSent, dateReceived, receiptCount, threadId,
|
||||
addressDeviceId, dateSent, dateReceived, deliveryReceiptCount, threadId,
|
||||
contentLocationBytes, messageSize, expiry, status,
|
||||
transactionIdBytes, mailbox, subscriptionId, slideDeck);
|
||||
transactionIdBytes, mailbox, subscriptionId, slideDeck,
|
||||
readReceiptCount);
|
||||
}
|
||||
|
||||
private MediaMmsMessageRecord getMediaMmsMessageRecord(Cursor cursor) {
|
||||
@ -1139,7 +1152,8 @@ public class MmsDatabase extends MessagingDatabase {
|
||||
long threadId = cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.THREAD_ID));
|
||||
String address = cursor.getString(cursor.getColumnIndexOrThrow(MmsDatabase.ADDRESS));
|
||||
int addressDeviceId = cursor.getInt(cursor.getColumnIndexOrThrow(MmsDatabase.ADDRESS_DEVICE_ID));
|
||||
int receiptCount = cursor.getInt(cursor.getColumnIndexOrThrow(MmsDatabase.RECEIPT_COUNT));
|
||||
int deliveryReceiptCount = cursor.getInt(cursor.getColumnIndexOrThrow(MmsDatabase.DELIVERY_RECEIPT_COUNT));
|
||||
int readReceiptCount = cursor.getInt(cursor.getColumnIndexOrThrow(MmsDatabase.READ_RECEIPT_COUNT));
|
||||
DisplayRecord.Body body = getBody(cursor);
|
||||
int partCount = cursor.getInt(cursor.getColumnIndexOrThrow(MmsDatabase.PART_COUNT));
|
||||
String mismatchDocument = cursor.getString(cursor.getColumnIndexOrThrow(MmsDatabase.MISMATCHED_IDENTITIES));
|
||||
@ -1148,15 +1162,20 @@ public class MmsDatabase extends MessagingDatabase {
|
||||
long expiresIn = cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.EXPIRES_IN));
|
||||
long expireStarted = cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.EXPIRE_STARTED));
|
||||
|
||||
if (!TextSecurePreferences.isReadReceiptsEnabled(context)) {
|
||||
readReceiptCount = 0;
|
||||
}
|
||||
|
||||
Recipient recipient = getRecipientFor(address);
|
||||
List<IdentityKeyMismatch> mismatches = getMismatchedIdentities(mismatchDocument);
|
||||
List<NetworkFailure> networkFailures = getFailures(networkDocument);
|
||||
SlideDeck slideDeck = getSlideDeck(cursor);
|
||||
|
||||
return new MediaMmsMessageRecord(context, id, recipient, recipient,
|
||||
addressDeviceId, dateSent, dateReceived, receiptCount,
|
||||
addressDeviceId, dateSent, dateReceived, deliveryReceiptCount,
|
||||
threadId, body, slideDeck, partCount, box, mismatches,
|
||||
networkFailures, subscriptionId, expiresIn, expireStarted);
|
||||
networkFailures, subscriptionId, expiresIn, expireStarted,
|
||||
readReceiptCount);
|
||||
}
|
||||
|
||||
private Recipient getRecipientFor(String serialized) {
|
||||
|
@ -11,7 +11,8 @@ public interface MmsSmsColumns {
|
||||
public static final String BODY = "body";
|
||||
public static final String ADDRESS = "address";
|
||||
public static final String ADDRESS_DEVICE_ID = "address_device_id";
|
||||
public static final String RECEIPT_COUNT = "delivery_receipt_count";
|
||||
public static final String DELIVERY_RECEIPT_COUNT = "delivery_receipt_count";
|
||||
public static final String READ_RECEIPT_COUNT = "read_receipt_count";
|
||||
public static final String MISMATCHED_IDENTITIES = "mismatched_identities";
|
||||
public static final String UNIQUE_ROW_ID = "unique_row_id";
|
||||
public static final String SUBSCRIPTION_ID = "subscription_id";
|
||||
|
@ -25,7 +25,6 @@ import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.util.Log;
|
||||
|
||||
import org.thoughtcrime.securesms.attachments.Attachment;
|
||||
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
||||
import org.thoughtcrime.securesms.database.MessagingDatabase.SyncMessageId;
|
||||
import org.thoughtcrime.securesms.database.model.MessageRecord;
|
||||
@ -52,7 +51,9 @@ public class MmsSmsDatabase extends Database {
|
||||
SmsDatabase.STATUS, MmsDatabase.PART_COUNT,
|
||||
MmsDatabase.CONTENT_LOCATION, MmsDatabase.TRANSACTION_ID,
|
||||
MmsDatabase.MESSAGE_SIZE, MmsDatabase.EXPIRY,
|
||||
MmsDatabase.STATUS, MmsSmsColumns.RECEIPT_COUNT,
|
||||
MmsDatabase.STATUS,
|
||||
MmsSmsColumns.DELIVERY_RECEIPT_COUNT,
|
||||
MmsSmsColumns.READ_RECEIPT_COUNT,
|
||||
MmsSmsColumns.MISMATCHED_IDENTITIES,
|
||||
MmsDatabase.NETWORK_FAILURE,
|
||||
MmsSmsColumns.SUBSCRIPTION_ID,
|
||||
@ -137,8 +138,13 @@ public class MmsSmsDatabase extends Database {
|
||||
}
|
||||
|
||||
public void incrementDeliveryReceiptCount(SyncMessageId syncMessageId) {
|
||||
DatabaseFactory.getSmsDatabase(context).incrementDeliveryReceiptCount(syncMessageId);
|
||||
DatabaseFactory.getMmsDatabase(context).incrementDeliveryReceiptCount(syncMessageId);
|
||||
DatabaseFactory.getSmsDatabase(context).incrementReceiptCount(syncMessageId, true, false);
|
||||
DatabaseFactory.getMmsDatabase(context).incrementReceiptCount(syncMessageId, true, false);
|
||||
}
|
||||
|
||||
public void incrementReadReceiptCount(SyncMessageId syncMessageId) {
|
||||
DatabaseFactory.getSmsDatabase(context).incrementReceiptCount(syncMessageId, false, true);
|
||||
DatabaseFactory.getMmsDatabase(context).incrementReceiptCount(syncMessageId, false, true);
|
||||
}
|
||||
|
||||
private Cursor queryTables(String[] projection, String selection, String order, String limit) {
|
||||
@ -154,7 +160,8 @@ public class MmsSmsDatabase extends Database {
|
||||
MmsDatabase.MESSAGE_BOX, SmsDatabase.STATUS, MmsDatabase.PART_COUNT,
|
||||
MmsDatabase.CONTENT_LOCATION, MmsDatabase.TRANSACTION_ID,
|
||||
MmsDatabase.MESSAGE_SIZE, MmsDatabase.EXPIRY, MmsDatabase.STATUS,
|
||||
MmsSmsColumns.RECEIPT_COUNT, MmsSmsColumns.MISMATCHED_IDENTITIES,
|
||||
MmsSmsColumns.DELIVERY_RECEIPT_COUNT, MmsSmsColumns.READ_RECEIPT_COUNT,
|
||||
MmsSmsColumns.MISMATCHED_IDENTITIES,
|
||||
MmsSmsColumns.SUBSCRIPTION_ID, MmsSmsColumns.EXPIRES_IN, MmsSmsColumns.EXPIRE_STARTED,
|
||||
MmsSmsColumns.NOTIFIED,
|
||||
MmsDatabase.NETWORK_FAILURE, TRANSPORT,
|
||||
@ -185,7 +192,8 @@ public class MmsSmsDatabase extends Database {
|
||||
MmsDatabase.MESSAGE_BOX, SmsDatabase.STATUS, MmsDatabase.PART_COUNT,
|
||||
MmsDatabase.CONTENT_LOCATION, MmsDatabase.TRANSACTION_ID,
|
||||
MmsDatabase.MESSAGE_SIZE, MmsDatabase.EXPIRY, MmsDatabase.STATUS,
|
||||
MmsSmsColumns.RECEIPT_COUNT, MmsSmsColumns.MISMATCHED_IDENTITIES,
|
||||
MmsSmsColumns.DELIVERY_RECEIPT_COUNT, MmsSmsColumns.READ_RECEIPT_COUNT,
|
||||
MmsSmsColumns.MISMATCHED_IDENTITIES,
|
||||
MmsSmsColumns.SUBSCRIPTION_ID, MmsSmsColumns.EXPIRES_IN, MmsSmsColumns.EXPIRE_STARTED,
|
||||
MmsSmsColumns.NOTIFIED,
|
||||
MmsDatabase.NETWORK_FAILURE, TRANSPORT,
|
||||
@ -227,7 +235,8 @@ public class MmsSmsDatabase extends Database {
|
||||
mmsColumnsPresent.add(MmsSmsColumns.BODY);
|
||||
mmsColumnsPresent.add(MmsSmsColumns.ADDRESS);
|
||||
mmsColumnsPresent.add(MmsSmsColumns.ADDRESS_DEVICE_ID);
|
||||
mmsColumnsPresent.add(MmsSmsColumns.RECEIPT_COUNT);
|
||||
mmsColumnsPresent.add(MmsSmsColumns.DELIVERY_RECEIPT_COUNT);
|
||||
mmsColumnsPresent.add(MmsSmsColumns.READ_RECEIPT_COUNT);
|
||||
mmsColumnsPresent.add(MmsSmsColumns.MISMATCHED_IDENTITIES);
|
||||
mmsColumnsPresent.add(MmsSmsColumns.SUBSCRIPTION_ID);
|
||||
mmsColumnsPresent.add(MmsSmsColumns.EXPIRES_IN);
|
||||
@ -268,7 +277,8 @@ public class MmsSmsDatabase extends Database {
|
||||
smsColumnsPresent.add(MmsSmsColumns.ADDRESS_DEVICE_ID);
|
||||
smsColumnsPresent.add(MmsSmsColumns.READ);
|
||||
smsColumnsPresent.add(MmsSmsColumns.THREAD_ID);
|
||||
smsColumnsPresent.add(MmsSmsColumns.RECEIPT_COUNT);
|
||||
smsColumnsPresent.add(MmsSmsColumns.DELIVERY_RECEIPT_COUNT);
|
||||
smsColumnsPresent.add(MmsSmsColumns.READ_RECEIPT_COUNT);
|
||||
smsColumnsPresent.add(MmsSmsColumns.MISMATCHED_IDENTITIES);
|
||||
smsColumnsPresent.add(MmsSmsColumns.SUBSCRIPTION_ID);
|
||||
smsColumnsPresent.add(MmsSmsColumns.EXPIRES_IN);
|
||||
|
@ -39,6 +39,7 @@ import org.thoughtcrime.securesms.sms.IncomingGroupMessage;
|
||||
import org.thoughtcrime.securesms.sms.IncomingTextMessage;
|
||||
import org.thoughtcrime.securesms.sms.OutgoingTextMessage;
|
||||
import org.thoughtcrime.securesms.util.JsonUtils;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
import org.whispersystems.jobqueue.JobManager;
|
||||
import org.whispersystems.libsignal.util.guava.Optional;
|
||||
|
||||
@ -73,9 +74,10 @@ public class SmsDatabase extends MessagingDatabase {
|
||||
THREAD_ID + " INTEGER, " + ADDRESS + " TEXT, " + ADDRESS_DEVICE_ID + " INTEGER DEFAULT 1, " + PERSON + " INTEGER, " +
|
||||
DATE_RECEIVED + " INTEGER, " + DATE_SENT + " INTEGER, " + PROTOCOL + " INTEGER, " + READ + " INTEGER DEFAULT 0, " +
|
||||
STATUS + " INTEGER DEFAULT -1," + TYPE + " INTEGER, " + REPLY_PATH_PRESENT + " INTEGER, " +
|
||||
RECEIPT_COUNT + " INTEGER DEFAULT 0," + SUBJECT + " TEXT, " + BODY + " TEXT, " +
|
||||
DELIVERY_RECEIPT_COUNT + " INTEGER DEFAULT 0," + SUBJECT + " TEXT, " + BODY + " TEXT, " +
|
||||
MISMATCHED_IDENTITIES + " TEXT DEFAULT NULL, " + SERVICE_CENTER + " TEXT, " + SUBSCRIPTION_ID + " INTEGER DEFAULT -1, " +
|
||||
EXPIRES_IN + " INTEGER DEFAULT 0, " + EXPIRE_STARTED + " INTEGER DEFAULT 0, " + NOTIFIED + " DEFAULT 0);";
|
||||
EXPIRES_IN + " INTEGER DEFAULT 0, " + EXPIRE_STARTED + " INTEGER DEFAULT 0, " + NOTIFIED + " DEFAULT 0, " +
|
||||
READ_RECEIPT_COUNT + " INTEGER DEFAULT 0);";
|
||||
|
||||
public static final String[] CREATE_INDEXS = {
|
||||
"CREATE INDEX IF NOT EXISTS sms_thread_id_index ON " + TABLE_NAME + " (" + THREAD_ID + ");",
|
||||
@ -91,12 +93,14 @@ public class SmsDatabase extends MessagingDatabase {
|
||||
DATE_RECEIVED + " AS " + NORMALIZED_DATE_RECEIVED,
|
||||
DATE_SENT + " AS " + NORMALIZED_DATE_SENT,
|
||||
PROTOCOL, READ, STATUS, TYPE,
|
||||
REPLY_PATH_PRESENT, SUBJECT, BODY, SERVICE_CENTER, RECEIPT_COUNT,
|
||||
REPLY_PATH_PRESENT, SUBJECT, BODY, SERVICE_CENTER, DELIVERY_RECEIPT_COUNT,
|
||||
MISMATCHED_IDENTITIES, SUBSCRIPTION_ID, EXPIRES_IN, EXPIRE_STARTED,
|
||||
NOTIFIED
|
||||
NOTIFIED, READ_RECEIPT_COUNT
|
||||
};
|
||||
|
||||
private static final EarlyReceiptCache earlyReceiptCache = new EarlyReceiptCache();
|
||||
private static final EarlyReceiptCache earlyDeliveryReceiptCache = new EarlyReceiptCache();
|
||||
private static final EarlyReceiptCache earlyReadReceiptCache = new EarlyReceiptCache();
|
||||
|
||||
private final JobManager jobManager;
|
||||
|
||||
public SmsDatabase(Context context, SQLiteOpenHelper databaseHelper) {
|
||||
@ -277,7 +281,7 @@ public class SmsDatabase extends MessagingDatabase {
|
||||
database.update(TABLE_NAME, contentValues, ID_WHERE, new String[] {String.valueOf(id)});
|
||||
}
|
||||
|
||||
public void incrementDeliveryReceiptCount(SyncMessageId messageId) {
|
||||
public void incrementReceiptCount(SyncMessageId messageId, boolean deliveryReceipt, boolean readReceipt) {
|
||||
SQLiteDatabase database = databaseHelper.getWritableDatabase();
|
||||
Cursor cursor = null;
|
||||
boolean foundMessage = false;
|
||||
@ -291,12 +295,13 @@ public class SmsDatabase extends MessagingDatabase {
|
||||
if (Types.isOutgoingMessageType(cursor.getLong(cursor.getColumnIndexOrThrow(TYPE)))) {
|
||||
Address theirAddress = messageId.getAddress();
|
||||
Address ourAddress = Address.fromSerialized(cursor.getString(cursor.getColumnIndexOrThrow(ADDRESS)));
|
||||
String columnName = deliveryReceipt ? DELIVERY_RECEIPT_COUNT : READ_RECEIPT_COUNT;
|
||||
|
||||
if (ourAddress.equals(theirAddress)) {
|
||||
long threadId = cursor.getLong(cursor.getColumnIndexOrThrow(THREAD_ID));
|
||||
|
||||
database.execSQL("UPDATE " + TABLE_NAME +
|
||||
" SET " + RECEIPT_COUNT + " = " + RECEIPT_COUNT + " + 1 WHERE " +
|
||||
" SET " + columnName + " = " + columnName + " + 1 WHERE " +
|
||||
ID + " = ?",
|
||||
new String[] {String.valueOf(cursor.getLong(cursor.getColumnIndexOrThrow(ID)))});
|
||||
|
||||
@ -308,7 +313,8 @@ public class SmsDatabase extends MessagingDatabase {
|
||||
}
|
||||
|
||||
if (!foundMessage) {
|
||||
earlyReceiptCache.increment(messageId.getTimetamp(), messageId.getAddress());
|
||||
if (deliveryReceipt) earlyDeliveryReceiptCache.increment(messageId.getTimetamp(), messageId.getAddress());
|
||||
if (readReceipt) earlyReadReceiptCache.increment(messageId.getTimetamp(), messageId.getAddress());
|
||||
}
|
||||
|
||||
} finally {
|
||||
@ -600,7 +606,8 @@ public class SmsDatabase extends MessagingDatabase {
|
||||
contentValues.put(TYPE, type);
|
||||
contentValues.put(SUBSCRIPTION_ID, message.getSubscriptionId());
|
||||
contentValues.put(EXPIRES_IN, message.getExpiresIn());
|
||||
contentValues.put(RECEIPT_COUNT, earlyReceiptCache.remove(date, address));
|
||||
contentValues.put(DELIVERY_RECEIPT_COUNT, earlyDeliveryReceiptCache.remove(date, address));
|
||||
contentValues.put(READ_RECEIPT_COUNT, earlyReadReceiptCache.remove(date, address));
|
||||
|
||||
SQLiteDatabase db = databaseHelper.getWritableDatabase();
|
||||
long messageId = db.insert(TABLE_NAME, ADDRESS, contentValues);
|
||||
@ -789,7 +796,7 @@ public class SmsDatabase extends MessagingDatabase {
|
||||
0, message.isSecureMessage() ? MmsSmsColumns.Types.getOutgoingEncryptedMessageType() : MmsSmsColumns.Types.getOutgoingSmsMessageType(),
|
||||
threadId, 0, new LinkedList<IdentityKeyMismatch>(),
|
||||
message.getSubscriptionId(), message.getExpiresIn(),
|
||||
System.currentTimeMillis());
|
||||
System.currentTimeMillis(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
@ -822,12 +829,17 @@ public class SmsDatabase extends MessagingDatabase {
|
||||
long dateSent = cursor.getLong(cursor.getColumnIndexOrThrow(SmsDatabase.NORMALIZED_DATE_SENT));
|
||||
long threadId = cursor.getLong(cursor.getColumnIndexOrThrow(SmsDatabase.THREAD_ID));
|
||||
int status = cursor.getInt(cursor.getColumnIndexOrThrow(SmsDatabase.STATUS));
|
||||
int receiptCount = cursor.getInt(cursor.getColumnIndexOrThrow(SmsDatabase.RECEIPT_COUNT));
|
||||
int deliveryReceiptCount = cursor.getInt(cursor.getColumnIndexOrThrow(SmsDatabase.DELIVERY_RECEIPT_COUNT));
|
||||
int readReceiptCount = cursor.getInt(cursor.getColumnIndexOrThrow(SmsDatabase.READ_RECEIPT_COUNT));
|
||||
String mismatchDocument = cursor.getString(cursor.getColumnIndexOrThrow(SmsDatabase.MISMATCHED_IDENTITIES));
|
||||
int subscriptionId = cursor.getInt(cursor.getColumnIndexOrThrow(SmsDatabase.SUBSCRIPTION_ID));
|
||||
long expiresIn = cursor.getLong(cursor.getColumnIndexOrThrow(SmsDatabase.EXPIRES_IN));
|
||||
long expireStarted = cursor.getLong(cursor.getColumnIndexOrThrow(SmsDatabase.EXPIRE_STARTED));
|
||||
|
||||
if (!TextSecurePreferences.isReadReceiptsEnabled(context)) {
|
||||
readReceiptCount = 0;
|
||||
}
|
||||
|
||||
List<IdentityKeyMismatch> mismatches = getMismatches(mismatchDocument);
|
||||
Recipient recipient = Recipient.from(context, address, true);
|
||||
DisplayRecord.Body body = getBody(cursor);
|
||||
@ -835,9 +847,9 @@ public class SmsDatabase extends MessagingDatabase {
|
||||
return new SmsMessageRecord(context, messageId, body, recipient,
|
||||
recipient,
|
||||
addressDeviceId,
|
||||
dateSent, dateReceived, receiptCount, type,
|
||||
dateSent, dateReceived, deliveryReceiptCount, type,
|
||||
threadId, status, mismatches, subscriptionId,
|
||||
expiresIn, expireStarted);
|
||||
expiresIn, expireStarted, readReceiptCount);
|
||||
}
|
||||
|
||||
private List<IdentityKeyMismatch> getMismatches(String document) {
|
||||
|
@ -43,6 +43,7 @@ import org.thoughtcrime.securesms.mms.Slide;
|
||||
import org.thoughtcrime.securesms.mms.SlideDeck;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.util.DelimiterUtil;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
import org.whispersystems.libsignal.InvalidMessageException;
|
||||
import org.whispersystems.libsignal.util.Pair;
|
||||
@ -70,7 +71,8 @@ public class ThreadDatabase extends Database {
|
||||
public static final String SNIPPET_URI = "snippet_uri";
|
||||
public static final String ARCHIVED = "archived";
|
||||
public static final String STATUS = "status";
|
||||
public static final String RECEIPT_COUNT = "delivery_receipt_count";
|
||||
public static final String DELIVERY_RECEIPT_COUNT = "delivery_receipt_count";
|
||||
public static final String READ_RECEIPT_COUNT = "read_receipt_count";
|
||||
public static final String EXPIRES_IN = "expires_in";
|
||||
public static final String LAST_SEEN = "last_seen";
|
||||
private static final String HAS_SENT = "has_sent";
|
||||
@ -82,8 +84,9 @@ public class ThreadDatabase extends Database {
|
||||
TYPE + " INTEGER DEFAULT 0, " + ERROR + " INTEGER DEFAULT 0, " +
|
||||
SNIPPET_TYPE + " INTEGER DEFAULT 0, " + SNIPPET_URI + " TEXT DEFAULT NULL, " +
|
||||
ARCHIVED + " INTEGER DEFAULT 0, " + STATUS + " INTEGER DEFAULT 0, " +
|
||||
RECEIPT_COUNT + " INTEGER DEFAULT 0, " + EXPIRES_IN + " INTEGER DEFAULT 0, " +
|
||||
LAST_SEEN + " INTEGER DEFAULT 0, " + HAS_SENT + " INTEGER DEFAULT 0);";
|
||||
DELIVERY_RECEIPT_COUNT + " INTEGER DEFAULT 0, " + EXPIRES_IN + " INTEGER DEFAULT 0, " +
|
||||
LAST_SEEN + " INTEGER DEFAULT 0, " + HAS_SENT + " INTEGER DEFAULT 0, " +
|
||||
READ_RECEIPT_COUNT + " INTEGER DEFAULT 0);";
|
||||
|
||||
public static final String[] CREATE_INDEXS = {
|
||||
"CREATE INDEX IF NOT EXISTS thread_recipient_ids_index ON " + TABLE_NAME + " (" + ADDRESS + ");",
|
||||
@ -92,7 +95,7 @@ public class ThreadDatabase extends Database {
|
||||
|
||||
private static final String[] THREAD_PROJECTION = {
|
||||
ID, DATE, MESSAGE_COUNT, ADDRESS, SNIPPET, SNIPPET_CHARSET, READ, TYPE, ERROR, SNIPPET_TYPE,
|
||||
SNIPPET_URI, ARCHIVED, STATUS, RECEIPT_COUNT, EXPIRES_IN, LAST_SEEN
|
||||
SNIPPET_URI, ARCHIVED, STATUS, DELIVERY_RECEIPT_COUNT, EXPIRES_IN, LAST_SEEN, READ_RECEIPT_COUNT
|
||||
};
|
||||
|
||||
private static final List<String> TYPED_THREAD_PROJECTION = Stream.of(THREAD_PROJECTION)
|
||||
@ -125,8 +128,8 @@ public class ThreadDatabase extends Database {
|
||||
}
|
||||
|
||||
private void updateThread(long threadId, long count, String body, @Nullable Uri attachment,
|
||||
long date, int status, int receiptCount, long type, boolean unarchive,
|
||||
long expiresIn)
|
||||
long date, int status, int deliveryReceiptCount, long type, boolean unarchive,
|
||||
long expiresIn, int readReceiptCount)
|
||||
{
|
||||
ContentValues contentValues = new ContentValues(7);
|
||||
contentValues.put(DATE, date - date % 1000);
|
||||
@ -135,7 +138,8 @@ public class ThreadDatabase extends Database {
|
||||
contentValues.put(SNIPPET_URI, attachment == null ? null : attachment.toString());
|
||||
contentValues.put(SNIPPET_TYPE, type);
|
||||
contentValues.put(STATUS, status);
|
||||
contentValues.put(RECEIPT_COUNT, receiptCount);
|
||||
contentValues.put(DELIVERY_RECEIPT_COUNT, deliveryReceiptCount);
|
||||
contentValues.put(READ_RECEIPT_COUNT, readReceiptCount);
|
||||
contentValues.put(EXPIRES_IN, expiresIn);
|
||||
|
||||
if (unarchive) {
|
||||
@ -550,8 +554,8 @@ public class ThreadDatabase extends Database {
|
||||
|
||||
if (reader != null && (record = reader.getNext()) != null) {
|
||||
updateThread(threadId, count, record.getBody().getBody(), getAttachmentUriFor(record),
|
||||
record.getTimestamp(), record.getDeliveryStatus(), record.getReceiptCount(),
|
||||
record.getType(), unarchive, record.getExpiresIn());
|
||||
record.getTimestamp(), record.getDeliveryStatus(), record.getDeliveryReceiptCount(),
|
||||
record.getType(), unarchive, record.getExpiresIn(), record.getReadReceiptCount());
|
||||
notifyConversationListListeners();
|
||||
return false;
|
||||
} else {
|
||||
@ -641,14 +645,19 @@ public class ThreadDatabase extends Database {
|
||||
long type = cursor.getLong(cursor.getColumnIndexOrThrow(ThreadDatabase.SNIPPET_TYPE));
|
||||
boolean archived = cursor.getInt(cursor.getColumnIndex(ThreadDatabase.ARCHIVED)) != 0;
|
||||
int status = cursor.getInt(cursor.getColumnIndexOrThrow(ThreadDatabase.STATUS));
|
||||
int receiptCount = cursor.getInt(cursor.getColumnIndexOrThrow(ThreadDatabase.RECEIPT_COUNT));
|
||||
int deliveryReceiptCount = cursor.getInt(cursor.getColumnIndexOrThrow(ThreadDatabase.DELIVERY_RECEIPT_COUNT));
|
||||
int readReceiptCount = cursor.getInt(cursor.getColumnIndexOrThrow(ThreadDatabase.READ_RECEIPT_COUNT));
|
||||
long expiresIn = cursor.getLong(cursor.getColumnIndexOrThrow(ThreadDatabase.EXPIRES_IN));
|
||||
long lastSeen = cursor.getLong(cursor.getColumnIndexOrThrow(ThreadDatabase.LAST_SEEN));
|
||||
Uri snippetUri = getSnippetUri(cursor);
|
||||
|
||||
if (!TextSecurePreferences.isReadReceiptsEnabled(context)) {
|
||||
readReceiptCount = 0;
|
||||
}
|
||||
|
||||
return new ThreadRecord(context, body, snippetUri, recipient, date, count, read == 1,
|
||||
threadId, receiptCount, status, type, distributionType, archived,
|
||||
expiresIn, lastSeen);
|
||||
threadId, deliveryReceiptCount, status, type, distributionType, archived,
|
||||
expiresIn, lastSeen, readReceiptCount);
|
||||
}
|
||||
|
||||
private DisplayRecord.Body getPlaintextBody(Cursor cursor) {
|
||||
|
@ -44,12 +44,12 @@ public class ConversationListLoader extends AbstractCursorLoader {
|
||||
ThreadDatabase.ID, ThreadDatabase.DATE, ThreadDatabase.MESSAGE_COUNT,
|
||||
ThreadDatabase.ADDRESS, ThreadDatabase.SNIPPET, ThreadDatabase.READ,
|
||||
ThreadDatabase.TYPE, ThreadDatabase.SNIPPET_TYPE, ThreadDatabase.SNIPPET_URI,
|
||||
ThreadDatabase.ARCHIVED, ThreadDatabase.STATUS, ThreadDatabase.RECEIPT_COUNT,
|
||||
ThreadDatabase.EXPIRES_IN, ThreadDatabase.LAST_SEEN}, 1);
|
||||
ThreadDatabase.ARCHIVED, ThreadDatabase.STATUS, ThreadDatabase.DELIVERY_RECEIPT_COUNT,
|
||||
ThreadDatabase.EXPIRES_IN, ThreadDatabase.LAST_SEEN, ThreadDatabase.READ_RECEIPT_COUNT}, 1);
|
||||
|
||||
switchToArchiveCursor.addRow(new Object[] {-1L, System.currentTimeMillis(), archivedCount,
|
||||
"-1", null, 1, ThreadDatabase.DistributionTypes.ARCHIVE,
|
||||
0, null, 0, -1, 0, 0, 0});
|
||||
0, null, 0, -1, 0, 0, 0, -1});
|
||||
|
||||
cursorList.add(switchToArchiveCursor);
|
||||
}
|
||||
|
@ -42,10 +42,12 @@ public abstract class DisplayRecord {
|
||||
private final long threadId;
|
||||
private final Body body;
|
||||
private final int deliveryStatus;
|
||||
private final int receiptCount;
|
||||
private final int deliveryReceiptCount;
|
||||
private final int readReceiptCount;
|
||||
|
||||
public DisplayRecord(Context context, Body body, Recipient recipient, long dateSent,
|
||||
long dateReceived, long threadId, int deliveryStatus, int receiptCount, long type)
|
||||
long dateReceived, long threadId, int deliveryStatus, int deliveryReceiptCount,
|
||||
long type, int readReceiptCount)
|
||||
{
|
||||
this.context = context.getApplicationContext();
|
||||
this.threadId = threadId;
|
||||
@ -54,7 +56,8 @@ public abstract class DisplayRecord {
|
||||
this.dateReceived = dateReceived;
|
||||
this.type = type;
|
||||
this.body = body;
|
||||
this.receiptCount = receiptCount;
|
||||
this.deliveryReceiptCount = deliveryReceiptCount;
|
||||
this.readReceiptCount = readReceiptCount;
|
||||
this.deliveryStatus = deliveryStatus;
|
||||
}
|
||||
|
||||
@ -145,13 +148,21 @@ public abstract class DisplayRecord {
|
||||
return deliveryStatus;
|
||||
}
|
||||
|
||||
public int getReceiptCount() {
|
||||
return receiptCount;
|
||||
public int getDeliveryReceiptCount() {
|
||||
return deliveryReceiptCount;
|
||||
}
|
||||
|
||||
public int getReadReceiptCount() {
|
||||
return readReceiptCount;
|
||||
}
|
||||
|
||||
public boolean isDelivered() {
|
||||
return (deliveryStatus >= SmsDatabase.Status.STATUS_COMPLETE &&
|
||||
deliveryStatus < SmsDatabase.Status.STATUS_PENDING) || receiptCount > 0;
|
||||
deliveryStatus < SmsDatabase.Status.STATUS_PENDING) || deliveryReceiptCount > 0;
|
||||
}
|
||||
|
||||
public boolean isRemoteRead() {
|
||||
return readReceiptCount > 0;
|
||||
}
|
||||
|
||||
public boolean isPendingInsecureSmsFallback() {
|
||||
|
@ -46,17 +46,17 @@ public class MediaMmsMessageRecord extends MmsMessageRecord {
|
||||
|
||||
public MediaMmsMessageRecord(Context context, long id, Recipient conversationRecipient,
|
||||
Recipient individualRecipient, int recipientDeviceId,
|
||||
long dateSent, long dateReceived, int receiptCount,
|
||||
long dateSent, long dateReceived, int deliveryReceiptCount,
|
||||
long threadId, Body body,
|
||||
@NonNull SlideDeck slideDeck,
|
||||
int partCount, long mailbox,
|
||||
List<IdentityKeyMismatch> mismatches,
|
||||
List<NetworkFailure> failures, int subscriptionId,
|
||||
long expiresIn, long expireStarted)
|
||||
long expiresIn, long expireStarted, int readReceiptCount)
|
||||
{
|
||||
super(context, id, body, conversationRecipient, individualRecipient, recipientDeviceId, dateSent,
|
||||
dateReceived, threadId, Status.STATUS_NONE, receiptCount, mailbox, mismatches, failures,
|
||||
subscriptionId, expiresIn, expireStarted, slideDeck);
|
||||
dateReceived, threadId, Status.STATUS_NONE, deliveryReceiptCount, mailbox, mismatches, failures,
|
||||
subscriptionId, expiresIn, expireStarted, slideDeck, readReceiptCount);
|
||||
|
||||
this.context = context.getApplicationContext();
|
||||
this.partCount = partCount;
|
||||
|
@ -57,13 +57,14 @@ public abstract class MessageRecord extends DisplayRecord {
|
||||
MessageRecord(Context context, long id, Body body, Recipient conversationRecipient,
|
||||
Recipient individualRecipient, int recipientDeviceId,
|
||||
long dateSent, long dateReceived, long threadId,
|
||||
int deliveryStatus, int receiptCount, long type,
|
||||
int deliveryStatus, int deliveryReceiptCount, long type,
|
||||
List<IdentityKeyMismatch> mismatches,
|
||||
List<NetworkFailure> networkFailures,
|
||||
int subscriptionId, long expiresIn, long expireStarted)
|
||||
int subscriptionId, long expiresIn, long expireStarted,
|
||||
int readReceiptCount)
|
||||
{
|
||||
super(context, body, conversationRecipient, dateSent, dateReceived, threadId, deliveryStatus, receiptCount,
|
||||
type);
|
||||
super(context, body, conversationRecipient, dateSent, dateReceived,
|
||||
threadId, deliveryStatus, deliveryReceiptCount, type, readReceiptCount);
|
||||
this.id = id;
|
||||
this.individualRecipient = individualRecipient;
|
||||
this.recipientDeviceId = recipientDeviceId;
|
||||
|
@ -18,12 +18,12 @@ public abstract class MmsMessageRecord extends MessageRecord {
|
||||
|
||||
MmsMessageRecord(Context context, long id, Body body, Recipient conversationRecipient,
|
||||
Recipient individualRecipient, int recipientDeviceId, long dateSent,
|
||||
long dateReceived, long threadId, int deliveryStatus, int receiptCount,
|
||||
long dateReceived, long threadId, int deliveryStatus, int deliveryReceiptCount,
|
||||
long type, List<IdentityKeyMismatch> mismatches,
|
||||
List<NetworkFailure> networkFailures, int subscriptionId, long expiresIn,
|
||||
long expireStarted, @NonNull SlideDeck slideDeck)
|
||||
long expireStarted, @NonNull SlideDeck slideDeck, int readReceiptCount)
|
||||
{
|
||||
super(context, id, body, conversationRecipient, individualRecipient, recipientDeviceId, dateSent, dateReceived, threadId, deliveryStatus, receiptCount, type, mismatches, networkFailures, subscriptionId, expiresIn, expireStarted);
|
||||
super(context, id, body, conversationRecipient, individualRecipient, recipientDeviceId, dateSent, dateReceived, threadId, deliveryStatus, deliveryReceiptCount, type, mismatches, networkFailures, subscriptionId, expiresIn, expireStarted, readReceiptCount);
|
||||
this.slideDeck = slideDeck;
|
||||
}
|
||||
|
||||
|
@ -47,15 +47,15 @@ public class NotificationMmsMessageRecord extends MmsMessageRecord {
|
||||
|
||||
public NotificationMmsMessageRecord(Context context, long id, Recipient conversationRecipient,
|
||||
Recipient individualRecipient, int recipientDeviceId,
|
||||
long dateSent, long dateReceived, int receiptCount,
|
||||
long dateSent, long dateReceived, int deliveryReceiptCount,
|
||||
long threadId, byte[] contentLocation, long messageSize,
|
||||
long expiry, int status, byte[] transactionId, long mailbox,
|
||||
int subscriptionId, SlideDeck slideDeck)
|
||||
int subscriptionId, SlideDeck slideDeck, int readReceiptCount)
|
||||
{
|
||||
super(context, id, new Body("", true), conversationRecipient, individualRecipient, recipientDeviceId,
|
||||
dateSent, dateReceived, threadId, Status.STATUS_NONE, receiptCount, mailbox,
|
||||
dateSent, dateReceived, threadId, Status.STATUS_NONE, deliveryReceiptCount, mailbox,
|
||||
new LinkedList<IdentityKeyMismatch>(), new LinkedList<NetworkFailure>(), subscriptionId,
|
||||
0, 0, slideDeck);
|
||||
0, 0, slideDeck, readReceiptCount);
|
||||
|
||||
this.contentLocation = contentLocation;
|
||||
this.messageSize = messageSize;
|
||||
|
@ -44,15 +44,16 @@ public class SmsMessageRecord extends MessageRecord {
|
||||
Recipient individualRecipient,
|
||||
int recipientDeviceId,
|
||||
long dateSent, long dateReceived,
|
||||
int receiptCount,
|
||||
int deliveryReceiptCount,
|
||||
long type, long threadId,
|
||||
int status, List<IdentityKeyMismatch> mismatches,
|
||||
int subscriptionId, long expiresIn, long expireStarted)
|
||||
int subscriptionId, long expiresIn, long expireStarted,
|
||||
int readReceiptCount)
|
||||
{
|
||||
super(context, id, body, recipient, individualRecipient, recipientDeviceId,
|
||||
dateSent, dateReceived, threadId, status, receiptCount, type,
|
||||
dateSent, dateReceived, threadId, status, deliveryReceiptCount, type,
|
||||
mismatches, new LinkedList<NetworkFailure>(), subscriptionId,
|
||||
expiresIn, expireStarted);
|
||||
expiresIn, expireStarted, readReceiptCount);
|
||||
}
|
||||
|
||||
public long getType() {
|
||||
|
@ -50,10 +50,11 @@ public class ThreadRecord extends DisplayRecord {
|
||||
|
||||
public ThreadRecord(@NonNull Context context, @NonNull Body body, @Nullable Uri snippetUri,
|
||||
@NonNull Recipient recipient, long date, long count, boolean read,
|
||||
long threadId, int receiptCount, int status, long snippetType,
|
||||
int distributionType, boolean archived, long expiresIn, long lastSeen)
|
||||
long threadId, int deliveryReceiptCount, int status, long snippetType,
|
||||
int distributionType, boolean archived, long expiresIn, long lastSeen,
|
||||
int readReceiptCount)
|
||||
{
|
||||
super(context, body, recipient, date, date, threadId, status, receiptCount, snippetType);
|
||||
super(context, body, recipient, date, date, threadId, status, deliveryReceiptCount, snippetType, readReceiptCount);
|
||||
this.context = context.getApplicationContext();
|
||||
this.snippetUri = snippetUri;
|
||||
this.count = count;
|
||||
|
@ -10,7 +10,6 @@ import org.thoughtcrime.securesms.jobs.AttachmentDownloadJob;
|
||||
import org.thoughtcrime.securesms.jobs.AvatarDownloadJob;
|
||||
import org.thoughtcrime.securesms.jobs.CleanPreKeysJob;
|
||||
import org.thoughtcrime.securesms.jobs.CreateSignedPreKeyJob;
|
||||
import org.thoughtcrime.securesms.jobs.DeliveryReceiptJob;
|
||||
import org.thoughtcrime.securesms.jobs.GcmRefreshJob;
|
||||
import org.thoughtcrime.securesms.jobs.MultiDeviceBlockedUpdateJob;
|
||||
import org.thoughtcrime.securesms.jobs.MultiDeviceContactUpdateJob;
|
||||
@ -29,6 +28,7 @@ import org.thoughtcrime.securesms.jobs.RequestGroupInfoJob;
|
||||
import org.thoughtcrime.securesms.jobs.RetrieveProfileAvatarJob;
|
||||
import org.thoughtcrime.securesms.jobs.RetrieveProfileJob;
|
||||
import org.thoughtcrime.securesms.jobs.RotateSignedPreKeyJob;
|
||||
import org.thoughtcrime.securesms.jobs.SendReadReceiptJob;
|
||||
import org.thoughtcrime.securesms.push.SecurityEventListener;
|
||||
import org.thoughtcrime.securesms.push.SignalServiceNetworkAccess;
|
||||
import org.thoughtcrime.securesms.service.MessageRetrievalService;
|
||||
@ -45,7 +45,6 @@ import dagger.Provides;
|
||||
|
||||
@Module(complete = false, injects = {CleanPreKeysJob.class,
|
||||
CreateSignedPreKeyJob.class,
|
||||
DeliveryReceiptJob.class,
|
||||
PushGroupSendJob.class,
|
||||
PushTextSendJob.class,
|
||||
PushMediaSendJob.class,
|
||||
@ -69,48 +68,56 @@ import dagger.Provides;
|
||||
MultiDeviceVerifiedUpdateJob.class,
|
||||
CreateProfileActivity.class,
|
||||
RetrieveProfileAvatarJob.class,
|
||||
MultiDeviceProfileKeyUpdateJob.class})
|
||||
MultiDeviceProfileKeyUpdateJob.class,
|
||||
SendReadReceiptJob.class})
|
||||
public class SignalCommunicationModule {
|
||||
|
||||
private final Context context;
|
||||
private final SignalServiceNetworkAccess networkAccess;
|
||||
|
||||
private SignalServiceAccountManager accountManager;
|
||||
private SignalServiceMessageSender messageSender;
|
||||
private SignalServiceMessageReceiver messageReceiver;
|
||||
|
||||
public SignalCommunicationModule(Context context, SignalServiceNetworkAccess networkAccess) {
|
||||
this.context = context;
|
||||
this.networkAccess = networkAccess;
|
||||
}
|
||||
|
||||
@Provides SignalServiceAccountManager provideSignalAccountManager() {
|
||||
return new SignalServiceAccountManager(networkAccess.getConfiguration(context),
|
||||
TextSecurePreferences.getLocalNumber(context),
|
||||
TextSecurePreferences.getPushServerPassword(context),
|
||||
@Provides
|
||||
synchronized SignalServiceAccountManager provideSignalAccountManager() {
|
||||
if (this.accountManager == null) {
|
||||
this.accountManager = new SignalServiceAccountManager(networkAccess.getConfiguration(context),
|
||||
new DynamicCredentialsProvider(context),
|
||||
BuildConfig.USER_AGENT);
|
||||
}
|
||||
|
||||
return this.accountManager;
|
||||
}
|
||||
|
||||
@Provides
|
||||
SignalMessageSenderFactory provideSignalMessageSenderFactory() {
|
||||
return new SignalMessageSenderFactory() {
|
||||
@Override
|
||||
public SignalServiceMessageSender create() {
|
||||
return new SignalServiceMessageSender(networkAccess.getConfiguration(context),
|
||||
TextSecurePreferences.getLocalNumber(context),
|
||||
TextSecurePreferences.getPushServerPassword(context),
|
||||
synchronized SignalServiceMessageSender provideSignalMessageSender() {
|
||||
if (this.messageSender == null) {
|
||||
this.messageSender = new SignalServiceMessageSender(networkAccess.getConfiguration(context),
|
||||
new DynamicCredentialsProvider(context),
|
||||
new SignalProtocolStoreImpl(context),
|
||||
BuildConfig.USER_AGENT,
|
||||
Optional.fromNullable(MessageRetrievalService.getPipe()),
|
||||
Optional.<SignalServiceMessageSender.EventListener>of(new SecurityEventListener(context)));
|
||||
}
|
||||
};
|
||||
|
||||
return this.messageSender;
|
||||
}
|
||||
|
||||
@Provides SignalServiceMessageReceiver provideSignalMessageReceiver() {
|
||||
return new SignalServiceMessageReceiver(networkAccess.getConfiguration(context),
|
||||
@Provides
|
||||
synchronized SignalServiceMessageReceiver provideSignalMessageReceiver() {
|
||||
if (this.messageReceiver == null) {
|
||||
this.messageReceiver = new SignalServiceMessageReceiver(networkAccess.getConfiguration(context),
|
||||
new DynamicCredentialsProvider(context),
|
||||
BuildConfig.USER_AGENT);
|
||||
}
|
||||
|
||||
public static interface SignalMessageSenderFactory {
|
||||
public SignalServiceMessageSender create();
|
||||
return this.messageReceiver;
|
||||
}
|
||||
|
||||
private static class DynamicCredentialsProvider implements CredentialsProvider {
|
||||
|
@ -30,11 +30,9 @@ public class GcmBroadcastReceiver extends WakefulBroadcastReceiver {
|
||||
return;
|
||||
}
|
||||
|
||||
String messageData = intent.getStringExtra("message");
|
||||
String receiptData = intent.getStringExtra("receipt");
|
||||
|
||||
if (!TextUtils.isEmpty(messageData)) handleReceivedMessage(context, messageData);
|
||||
else if (!TextUtils.isEmpty(receiptData)) handleReceivedMessage(context, receiptData);
|
||||
if (!TextUtils.isEmpty(receiptData)) handleReceivedMessage(context, receiptData);
|
||||
else if (intent.hasExtra("notification")) handleReceivedNotification(context);
|
||||
}
|
||||
}
|
||||
|
@ -1,71 +0,0 @@
|
||||
package org.thoughtcrime.securesms.jobs;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
|
||||
|
||||
import org.thoughtcrime.securesms.dependencies.InjectableType;
|
||||
import org.whispersystems.jobqueue.JobParameters;
|
||||
import org.whispersystems.jobqueue.requirements.NetworkRequirement;
|
||||
import org.whispersystems.libsignal.util.guava.Optional;
|
||||
import org.whispersystems.signalservice.api.SignalServiceMessageSender;
|
||||
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
||||
import org.whispersystems.signalservice.api.push.exceptions.NonSuccessfulResponseCodeException;
|
||||
import org.whispersystems.signalservice.api.push.exceptions.PushNetworkException;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import static org.thoughtcrime.securesms.dependencies.SignalCommunicationModule.SignalMessageSenderFactory;
|
||||
|
||||
public class DeliveryReceiptJob extends ContextJob implements InjectableType {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private static final String TAG = DeliveryReceiptJob.class.getSimpleName();
|
||||
|
||||
@Inject transient SignalMessageSenderFactory messageSenderFactory;
|
||||
|
||||
private final String destination;
|
||||
private final long timestamp;
|
||||
private final String relay;
|
||||
|
||||
public DeliveryReceiptJob(Context context, String destination, long timestamp, String relay) {
|
||||
super(context, JobParameters.newBuilder()
|
||||
.withRequirement(new NetworkRequirement(context))
|
||||
.withPersistence()
|
||||
.withRetryCount(50)
|
||||
.create());
|
||||
|
||||
this.destination = destination;
|
||||
this.timestamp = timestamp;
|
||||
this.relay = relay;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAdded() {}
|
||||
|
||||
@Override
|
||||
public void onRun() throws IOException {
|
||||
Log.w("DeliveryReceiptJob", "Sending delivery receipt...");
|
||||
SignalServiceMessageSender messageSender = messageSenderFactory.create();
|
||||
SignalServiceAddress textSecureAddress = new SignalServiceAddress(destination, Optional.fromNullable(relay));
|
||||
|
||||
messageSender.sendDeliveryReceipt(textSecureAddress, timestamp);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCanceled() {
|
||||
Log.w(TAG, "Failed to send receipt after retry exhausted!");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onShouldRetry(Exception exception) {
|
||||
Log.w(TAG, exception);
|
||||
if (exception instanceof NonSuccessfulResponseCodeException) return false;
|
||||
if (exception instanceof PushNetworkException) return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
@ -7,7 +7,6 @@ import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||
import org.thoughtcrime.securesms.database.RecipientDatabase;
|
||||
import org.thoughtcrime.securesms.database.RecipientDatabase.BlockedReader;
|
||||
import org.thoughtcrime.securesms.dependencies.InjectableType;
|
||||
import org.thoughtcrime.securesms.dependencies.SignalCommunicationModule.SignalMessageSenderFactory;
|
||||
import org.thoughtcrime.securesms.jobs.requirements.MasterSecretRequirement;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.whispersystems.jobqueue.JobParameters;
|
||||
@ -30,7 +29,7 @@ public class MultiDeviceBlockedUpdateJob extends MasterSecretJob implements Inje
|
||||
|
||||
private static final String TAG = MultiDeviceBlockedUpdateJob.class.getSimpleName();
|
||||
|
||||
@Inject transient SignalMessageSenderFactory messageSenderFactory;
|
||||
@Inject transient SignalServiceMessageSender messageSender;
|
||||
|
||||
public MultiDeviceBlockedUpdateJob(Context context) {
|
||||
super(context, JobParameters.newBuilder()
|
||||
@ -46,7 +45,6 @@ public class MultiDeviceBlockedUpdateJob extends MasterSecretJob implements Inje
|
||||
throws IOException, UntrustedIdentityException
|
||||
{
|
||||
RecipientDatabase database = DatabaseFactory.getRecipientDatabase(context);
|
||||
SignalServiceMessageSender messageSender = messageSenderFactory.create();
|
||||
BlockedReader reader = database.readerForBlocked(database.getBlocked());
|
||||
List<String> blocked = new LinkedList<>();
|
||||
|
||||
|
@ -18,7 +18,6 @@ import org.thoughtcrime.securesms.database.Address;
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||
import org.thoughtcrime.securesms.database.IdentityDatabase;
|
||||
import org.thoughtcrime.securesms.dependencies.InjectableType;
|
||||
import org.thoughtcrime.securesms.dependencies.SignalCommunicationModule.SignalMessageSenderFactory;
|
||||
import org.thoughtcrime.securesms.jobs.requirements.MasterSecretRequirement;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.util.Base64;
|
||||
@ -54,7 +53,7 @@ public class MultiDeviceContactUpdateJob extends MasterSecretJob implements Inje
|
||||
|
||||
private static final String TAG = MultiDeviceContactUpdateJob.class.getSimpleName();
|
||||
|
||||
@Inject transient SignalMessageSenderFactory messageSenderFactory;
|
||||
@Inject transient SignalServiceMessageSender messageSender;
|
||||
|
||||
private final @Nullable String address;
|
||||
|
||||
@ -90,7 +89,6 @@ public class MultiDeviceContactUpdateJob extends MasterSecretJob implements Inje
|
||||
private void generateSingleContactUpdate(@NonNull Address address)
|
||||
throws IOException, UntrustedIdentityException, NetworkException
|
||||
{
|
||||
SignalServiceMessageSender messageSender = messageSenderFactory.create();
|
||||
File contactDataFile = createTempFile("multidevice-contact-update");
|
||||
|
||||
try {
|
||||
@ -119,7 +117,6 @@ public class MultiDeviceContactUpdateJob extends MasterSecretJob implements Inje
|
||||
private void generateFullContactUpdate()
|
||||
throws IOException, UntrustedIdentityException, NetworkException
|
||||
{
|
||||
SignalServiceMessageSender messageSender = messageSenderFactory.create();
|
||||
File contactDataFile = createTempFile("multidevice-contact-update");
|
||||
|
||||
try {
|
||||
|
@ -9,7 +9,6 @@ import org.thoughtcrime.securesms.database.Address;
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||
import org.thoughtcrime.securesms.database.GroupDatabase;
|
||||
import org.thoughtcrime.securesms.dependencies.InjectableType;
|
||||
import org.thoughtcrime.securesms.dependencies.SignalCommunicationModule;
|
||||
import org.thoughtcrime.securesms.jobs.requirements.MasterSecretRequirement;
|
||||
import org.whispersystems.jobqueue.JobParameters;
|
||||
import org.whispersystems.jobqueue.requirements.NetworkRequirement;
|
||||
@ -38,8 +37,7 @@ public class MultiDeviceGroupUpdateJob extends MasterSecretJob implements Inject
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final String TAG = MultiDeviceGroupUpdateJob.class.getSimpleName();
|
||||
|
||||
@Inject
|
||||
transient SignalCommunicationModule.SignalMessageSenderFactory messageSenderFactory;
|
||||
@Inject transient SignalServiceMessageSender messageSender;
|
||||
|
||||
public MultiDeviceGroupUpdateJob(Context context) {
|
||||
super(context, JobParameters.newBuilder()
|
||||
@ -52,7 +50,6 @@ public class MultiDeviceGroupUpdateJob extends MasterSecretJob implements Inject
|
||||
|
||||
@Override
|
||||
public void onRun(MasterSecret masterSecret) throws Exception {
|
||||
SignalServiceMessageSender messageSender = messageSenderFactory.create();
|
||||
File contactDataFile = createTempFile("multidevice-contact-update");
|
||||
GroupDatabase.Reader reader = null;
|
||||
|
||||
|
@ -7,11 +7,11 @@ import android.util.Log;
|
||||
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
||||
import org.thoughtcrime.securesms.crypto.ProfileKeyUtil;
|
||||
import org.thoughtcrime.securesms.dependencies.InjectableType;
|
||||
import org.thoughtcrime.securesms.dependencies.SignalCommunicationModule.SignalMessageSenderFactory;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
import org.whispersystems.jobqueue.JobParameters;
|
||||
import org.whispersystems.jobqueue.requirements.NetworkRequirement;
|
||||
import org.whispersystems.libsignal.util.guava.Optional;
|
||||
import org.whispersystems.signalservice.api.SignalServiceMessageSender;
|
||||
import org.whispersystems.signalservice.api.crypto.UntrustedIdentityException;
|
||||
import org.whispersystems.signalservice.api.messages.SignalServiceAttachment;
|
||||
import org.whispersystems.signalservice.api.messages.SignalServiceAttachmentStream;
|
||||
@ -33,7 +33,7 @@ public class MultiDeviceProfileKeyUpdateJob extends MasterSecretJob implements I
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final String TAG = MultiDeviceProfileKeyUpdateJob.class.getSimpleName();
|
||||
|
||||
@Inject SignalMessageSenderFactory messageSender;
|
||||
@Inject transient SignalServiceMessageSender messageSender;
|
||||
|
||||
public MultiDeviceProfileKeyUpdateJob(Context context) {
|
||||
super(context, JobParameters.newBuilder()
|
||||
@ -71,7 +71,7 @@ public class MultiDeviceProfileKeyUpdateJob extends MasterSecretJob implements I
|
||||
|
||||
SignalServiceSyncMessage syncMessage = SignalServiceSyncMessage.forContacts(new ContactsMessage(attachmentStream, false));
|
||||
|
||||
messageSender.create().sendMessage(syncMessage);
|
||||
messageSender.sendMessage(syncMessage);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -6,7 +6,6 @@ import android.util.Log;
|
||||
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
||||
import org.thoughtcrime.securesms.database.MessagingDatabase.SyncMessageId;
|
||||
import org.thoughtcrime.securesms.dependencies.InjectableType;
|
||||
import org.thoughtcrime.securesms.dependencies.SignalCommunicationModule;
|
||||
import org.thoughtcrime.securesms.jobs.requirements.MasterSecretRequirement;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
import org.whispersystems.jobqueue.JobParameters;
|
||||
@ -31,8 +30,7 @@ public class MultiDeviceReadUpdateJob extends MasterSecretJob implements Injecta
|
||||
|
||||
private final List<SerializableSyncMessageId> messageIds;
|
||||
|
||||
@Inject
|
||||
transient SignalCommunicationModule.SignalMessageSenderFactory messageSenderFactory;
|
||||
@Inject transient SignalServiceMessageSender messageSender;
|
||||
|
||||
public MultiDeviceReadUpdateJob(Context context, List<SyncMessageId> messageIds) {
|
||||
super(context, JobParameters.newBuilder()
|
||||
@ -62,7 +60,6 @@ public class MultiDeviceReadUpdateJob extends MasterSecretJob implements Injecta
|
||||
readMessages.add(new ReadMessage(messageId.sender, messageId.timestamp));
|
||||
}
|
||||
|
||||
SignalServiceMessageSender messageSender = messageSenderFactory.create();
|
||||
messageSender.sendMessage(SignalServiceSyncMessage.forRead(readMessages));
|
||||
}
|
||||
|
||||
|
@ -7,7 +7,6 @@ import android.util.Log;
|
||||
import org.thoughtcrime.securesms.database.Address;
|
||||
import org.thoughtcrime.securesms.database.IdentityDatabase.VerifiedStatus;
|
||||
import org.thoughtcrime.securesms.dependencies.InjectableType;
|
||||
import org.thoughtcrime.securesms.dependencies.SignalCommunicationModule;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
import org.whispersystems.jobqueue.JobParameters;
|
||||
import org.whispersystems.jobqueue.requirements.NetworkRequirement;
|
||||
@ -30,7 +29,7 @@ public class MultiDeviceVerifiedUpdateJob extends ContextJob implements Injectab
|
||||
private static final String TAG = MultiDeviceVerifiedUpdateJob.class.getSimpleName();
|
||||
|
||||
@Inject
|
||||
transient SignalCommunicationModule.SignalMessageSenderFactory messageSenderFactory;
|
||||
transient SignalServiceMessageSender messageSender;
|
||||
|
||||
private final String destination;
|
||||
private final byte[] identityKey;
|
||||
@ -65,7 +64,6 @@ public class MultiDeviceVerifiedUpdateJob extends ContextJob implements Injectab
|
||||
|
||||
Address canonicalDestination = Address.fromSerialized(destination);
|
||||
VerifiedMessage.VerifiedState verifiedState = getVerifiedState(verifiedStatus);
|
||||
SignalServiceMessageSender messageSender = messageSenderFactory.create();
|
||||
VerifiedMessage verifiedMessage = new VerifiedMessage(canonicalDestination.toPhoneString(), new IdentityKey(identityKey, 0), verifiedState, timestamp);
|
||||
|
||||
messageSender.sendMessage(SignalServiceSyncMessage.forVerified(verifiedMessage));
|
||||
|
@ -39,7 +39,7 @@ public class PushContentReceiveJob extends PushReceivedJob {
|
||||
String sessionKey = TextSecurePreferences.getSignalingKey(context);
|
||||
SignalServiceEnvelope envelope = new SignalServiceEnvelope(data, sessionKey);
|
||||
|
||||
handle(envelope, true);
|
||||
handle(envelope);
|
||||
} catch (IOException | InvalidVersionException e) {
|
||||
Log.w(TAG, e);
|
||||
}
|
||||
|
@ -68,6 +68,7 @@ import org.whispersystems.signalservice.api.messages.SignalServiceContent;
|
||||
import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage;
|
||||
import org.whispersystems.signalservice.api.messages.SignalServiceEnvelope;
|
||||
import org.whispersystems.signalservice.api.messages.SignalServiceGroup;
|
||||
import org.whispersystems.signalservice.api.messages.SignalServiceReceiptMessage;
|
||||
import org.whispersystems.signalservice.api.messages.calls.AnswerMessage;
|
||||
import org.whispersystems.signalservice.api.messages.calls.BusyMessage;
|
||||
import org.whispersystems.signalservice.api.messages.calls.HangupMessage;
|
||||
@ -186,6 +187,11 @@ public class PushDecryptJob extends ContextJob {
|
||||
else if (message.getIceUpdateMessages().isPresent()) handleCallIceUpdateMessage(envelope, message.getIceUpdateMessages().get());
|
||||
else if (message.getHangupMessage().isPresent()) handleCallHangupMessage(envelope, message.getHangupMessage().get(), smsMessageId);
|
||||
else if (message.getBusyMessage().isPresent()) handleCallBusyMessage(envelope, message.getBusyMessage().get());
|
||||
} else if (content.getReceiptMessage().isPresent()) {
|
||||
SignalServiceReceiptMessage message = content.getReceiptMessage().get();
|
||||
|
||||
if (message.isReadReceipt()) handleReadReceipt(envelope, message);
|
||||
else if (message.isDeliveryReceipt()) handleDeliveryReceipt(envelope, message);
|
||||
} else {
|
||||
Log.w(TAG, "Got unrecognized message...");
|
||||
}
|
||||
@ -824,6 +830,29 @@ public class PushDecryptJob extends ContextJob {
|
||||
}
|
||||
}
|
||||
|
||||
private void handleDeliveryReceipt(@NonNull SignalServiceEnvelope envelope,
|
||||
@NonNull SignalServiceReceiptMessage message)
|
||||
{
|
||||
for (long timestamp : message.getTimestamps()) {
|
||||
Log.w(TAG, String.format("Received encrypted delivery receipt: (XXXXX, %d)", timestamp));
|
||||
DatabaseFactory.getMmsSmsDatabase(context)
|
||||
.incrementDeliveryReceiptCount(new SyncMessageId(Address.fromExternal(context, envelope.getSource()), timestamp));
|
||||
}
|
||||
}
|
||||
|
||||
private void handleReadReceipt(@NonNull SignalServiceEnvelope envelope,
|
||||
@NonNull SignalServiceReceiptMessage message)
|
||||
{
|
||||
if (TextSecurePreferences.isReadReceiptsEnabled(context)) {
|
||||
for (long timestamp : message.getTimestamps()) {
|
||||
Log.w(TAG, String.format("Received encrypted read receipt: (XXXXX, %d)", timestamp));
|
||||
|
||||
DatabaseFactory.getMmsSmsDatabase(context)
|
||||
.incrementReadReceiptCount(new SyncMessageId(Address.fromExternal(context, envelope.getSource()), timestamp));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Optional<InsertResult> insertPlaceholder(@NonNull SignalServiceEnvelope envelope) {
|
||||
EncryptingSmsDatabase database = DatabaseFactory.getEncryptingSmsDatabase(context);
|
||||
IncomingTextMessage textMessage = new IncomingTextMessage(Address.fromExternal(context, envelope.getSource()),
|
||||
|
@ -43,15 +43,13 @@ import java.util.List;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import static org.thoughtcrime.securesms.dependencies.SignalCommunicationModule.SignalMessageSenderFactory;
|
||||
|
||||
public class PushGroupSendJob extends PushSendJob implements InjectableType {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private static final String TAG = PushGroupSendJob.class.getSimpleName();
|
||||
|
||||
@Inject transient SignalMessageSenderFactory messageSenderFactory;
|
||||
@Inject transient SignalServiceMessageSender messageSender;
|
||||
|
||||
private final long messageId;
|
||||
private final long filterRecipientId; // Deprecated
|
||||
@ -137,7 +135,6 @@ public class PushGroupSendJob extends PushSendJob implements InjectableType {
|
||||
throws IOException, RecipientFormattingException, InvalidNumberException,
|
||||
EncapsulatedExceptions, UndeliverableMessageException
|
||||
{
|
||||
SignalServiceMessageSender messageSender = messageSenderFactory.create();
|
||||
String groupId = message.getRecipient().getAddress().toGroupString();
|
||||
Optional<byte[]> profileKey = getProfileKey(message.getRecipient());
|
||||
List<Recipient> recipients = DatabaseFactory.getGroupDatabase(context).getGroupMembers(groupId, false);
|
||||
|
@ -9,7 +9,6 @@ import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||
import org.thoughtcrime.securesms.database.GroupDatabase;
|
||||
import org.thoughtcrime.securesms.database.GroupDatabase.GroupRecord;
|
||||
import org.thoughtcrime.securesms.dependencies.InjectableType;
|
||||
import org.thoughtcrime.securesms.dependencies.SignalCommunicationModule.SignalMessageSenderFactory;
|
||||
import org.thoughtcrime.securesms.util.GroupUtil;
|
||||
import org.whispersystems.jobqueue.JobParameters;
|
||||
import org.whispersystems.jobqueue.requirements.NetworkRequirement;
|
||||
@ -37,7 +36,7 @@ public class PushGroupUpdateJob extends ContextJob implements InjectableType {
|
||||
|
||||
private static final long serialVersionUID = 0L;
|
||||
|
||||
@Inject transient SignalMessageSenderFactory messageSenderFactory;
|
||||
@Inject transient SignalServiceMessageSender messageSender;
|
||||
|
||||
private final String source;
|
||||
private final byte[] groupId;
|
||||
@ -59,7 +58,6 @@ public class PushGroupUpdateJob extends ContextJob implements InjectableType {
|
||||
|
||||
@Override
|
||||
public void onRun() throws IOException, UntrustedIdentityException {
|
||||
SignalServiceMessageSender messageSender = messageSenderFactory.create();
|
||||
GroupDatabase groupDatabase = DatabaseFactory.getGroupDatabase(context);
|
||||
Optional<GroupRecord> record = groupDatabase.getGroup(GroupUtil.getEncodedId(groupId, false));
|
||||
SignalServiceAttachment avatar = null;
|
||||
|
@ -32,15 +32,13 @@ import java.util.List;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import static org.thoughtcrime.securesms.dependencies.SignalCommunicationModule.SignalMessageSenderFactory;
|
||||
|
||||
public class PushMediaSendJob extends PushSendJob implements InjectableType {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private static final String TAG = PushMediaSendJob.class.getSimpleName();
|
||||
|
||||
@Inject transient SignalMessageSenderFactory messageSenderFactory;
|
||||
@Inject transient SignalServiceMessageSender messageSender;
|
||||
|
||||
private final long messageId;
|
||||
|
||||
@ -107,8 +105,6 @@ public class PushMediaSendJob extends PushSendJob implements InjectableType {
|
||||
throw new UndeliverableMessageException("No destination address.");
|
||||
}
|
||||
|
||||
SignalServiceMessageSender messageSender = messageSenderFactory.create();
|
||||
|
||||
try {
|
||||
SignalServiceAddress address = getPushAddress(message.getRecipient().getAddress());
|
||||
MediaConstraints mediaConstraints = MediaConstraints.getPushMediaConstraints();
|
||||
|
@ -4,7 +4,6 @@ import android.content.Context;
|
||||
import android.util.Log;
|
||||
|
||||
import org.thoughtcrime.securesms.dependencies.InjectableType;
|
||||
import org.thoughtcrime.securesms.notifications.MessageNotifier;
|
||||
import org.whispersystems.jobqueue.JobParameters;
|
||||
import org.whispersystems.jobqueue.requirements.NetworkRequirement;
|
||||
import org.whispersystems.signalservice.api.SignalServiceMessageReceiver;
|
||||
@ -37,7 +36,7 @@ public class PushNotificationReceiveJob extends PushReceivedJob implements Injec
|
||||
receiver.retrieveMessages(new SignalServiceMessageReceiver.MessageReceivedCallback() {
|
||||
@Override
|
||||
public void onMessage(SignalServiceEnvelope envelope) {
|
||||
handle(envelope, false);
|
||||
handle(envelope);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -9,17 +9,12 @@ import org.thoughtcrime.securesms.database.Address;
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||
import org.thoughtcrime.securesms.database.MessagingDatabase.SyncMessageId;
|
||||
import org.thoughtcrime.securesms.database.RecipientDatabase;
|
||||
import org.thoughtcrime.securesms.database.RecipientDatabase.RecipientSettings;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.service.KeyCachingService;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
import org.whispersystems.jobqueue.JobManager;
|
||||
import org.whispersystems.jobqueue.JobParameters;
|
||||
import org.whispersystems.libsignal.util.guava.Optional;
|
||||
import org.whispersystems.signalservice.api.messages.SignalServiceEnvelope;
|
||||
|
||||
import java.util.LinkedList;
|
||||
|
||||
public abstract class PushReceivedJob extends ContextJob {
|
||||
|
||||
private static final String TAG = PushReceivedJob.class.getSimpleName();
|
||||
@ -28,7 +23,7 @@ public abstract class PushReceivedJob extends ContextJob {
|
||||
super(context, parameters);
|
||||
}
|
||||
|
||||
public void handle(SignalServiceEnvelope envelope, boolean sendExplicitReceipt) {
|
||||
public void handle(SignalServiceEnvelope envelope) {
|
||||
Address source = Address.fromExternal(context, envelope.getSource());
|
||||
Recipient recipient = Recipient.from(context, source, false);
|
||||
|
||||
@ -40,13 +35,13 @@ public abstract class PushReceivedJob extends ContextJob {
|
||||
if (envelope.isReceipt()) {
|
||||
handleReceipt(envelope);
|
||||
} else if (envelope.isPreKeySignalMessage() || envelope.isSignalMessage()) {
|
||||
handleMessage(envelope, source, sendExplicitReceipt);
|
||||
handleMessage(envelope, source);
|
||||
} else {
|
||||
Log.w(TAG, "Received envelope of unknown type: " + envelope.getType());
|
||||
}
|
||||
}
|
||||
|
||||
private void handleMessage(SignalServiceEnvelope envelope, Address source, boolean sendExplicitReceipt) {
|
||||
private void handleMessage(SignalServiceEnvelope envelope, Address source) {
|
||||
Recipient recipients = Recipient.from(context, source, false);
|
||||
JobManager jobManager = ApplicationContext.getInstance(context).getJobManager();
|
||||
|
||||
@ -56,12 +51,6 @@ public abstract class PushReceivedJob extends ContextJob {
|
||||
} else {
|
||||
Log.w(TAG, "*** Received blocked push message, ignoring...");
|
||||
}
|
||||
|
||||
if (sendExplicitReceipt) {
|
||||
jobManager.add(new DeliveryReceiptJob(context, envelope.getSource(),
|
||||
envelope.getTimestamp(),
|
||||
envelope.getRelay()));
|
||||
}
|
||||
}
|
||||
|
||||
private void handleReceipt(SignalServiceEnvelope envelope) {
|
||||
|
@ -27,15 +27,13 @@ import java.io.IOException;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import static org.thoughtcrime.securesms.dependencies.SignalCommunicationModule.SignalMessageSenderFactory;
|
||||
|
||||
public class PushTextSendJob extends PushSendJob implements InjectableType {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private static final String TAG = PushTextSendJob.class.getSimpleName();
|
||||
|
||||
@Inject transient SignalMessageSenderFactory messageSenderFactory;
|
||||
@Inject transient SignalServiceMessageSender messageSender;
|
||||
|
||||
private final long messageId;
|
||||
|
||||
@ -101,7 +99,6 @@ public class PushTextSendJob extends PushSendJob implements InjectableType {
|
||||
{
|
||||
try {
|
||||
SignalServiceAddress address = getPushAddress(message.getIndividualRecipient().getAddress());
|
||||
SignalServiceMessageSender messageSender = messageSenderFactory.create();
|
||||
Optional<byte[]> profileKey = getProfileKey(message.getIndividualRecipient());
|
||||
SignalServiceDataMessage textSecureMessage = SignalServiceDataMessage.newBuilder()
|
||||
.withTimestamp(message.getDateSent())
|
||||
|
@ -4,7 +4,6 @@ import android.content.Context;
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
import org.thoughtcrime.securesms.dependencies.InjectableType;
|
||||
import org.thoughtcrime.securesms.dependencies.SignalCommunicationModule.SignalMessageSenderFactory;
|
||||
import org.whispersystems.jobqueue.JobParameters;
|
||||
import org.whispersystems.jobqueue.requirements.NetworkRequirement;
|
||||
import org.whispersystems.signalservice.api.SignalServiceMessageSender;
|
||||
@ -25,7 +24,7 @@ public class RequestGroupInfoJob extends ContextJob implements InjectableType {
|
||||
|
||||
private static final long serialVersionUID = 0L;
|
||||
|
||||
@Inject transient SignalMessageSenderFactory messageSenderFactory;
|
||||
@Inject transient SignalServiceMessageSender messageSender;
|
||||
|
||||
private final String source;
|
||||
private final byte[] groupId;
|
||||
@ -46,8 +45,6 @@ public class RequestGroupInfoJob extends ContextJob implements InjectableType {
|
||||
|
||||
@Override
|
||||
public void onRun() throws IOException, UntrustedIdentityException {
|
||||
SignalServiceMessageSender messageSender = messageSenderFactory.create();
|
||||
|
||||
SignalServiceGroup group = SignalServiceGroup.newBuilder(Type.REQUEST_INFO)
|
||||
.withId(groupId)
|
||||
.build();
|
||||
|
69
src/org/thoughtcrime/securesms/jobs/SendReadReceiptJob.java
Normal file
69
src/org/thoughtcrime/securesms/jobs/SendReadReceiptJob.java
Normal file
@ -0,0 +1,69 @@
|
||||
package org.thoughtcrime.securesms.jobs;
|
||||
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
|
||||
import org.thoughtcrime.securesms.database.Address;
|
||||
import org.thoughtcrime.securesms.dependencies.InjectableType;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
import org.whispersystems.jobqueue.JobParameters;
|
||||
import org.whispersystems.jobqueue.requirements.NetworkRequirement;
|
||||
import org.whispersystems.signalservice.api.SignalServiceMessageSender;
|
||||
import org.whispersystems.signalservice.api.crypto.UntrustedIdentityException;
|
||||
import org.whispersystems.signalservice.api.messages.SignalServiceReceiptMessage;
|
||||
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
||||
import org.whispersystems.signalservice.api.push.exceptions.PushNetworkException;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
public class SendReadReceiptJob extends ContextJob implements InjectableType {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private static final String TAG = SendReadReceiptJob.class.getSimpleName();
|
||||
|
||||
@Inject transient SignalServiceMessageSender messageSender;
|
||||
|
||||
private final String address;
|
||||
private final List<Long> messageIds;
|
||||
private final long timestamp;
|
||||
|
||||
public SendReadReceiptJob(Context context, Address address, List<Long> messageIds) {
|
||||
super(context, JobParameters.newBuilder()
|
||||
.withRequirement(new NetworkRequirement(context))
|
||||
.withPersistence()
|
||||
.create());
|
||||
|
||||
this.address = address.serialize();
|
||||
this.messageIds = messageIds;
|
||||
this.timestamp = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAdded() {}
|
||||
|
||||
@Override
|
||||
public void onRun() throws IOException, UntrustedIdentityException {
|
||||
if (!TextSecurePreferences.isReadReceiptsEnabled(context)) return;
|
||||
|
||||
SignalServiceAddress remoteAddress = new SignalServiceAddress(address);
|
||||
SignalServiceReceiptMessage receiptMessage = new SignalServiceReceiptMessage(SignalServiceReceiptMessage.Type.READ, messageIds, timestamp);
|
||||
|
||||
messageSender.sendReceipt(remoteAddress, receiptMessage);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onShouldRetry(Exception e) {
|
||||
if (e instanceof PushNetworkException) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCanceled() {
|
||||
Log.w(TAG, "Failed to send read receipts to: " + address);
|
||||
}
|
||||
}
|
@ -8,17 +8,23 @@ import android.support.annotation.Nullable;
|
||||
import android.support.v4.app.NotificationManagerCompat;
|
||||
import android.util.Log;
|
||||
|
||||
import com.annimon.stream.Collectors;
|
||||
import com.annimon.stream.Stream;
|
||||
|
||||
import org.thoughtcrime.securesms.ApplicationContext;
|
||||
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
||||
import org.thoughtcrime.securesms.database.Address;
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||
import org.thoughtcrime.securesms.database.MessagingDatabase.ExpirationInfo;
|
||||
import org.thoughtcrime.securesms.database.MessagingDatabase.MarkedMessageInfo;
|
||||
import org.thoughtcrime.securesms.database.MessagingDatabase.SyncMessageId;
|
||||
import org.thoughtcrime.securesms.jobs.MultiDeviceReadUpdateJob;
|
||||
import org.thoughtcrime.securesms.jobs.SendReadReceiptJob;
|
||||
import org.thoughtcrime.securesms.service.ExpiringMessageManager;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class MarkReadReceiver extends MasterSecretBroadcastReceiver {
|
||||
|
||||
@ -72,6 +78,18 @@ public class MarkReadReceiver extends MasterSecretBroadcastReceiver {
|
||||
ApplicationContext.getInstance(context)
|
||||
.getJobManager()
|
||||
.add(new MultiDeviceReadUpdateJob(context, syncMessageIds));
|
||||
|
||||
Map<Address, List<SyncMessageId>> addressMap = Stream.of(markedReadMessages)
|
||||
.map(MarkedMessageInfo::getSyncMessageId)
|
||||
.collect(Collectors.groupingBy(SyncMessageId::getAddress));
|
||||
|
||||
for (Address address : addressMap.keySet()) {
|
||||
List<Long> timestamps = Stream.of(addressMap.get(address)).map(SyncMessageId::getTimetamp).toList();
|
||||
|
||||
ApplicationContext.getInstance(context)
|
||||
.getJobManager()
|
||||
.add(new SendReadReceiptJob(context, address, timestamps));
|
||||
}
|
||||
}
|
||||
|
||||
private static void scheduleDeletion(Context context, ExpirationInfo expirationInfo) {
|
||||
|
@ -214,7 +214,7 @@ public class MessageRetrievalService extends Service implements InjectableType,
|
||||
Log.w(TAG, "Retrieved envelope! " + envelope.getSource());
|
||||
|
||||
PushContentReceiveJob receiveJob = new PushContentReceiveJob(MessageRetrievalService.this);
|
||||
receiveJob.handle(envelope, false);
|
||||
receiveJob.handle(envelope);
|
||||
|
||||
decrementPushReceived();
|
||||
}
|
||||
|
@ -29,7 +29,6 @@ import org.thoughtcrime.securesms.contacts.ContactAccessor;
|
||||
import org.thoughtcrime.securesms.database.Address;
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||
import org.thoughtcrime.securesms.dependencies.InjectableType;
|
||||
import org.thoughtcrime.securesms.dependencies.SignalCommunicationModule.SignalMessageSenderFactory;
|
||||
import org.thoughtcrime.securesms.events.WebRtcViewModel;
|
||||
import org.thoughtcrime.securesms.notifications.MessageNotifier;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
@ -148,10 +147,9 @@ public class WebRtcCallService extends Service implements InjectableType, PeerCo
|
||||
private boolean remoteVideoEnabled = false;
|
||||
private boolean bluetoothAvailable = false;
|
||||
|
||||
@Inject public SignalMessageSenderFactory messageSenderFactory;
|
||||
@Inject public SignalServiceMessageSender messageSender;
|
||||
@Inject public SignalServiceAccountManager accountManager;
|
||||
|
||||
private SignalServiceMessageSender messageSender;
|
||||
private PeerConnectionFactory peerConnectionFactory;
|
||||
private SignalAudioManager audioManager;
|
||||
private BluetoothStateManager bluetoothStateManager;
|
||||
@ -271,7 +269,6 @@ public class WebRtcCallService extends Service implements InjectableType, PeerCo
|
||||
this.peerConnectionFactory = new PeerConnectionFactory(new PeerConnectionFactoryOptions());
|
||||
this.audioManager = new SignalAudioManager(this);
|
||||
this.bluetoothStateManager = new BluetoothStateManager(this, this);
|
||||
this.messageSender = messageSenderFactory.create();
|
||||
this.messageSender.setSoTimeoutMillis(TimeUnit.SECONDS.toMillis(10));
|
||||
this.accountManager.setSoTimeoutMillis(TimeUnit.SECONDS.toMillis(10));
|
||||
}
|
||||
|
@ -113,6 +113,15 @@ public class TextSecurePreferences {
|
||||
private static final String ALWAYS_RELAY_CALLS_PREF = "pref_turn_only";
|
||||
private static final String PROFILE_KEY_PREF = "pref_profile_key";
|
||||
private static final String PROFILE_NAME_PREF = "pref_profile_name";
|
||||
private static final String READ_RECEIPTS_PREF = "pref_read_receipts";
|
||||
|
||||
public static boolean isReadReceiptsEnabled(Context context) {
|
||||
return getBooleanPreference(context, READ_RECEIPTS_PREF, false);
|
||||
}
|
||||
|
||||
public static void setReadReceiptsEnabled(Context context, boolean enabled) {
|
||||
setBooleanPreference(context, READ_RECEIPTS_PREF, enabled);
|
||||
}
|
||||
|
||||
public static @Nullable String getProfileKey(Context context) {
|
||||
return getStringPreference(context, PROFILE_KEY_PREF, null);
|
||||
|
@ -1,104 +0,0 @@
|
||||
package org.thoughtcrime.securesms.jobs;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Mockito;
|
||||
import org.thoughtcrime.securesms.BaseUnitTest;
|
||||
import org.thoughtcrime.securesms.dependencies.SignalCommunicationModule.SignalMessageSenderFactory;
|
||||
import org.whispersystems.signalservice.api.SignalServiceMessageSender;
|
||||
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
||||
import org.whispersystems.signalservice.api.push.exceptions.NotFoundException;
|
||||
import org.whispersystems.signalservice.api.push.exceptions.PushNetworkException;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import dagger.Module;
|
||||
import dagger.ObjectGraph;
|
||||
import dagger.Provides;
|
||||
|
||||
import static junit.framework.Assert.assertFalse;
|
||||
import static junit.framework.Assert.assertTrue;
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Matchers.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
public class DeliveryReceiptJobTest extends BaseUnitTest {
|
||||
@Test
|
||||
public void testDelivery() throws IOException {
|
||||
SignalServiceMessageSender textSecureMessageSender = mock(SignalServiceMessageSender.class);
|
||||
long timestamp = System.currentTimeMillis();
|
||||
|
||||
DeliveryReceiptJob deliveryReceiptJob = new DeliveryReceiptJob(context,
|
||||
"+14152222222",
|
||||
timestamp, "foo");
|
||||
|
||||
ObjectGraph objectGraph = ObjectGraph.create(new TestModule(textSecureMessageSender));
|
||||
objectGraph.inject(deliveryReceiptJob);
|
||||
|
||||
deliveryReceiptJob.onRun();
|
||||
|
||||
ArgumentCaptor<SignalServiceAddress> captor = ArgumentCaptor.forClass(SignalServiceAddress.class);
|
||||
verify(textSecureMessageSender).sendDeliveryReceipt(captor.capture(), eq(timestamp));
|
||||
|
||||
assertTrue(captor.getValue().getRelay().get().equals("foo"));
|
||||
assertTrue(captor.getValue().getNumber().equals("+14152222222"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNetworkError() throws IOException {
|
||||
SignalServiceMessageSender textSecureMessageSender = mock(SignalServiceMessageSender.class);
|
||||
long timestamp = System.currentTimeMillis();
|
||||
|
||||
Mockito.doThrow(new PushNetworkException("network error"))
|
||||
.when(textSecureMessageSender)
|
||||
.sendDeliveryReceipt(any(SignalServiceAddress.class), eq(timestamp));
|
||||
|
||||
|
||||
DeliveryReceiptJob deliveryReceiptJob = new DeliveryReceiptJob(context,
|
||||
"+14152222222",
|
||||
timestamp, "foo");
|
||||
|
||||
ObjectGraph objectGraph = ObjectGraph.create(new TestModule(textSecureMessageSender));
|
||||
objectGraph.inject(deliveryReceiptJob);
|
||||
|
||||
try {
|
||||
deliveryReceiptJob.onRun();
|
||||
throw new AssertionError();
|
||||
} catch (IOException e) {
|
||||
assertTrue(deliveryReceiptJob.onShouldRetry(e));
|
||||
}
|
||||
|
||||
Mockito.doThrow(new NotFoundException("not found"))
|
||||
.when(textSecureMessageSender)
|
||||
.sendDeliveryReceipt(any(SignalServiceAddress.class), eq(timestamp));
|
||||
|
||||
try {
|
||||
deliveryReceiptJob.onRun();
|
||||
throw new AssertionError();
|
||||
} catch (IOException e) {
|
||||
assertFalse(deliveryReceiptJob.onShouldRetry(e));
|
||||
}
|
||||
}
|
||||
|
||||
@Module(injects = DeliveryReceiptJob.class)
|
||||
public static class TestModule {
|
||||
|
||||
private final SignalServiceMessageSender textSecureMessageSender;
|
||||
|
||||
public TestModule(SignalServiceMessageSender textSecureMessageSender) {
|
||||
this.textSecureMessageSender = textSecureMessageSender;
|
||||
}
|
||||
|
||||
@Provides
|
||||
SignalMessageSenderFactory provideSignalServiceMessageSenderFactory() {
|
||||
return new SignalMessageSenderFactory() {
|
||||
@Override
|
||||
public SignalServiceMessageSender create() {
|
||||
return textSecureMessageSender;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user