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:jobmanager:1.0.2'
|
||||||
compile 'org.whispersystems:libpastelog:1.0.7'
|
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 'org.whispersystems:webrtc-android:M59-S1'
|
||||||
|
|
||||||
compile "me.leolin:ShortcutBadger:1.1.16"
|
compile "me.leolin:ShortcutBadger:1.1.16"
|
||||||
@ -138,7 +138,7 @@ dependencyVerification {
|
|||||||
'com.google.android.exoplayer:exoplayer:955085aa611a8f7cf6c61b88ae03d1a392f4ad94c9bfbc153f3dedb9ffb14718',
|
'com.google.android.exoplayer:exoplayer:955085aa611a8f7cf6c61b88ae03d1a392f4ad94c9bfbc153f3dedb9ffb14718',
|
||||||
'org.whispersystems:jobmanager:506f679fc2fcf7bb6d10f00f41d6f6ea0abf75c70dc95b913398661ad538a181',
|
'org.whispersystems:jobmanager:506f679fc2fcf7bb6d10f00f41d6f6ea0abf75c70dc95b913398661ad538a181',
|
||||||
'org.whispersystems:libpastelog:bb331d9a98240fc139101128ba836c1edec3c40e000597cdbb29ebf4cbf34d88',
|
'org.whispersystems:libpastelog:bb331d9a98240fc139101128ba836c1edec3c40e000597cdbb29ebf4cbf34d88',
|
||||||
'org.whispersystems:signal-service-android:690e04d53c8b5ec8cda064b242d7c00b0e5321851b811798dd0ec3712f5e1a85',
|
'org.whispersystems:signal-service-android:731fc8c45f38f42b2d0da1053cf32adcd175708e0c126571150690637108971a',
|
||||||
'org.whispersystems:webrtc-android:de647643afbbea45a26a4f24db75aa10bc8de45426e8eb0d9d563cc10af4f582',
|
'org.whispersystems:webrtc-android:de647643afbbea45a26a4f24db75aa10bc8de45426e8eb0d9d563cc10af4f582',
|
||||||
'me.leolin:ShortcutBadger:e3cb3e7625892129b0c92dd5e4bc649faffdd526d5af26d9c45ee31ff8851774',
|
'me.leolin:ShortcutBadger:e3cb3e7625892129b0c92dd5e4bc649faffdd526d5af26d9c45ee31ff8851774',
|
||||||
'se.emilsjolander:stickylistheaders:a08ca948aa6b220f09d82f16bbbac395f6b78897e9eeac6a9f0b0ba755928eeb',
|
'se.emilsjolander:stickylistheaders:a08ca948aa6b220f09d82f16bbbac395f6b78897e9eeac6a9f0b0ba755928eeb',
|
||||||
@ -173,7 +173,7 @@ dependencyVerification {
|
|||||||
'com.google.android.gms:play-services-basement:95dd882c5ffba15b9a99de3fefb05d3a01946623af67454ca00055d222f85a8d',
|
'com.google.android.gms:play-services-basement:95dd882c5ffba15b9a99de3fefb05d3a01946623af67454ca00055d222f85a8d',
|
||||||
'com.google.android.gms:play-services-iid:54e919f9957b8b7820da7ee9b83471d00d0cac1cf08ddea8b5b41aea80bb1a70',
|
'com.google.android.gms:play-services-iid:54e919f9957b8b7820da7ee9b83471d00d0cac1cf08ddea8b5b41aea80bb1a70',
|
||||||
'org.whispersystems:signal-protocol-android:5b8acded7f2a40178eb90ab8e8cbfec89d170d91b3ff5e78487d1098df6185a1',
|
'org.whispersystems:signal-protocol-android:5b8acded7f2a40178eb90ab8e8cbfec89d170d91b3ff5e78487d1098df6185a1',
|
||||||
'org.whispersystems:signal-service-java:438e8330cf806152e7e226d8241dd6388ee4005f0ea7d2aaa99d7ef514012dca',
|
'org.whispersystems:signal-service-java:90aadf941cc31cb0f5af9e1adffa248556f1cfc56a62c141bc62812e7bf3ed52',
|
||||||
'com.nineoldandroids:library:68025a14e3e7673d6ad2f95e4b46d78d7d068343aa99256b686fe59de1b3163a',
|
'com.nineoldandroids:library:68025a14e3e7673d6ad2f95e4b46d78d7d068343aa99256b686fe59de1b3163a',
|
||||||
'javax.inject:javax.inject:91c77044a50c481636c32d916fd89c9118a72195390452c81065080f957de7ff',
|
'javax.inject:javax.inject:91c77044a50c481636c32d916fd89c9118a72195390452c81065080f957de7ff',
|
||||||
'com.klinkerapps:logger:177e325259a8b111ad6745ec10db5861723c99f402222b80629f576f49408541',
|
'com.klinkerapps:logger:177e325259a8b111ad6745ec10db5861723c99f402222b80629f576f49408541',
|
||||||
|
@ -27,6 +27,18 @@
|
|||||||
android:paddingBottom="2dp"
|
android:paddingBottom="2dp"
|
||||||
android:visibility="gone"
|
android:visibility="gone"
|
||||||
android:contentDescription="@string/conversation_item_sent__delivered_description"
|
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"/>
|
tools:visibility="visible"/>
|
||||||
|
|
||||||
</merge>
|
</merge>
|
@ -1456,7 +1456,9 @@
|
|||||||
|
|
||||||
<!-- transport_selection_list_item -->
|
<!-- transport_selection_list_item -->
|
||||||
<string name="transport_selection_list_item__transport_icon">Transport icon</string>
|
<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 -->
|
<!-- EOF -->
|
||||||
|
@ -40,6 +40,12 @@
|
|||||||
android:title="@string/preferences_advanced__always_relay_calls"
|
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"/>
|
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"
|
<Preference android:key="preference_category_blocked"
|
||||||
android:title="@string/preferences_app_protection__blocked_contacts" />
|
android:title="@string/preferences_app_protection__blocked_contacts" />
|
||||||
</PreferenceCategory>
|
</PreferenceCategory>
|
||||||
|
@ -445,6 +445,7 @@ public class ConversationItem extends LinearLayout
|
|||||||
|
|
||||||
if (!messageRecord.isOutgoing()) deliveryStatusIndicator.setNone();
|
if (!messageRecord.isOutgoing()) deliveryStatusIndicator.setNone();
|
||||||
else if (messageRecord.isPending()) deliveryStatusIndicator.setPending();
|
else if (messageRecord.isPending()) deliveryStatusIndicator.setPending();
|
||||||
|
else if (messageRecord.isRemoteRead()) deliveryStatusIndicator.setRead();
|
||||||
else if (messageRecord.isDelivered()) deliveryStatusIndicator.setDelivered();
|
else if (messageRecord.isDelivered()) deliveryStatusIndicator.setDelivered();
|
||||||
else deliveryStatusIndicator.setSent();
|
else deliveryStatusIndicator.setSent();
|
||||||
}
|
}
|
||||||
|
@ -215,6 +215,7 @@ public class ConversationListItem extends RelativeLayout
|
|||||||
alertView.setNone();
|
alertView.setNone();
|
||||||
|
|
||||||
if (thread.isPending()) deliveryStatusIndicator.setPending();
|
if (thread.isPending()) deliveryStatusIndicator.setPending();
|
||||||
|
else if (thread.isRemoteRead()) deliveryStatusIndicator.setRead();
|
||||||
else if (thread.isDelivered()) deliveryStatusIndicator.setDelivered();
|
else if (thread.isDelivered()) deliveryStatusIndicator.setDelivered();
|
||||||
else deliveryStatusIndicator.setSent();
|
else deliveryStatusIndicator.setSent();
|
||||||
}
|
}
|
||||||
|
@ -68,6 +68,7 @@ public class PassphraseCreateActivity extends PassphraseActivity {
|
|||||||
VersionTracker.updateLastSeenVersion(PassphraseCreateActivity.this);
|
VersionTracker.updateLastSeenVersion(PassphraseCreateActivity.this);
|
||||||
TextSecurePreferences.setLastExperienceVersionCode(PassphraseCreateActivity.this, Util.getCurrentApkReleaseVersion(PassphraseCreateActivity.this));
|
TextSecurePreferences.setLastExperienceVersionCode(PassphraseCreateActivity.this, Util.getCurrentApkReleaseVersion(PassphraseCreateActivity.this));
|
||||||
TextSecurePreferences.setPasswordDisabled(PassphraseCreateActivity.this, true);
|
TextSecurePreferences.setPasswordDisabled(PassphraseCreateActivity.this, true);
|
||||||
|
TextSecurePreferences.setReadReceiptsEnabled(PassphraseCreateActivity.this, true);
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,7 @@ public class DeliveryStatusView extends FrameLayout {
|
|||||||
private final ViewGroup pendingIndicatorStub;
|
private final ViewGroup pendingIndicatorStub;
|
||||||
private final ImageView sentIndicator;
|
private final ImageView sentIndicator;
|
||||||
private final ImageView deliveredIndicator;
|
private final ImageView deliveredIndicator;
|
||||||
|
private final ImageView readIndicator;
|
||||||
|
|
||||||
public DeliveryStatusView(Context context) {
|
public DeliveryStatusView(Context context) {
|
||||||
this(context, null);
|
this(context, null);
|
||||||
@ -39,6 +40,7 @@ public class DeliveryStatusView extends FrameLayout {
|
|||||||
this.deliveredIndicator = (ImageView) findViewById(R.id.delivered_indicator);
|
this.deliveredIndicator = (ImageView) findViewById(R.id.delivered_indicator);
|
||||||
this.sentIndicator = (ImageView) findViewById(R.id.sent_indicator);
|
this.sentIndicator = (ImageView) findViewById(R.id.sent_indicator);
|
||||||
this.pendingIndicatorStub = (ViewGroup) findViewById(R.id.pending_indicator_stub);
|
this.pendingIndicatorStub = (ViewGroup) findViewById(R.id.pending_indicator_stub);
|
||||||
|
this.readIndicator = (ImageView) findViewById(R.id.read_indicator);
|
||||||
|
|
||||||
int iconColor = Color.GRAY;
|
int iconColor = Color.GRAY;
|
||||||
|
|
||||||
@ -71,6 +73,7 @@ public class DeliveryStatusView extends FrameLayout {
|
|||||||
pendingIndicatorStub.setVisibility(View.VISIBLE);
|
pendingIndicatorStub.setVisibility(View.VISIBLE);
|
||||||
sentIndicator.setVisibility(View.GONE);
|
sentIndicator.setVisibility(View.GONE);
|
||||||
deliveredIndicator.setVisibility(View.GONE);
|
deliveredIndicator.setVisibility(View.GONE);
|
||||||
|
readIndicator.setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setSent() {
|
public void setSent() {
|
||||||
@ -78,6 +81,7 @@ public class DeliveryStatusView extends FrameLayout {
|
|||||||
pendingIndicatorStub.setVisibility(View.GONE);
|
pendingIndicatorStub.setVisibility(View.GONE);
|
||||||
sentIndicator.setVisibility(View.VISIBLE);
|
sentIndicator.setVisibility(View.VISIBLE);
|
||||||
deliveredIndicator.setVisibility(View.GONE);
|
deliveredIndicator.setVisibility(View.GONE);
|
||||||
|
readIndicator.setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setDelivered() {
|
public void setDelivered() {
|
||||||
@ -85,5 +89,14 @@ public class DeliveryStatusView extends FrameLayout {
|
|||||||
pendingIndicatorStub.setVisibility(View.GONE);
|
pendingIndicatorStub.setVisibility(View.GONE);
|
||||||
sentIndicator.setVisibility(View.GONE);
|
sentIndicator.setVisibility(View.GONE);
|
||||||
deliveredIndicator.setVisibility(View.VISIBLE);
|
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 PROFILES = 41;
|
||||||
private static final int PROFILE_SHARING_APPROVAL = 42;
|
private static final int PROFILE_SHARING_APPROVAL = 42;
|
||||||
private static final int UNSEEN_NUMBER_OFFER = 43;
|
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 String DATABASE_NAME = "messages.db";
|
||||||
private static final Object lock = new Object();
|
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");
|
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.setTransactionSuccessful();
|
||||||
db.endTransaction();
|
db.endTransaction();
|
||||||
}
|
}
|
||||||
|
@ -59,6 +59,7 @@ import org.thoughtcrime.securesms.mms.SlideDeck;
|
|||||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||||
import org.thoughtcrime.securesms.recipients.RecipientFormattingException;
|
import org.thoughtcrime.securesms.recipients.RecipientFormattingException;
|
||||||
import org.thoughtcrime.securesms.util.JsonUtils;
|
import org.thoughtcrime.securesms.util.JsonUtils;
|
||||||
|
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||||
import org.thoughtcrime.securesms.util.Util;
|
import org.thoughtcrime.securesms.util.Util;
|
||||||
import org.whispersystems.jobqueue.JobManager;
|
import org.whispersystems.jobqueue.JobManager;
|
||||||
import org.whispersystems.libsignal.InvalidMessageException;
|
import org.whispersystems.libsignal.InvalidMessageException;
|
||||||
@ -101,10 +102,11 @@ public class MmsDatabase extends MessagingDatabase {
|
|||||||
STATUS + " INTEGER, " + TRANSACTION_ID + " TEXT, " + "retr_st" + " INTEGER, " +
|
STATUS + " INTEGER, " + TRANSACTION_ID + " TEXT, " + "retr_st" + " INTEGER, " +
|
||||||
"retr_txt" + " TEXT, " + "retr_txt_cs" + " INTEGER, " + "read_status" + " INTEGER, " +
|
"retr_txt" + " TEXT, " + "retr_txt_cs" + " INTEGER, " + "read_status" + " INTEGER, " +
|
||||||
"ct_cls" + " INTEGER, " + "resp_txt" + " TEXT, " + "d_tm" + " 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, " +
|
NETWORK_FAILURE + " TEXT DEFAULT NULL," + "d_rpt" + " INTEGER, " +
|
||||||
SUBSCRIPTION_ID + " INTEGER DEFAULT -1, " + EXPIRES_IN + " INTEGER DEFAULT 0, " +
|
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 = {
|
public static final String[] CREATE_INDEXS = {
|
||||||
"CREATE INDEX IF NOT EXISTS mms_thread_id_index ON " + TABLE_NAME + " (" + THREAD_ID + ");",
|
"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,
|
CONTENT_LOCATION, EXPIRY, MESSAGE_TYPE,
|
||||||
MESSAGE_SIZE, STATUS, TRANSACTION_ID,
|
MESSAGE_SIZE, STATUS, TRANSACTION_ID,
|
||||||
BODY, PART_COUNT, ADDRESS, ADDRESS_DEVICE_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,
|
EXPIRES_IN, EXPIRE_STARTED, NOTIFIED,
|
||||||
AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.ROW_ID + " AS " + AttachmentDatabase.ATTACHMENT_ID_ALIAS,
|
AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.ROW_ID + " AS " + AttachmentDatabase.ATTACHMENT_ID_ALIAS,
|
||||||
AttachmentDatabase.UNIQUE_ID,
|
AttachmentDatabase.UNIQUE_ID,
|
||||||
@ -144,7 +146,9 @@ public class MmsDatabase extends MessagingDatabase {
|
|||||||
|
|
||||||
private static final String RAW_ID_WHERE = TABLE_NAME + "._id = ?";
|
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;
|
private final JobManager jobManager;
|
||||||
|
|
||||||
public MmsDatabase(Context context, SQLiteOpenHelper databaseHelper) {
|
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();
|
SQLiteDatabase database = databaseHelper.getWritableDatabase();
|
||||||
Cursor cursor = null;
|
Cursor cursor = null;
|
||||||
boolean found = false;
|
boolean found = false;
|
||||||
@ -202,6 +206,7 @@ public class MmsDatabase extends MessagingDatabase {
|
|||||||
if (Types.isOutgoingMessageType(cursor.getLong(cursor.getColumnIndexOrThrow(MESSAGE_BOX)))) {
|
if (Types.isOutgoingMessageType(cursor.getLong(cursor.getColumnIndexOrThrow(MESSAGE_BOX)))) {
|
||||||
Address theirAddress = Address.fromSerialized(cursor.getString(cursor.getColumnIndexOrThrow(ADDRESS)));
|
Address theirAddress = Address.fromSerialized(cursor.getString(cursor.getColumnIndexOrThrow(ADDRESS)));
|
||||||
Address ourAddress = messageId.getAddress();
|
Address ourAddress = messageId.getAddress();
|
||||||
|
String columnName = deliveryReceipt ? DELIVERY_RECEIPT_COUNT : READ_RECEIPT_COUNT;
|
||||||
|
|
||||||
if (ourAddress.equals(theirAddress) || theirAddress.isGroup()) {
|
if (ourAddress.equals(theirAddress) || theirAddress.isGroup()) {
|
||||||
long id = cursor.getLong(cursor.getColumnIndexOrThrow(ID));
|
long id = cursor.getLong(cursor.getColumnIndexOrThrow(ID));
|
||||||
@ -210,7 +215,7 @@ public class MmsDatabase extends MessagingDatabase {
|
|||||||
found = true;
|
found = true;
|
||||||
|
|
||||||
database.execSQL("UPDATE " + TABLE_NAME + " SET " +
|
database.execSQL("UPDATE " + TABLE_NAME + " SET " +
|
||||||
RECEIPT_COUNT + " = " + RECEIPT_COUNT + " + 1 WHERE " + ID + " = ?",
|
columnName + " = " + columnName + " + 1 WHERE " + ID + " = ?",
|
||||||
new String[] {String.valueOf(id)});
|
new String[] {String.valueOf(id)});
|
||||||
|
|
||||||
DatabaseFactory.getThreadDatabase(context).update(threadId, false);
|
DatabaseFactory.getThreadDatabase(context).update(threadId, false);
|
||||||
@ -220,7 +225,8 @@ public class MmsDatabase extends MessagingDatabase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!found) {
|
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 {
|
} finally {
|
||||||
if (cursor != null)
|
if (cursor != null)
|
||||||
@ -803,7 +809,8 @@ public class MmsDatabase extends MessagingDatabase {
|
|||||||
contentValues.put(SUBSCRIPTION_ID, message.getSubscriptionId());
|
contentValues.put(SUBSCRIPTION_ID, message.getSubscriptionId());
|
||||||
contentValues.put(EXPIRES_IN, message.getExpiresIn());
|
contentValues.put(EXPIRES_IN, message.getExpiresIn());
|
||||||
contentValues.put(ADDRESS, message.getRecipient().getAddress().serialize());
|
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);
|
long messageId = insertMediaMessage(masterSecret, message.getBody(), message.getAttachments(), contentValues, insertListener);
|
||||||
|
|
||||||
@ -1060,7 +1067,7 @@ public class MmsDatabase extends MessagingDatabase {
|
|||||||
new LinkedList<NetworkFailure>(),
|
new LinkedList<NetworkFailure>(),
|
||||||
message.getSubscriptionId(),
|
message.getSubscriptionId(),
|
||||||
message.getExpiresIn(),
|
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 messageSize = cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.MESSAGE_SIZE));
|
||||||
long expiry = cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.EXPIRY));
|
long expiry = cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.EXPIRY));
|
||||||
int status = cursor.getInt(cursor.getColumnIndexOrThrow(MmsDatabase.STATUS));
|
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));
|
int subscriptionId = cursor.getInt(cursor.getColumnIndexOrThrow(MmsDatabase.SUBSCRIPTION_ID));
|
||||||
|
|
||||||
|
if (!TextSecurePreferences.isReadReceiptsEnabled(context)) {
|
||||||
|
readReceiptCount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
byte[]contentLocationBytes = null;
|
byte[]contentLocationBytes = null;
|
||||||
byte[]transactionIdBytes = null;
|
byte[]transactionIdBytes = null;
|
||||||
|
|
||||||
@ -1126,9 +1138,10 @@ public class MmsDatabase extends MessagingDatabase {
|
|||||||
|
|
||||||
|
|
||||||
return new NotificationMmsMessageRecord(context, id, recipient, recipient,
|
return new NotificationMmsMessageRecord(context, id, recipient, recipient,
|
||||||
addressDeviceId, dateSent, dateReceived, receiptCount, threadId,
|
addressDeviceId, dateSent, dateReceived, deliveryReceiptCount, threadId,
|
||||||
contentLocationBytes, messageSize, expiry, status,
|
contentLocationBytes, messageSize, expiry, status,
|
||||||
transactionIdBytes, mailbox, subscriptionId, slideDeck);
|
transactionIdBytes, mailbox, subscriptionId, slideDeck,
|
||||||
|
readReceiptCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
private MediaMmsMessageRecord getMediaMmsMessageRecord(Cursor cursor) {
|
private MediaMmsMessageRecord getMediaMmsMessageRecord(Cursor cursor) {
|
||||||
@ -1139,7 +1152,8 @@ public class MmsDatabase extends MessagingDatabase {
|
|||||||
long threadId = cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.THREAD_ID));
|
long threadId = cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.THREAD_ID));
|
||||||
String address = cursor.getString(cursor.getColumnIndexOrThrow(MmsDatabase.ADDRESS));
|
String address = cursor.getString(cursor.getColumnIndexOrThrow(MmsDatabase.ADDRESS));
|
||||||
int addressDeviceId = cursor.getInt(cursor.getColumnIndexOrThrow(MmsDatabase.ADDRESS_DEVICE_ID));
|
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);
|
DisplayRecord.Body body = getBody(cursor);
|
||||||
int partCount = cursor.getInt(cursor.getColumnIndexOrThrow(MmsDatabase.PART_COUNT));
|
int partCount = cursor.getInt(cursor.getColumnIndexOrThrow(MmsDatabase.PART_COUNT));
|
||||||
String mismatchDocument = cursor.getString(cursor.getColumnIndexOrThrow(MmsDatabase.MISMATCHED_IDENTITIES));
|
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 expiresIn = cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.EXPIRES_IN));
|
||||||
long expireStarted = cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.EXPIRE_STARTED));
|
long expireStarted = cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.EXPIRE_STARTED));
|
||||||
|
|
||||||
|
if (!TextSecurePreferences.isReadReceiptsEnabled(context)) {
|
||||||
|
readReceiptCount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
Recipient recipient = getRecipientFor(address);
|
Recipient recipient = getRecipientFor(address);
|
||||||
List<IdentityKeyMismatch> mismatches = getMismatchedIdentities(mismatchDocument);
|
List<IdentityKeyMismatch> mismatches = getMismatchedIdentities(mismatchDocument);
|
||||||
List<NetworkFailure> networkFailures = getFailures(networkDocument);
|
List<NetworkFailure> networkFailures = getFailures(networkDocument);
|
||||||
SlideDeck slideDeck = getSlideDeck(cursor);
|
SlideDeck slideDeck = getSlideDeck(cursor);
|
||||||
|
|
||||||
return new MediaMmsMessageRecord(context, id, recipient, recipient,
|
return new MediaMmsMessageRecord(context, id, recipient, recipient,
|
||||||
addressDeviceId, dateSent, dateReceived, receiptCount,
|
addressDeviceId, dateSent, dateReceived, deliveryReceiptCount,
|
||||||
threadId, body, slideDeck, partCount, box, mismatches,
|
threadId, body, slideDeck, partCount, box, mismatches,
|
||||||
networkFailures, subscriptionId, expiresIn, expireStarted);
|
networkFailures, subscriptionId, expiresIn, expireStarted,
|
||||||
|
readReceiptCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Recipient getRecipientFor(String serialized) {
|
private Recipient getRecipientFor(String serialized) {
|
||||||
|
@ -11,7 +11,8 @@ public interface MmsSmsColumns {
|
|||||||
public static final String BODY = "body";
|
public static final String BODY = "body";
|
||||||
public static final String ADDRESS = "address";
|
public static final String ADDRESS = "address";
|
||||||
public static final String ADDRESS_DEVICE_ID = "address_device_id";
|
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 MISMATCHED_IDENTITIES = "mismatched_identities";
|
||||||
public static final String UNIQUE_ROW_ID = "unique_row_id";
|
public static final String UNIQUE_ROW_ID = "unique_row_id";
|
||||||
public static final String SUBSCRIPTION_ID = "subscription_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.support.annotation.Nullable;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.attachments.Attachment;
|
|
||||||
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
||||||
import org.thoughtcrime.securesms.database.MessagingDatabase.SyncMessageId;
|
import org.thoughtcrime.securesms.database.MessagingDatabase.SyncMessageId;
|
||||||
import org.thoughtcrime.securesms.database.model.MessageRecord;
|
import org.thoughtcrime.securesms.database.model.MessageRecord;
|
||||||
@ -52,7 +51,9 @@ public class MmsSmsDatabase extends Database {
|
|||||||
SmsDatabase.STATUS, MmsDatabase.PART_COUNT,
|
SmsDatabase.STATUS, MmsDatabase.PART_COUNT,
|
||||||
MmsDatabase.CONTENT_LOCATION, MmsDatabase.TRANSACTION_ID,
|
MmsDatabase.CONTENT_LOCATION, MmsDatabase.TRANSACTION_ID,
|
||||||
MmsDatabase.MESSAGE_SIZE, MmsDatabase.EXPIRY,
|
MmsDatabase.MESSAGE_SIZE, MmsDatabase.EXPIRY,
|
||||||
MmsDatabase.STATUS, MmsSmsColumns.RECEIPT_COUNT,
|
MmsDatabase.STATUS,
|
||||||
|
MmsSmsColumns.DELIVERY_RECEIPT_COUNT,
|
||||||
|
MmsSmsColumns.READ_RECEIPT_COUNT,
|
||||||
MmsSmsColumns.MISMATCHED_IDENTITIES,
|
MmsSmsColumns.MISMATCHED_IDENTITIES,
|
||||||
MmsDatabase.NETWORK_FAILURE,
|
MmsDatabase.NETWORK_FAILURE,
|
||||||
MmsSmsColumns.SUBSCRIPTION_ID,
|
MmsSmsColumns.SUBSCRIPTION_ID,
|
||||||
@ -137,8 +138,13 @@ public class MmsSmsDatabase extends Database {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void incrementDeliveryReceiptCount(SyncMessageId syncMessageId) {
|
public void incrementDeliveryReceiptCount(SyncMessageId syncMessageId) {
|
||||||
DatabaseFactory.getSmsDatabase(context).incrementDeliveryReceiptCount(syncMessageId);
|
DatabaseFactory.getSmsDatabase(context).incrementReceiptCount(syncMessageId, true, false);
|
||||||
DatabaseFactory.getMmsDatabase(context).incrementDeliveryReceiptCount(syncMessageId);
|
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) {
|
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.MESSAGE_BOX, SmsDatabase.STATUS, MmsDatabase.PART_COUNT,
|
||||||
MmsDatabase.CONTENT_LOCATION, MmsDatabase.TRANSACTION_ID,
|
MmsDatabase.CONTENT_LOCATION, MmsDatabase.TRANSACTION_ID,
|
||||||
MmsDatabase.MESSAGE_SIZE, MmsDatabase.EXPIRY, MmsDatabase.STATUS,
|
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.SUBSCRIPTION_ID, MmsSmsColumns.EXPIRES_IN, MmsSmsColumns.EXPIRE_STARTED,
|
||||||
MmsSmsColumns.NOTIFIED,
|
MmsSmsColumns.NOTIFIED,
|
||||||
MmsDatabase.NETWORK_FAILURE, TRANSPORT,
|
MmsDatabase.NETWORK_FAILURE, TRANSPORT,
|
||||||
@ -185,7 +192,8 @@ public class MmsSmsDatabase extends Database {
|
|||||||
MmsDatabase.MESSAGE_BOX, SmsDatabase.STATUS, MmsDatabase.PART_COUNT,
|
MmsDatabase.MESSAGE_BOX, SmsDatabase.STATUS, MmsDatabase.PART_COUNT,
|
||||||
MmsDatabase.CONTENT_LOCATION, MmsDatabase.TRANSACTION_ID,
|
MmsDatabase.CONTENT_LOCATION, MmsDatabase.TRANSACTION_ID,
|
||||||
MmsDatabase.MESSAGE_SIZE, MmsDatabase.EXPIRY, MmsDatabase.STATUS,
|
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.SUBSCRIPTION_ID, MmsSmsColumns.EXPIRES_IN, MmsSmsColumns.EXPIRE_STARTED,
|
||||||
MmsSmsColumns.NOTIFIED,
|
MmsSmsColumns.NOTIFIED,
|
||||||
MmsDatabase.NETWORK_FAILURE, TRANSPORT,
|
MmsDatabase.NETWORK_FAILURE, TRANSPORT,
|
||||||
@ -227,7 +235,8 @@ public class MmsSmsDatabase extends Database {
|
|||||||
mmsColumnsPresent.add(MmsSmsColumns.BODY);
|
mmsColumnsPresent.add(MmsSmsColumns.BODY);
|
||||||
mmsColumnsPresent.add(MmsSmsColumns.ADDRESS);
|
mmsColumnsPresent.add(MmsSmsColumns.ADDRESS);
|
||||||
mmsColumnsPresent.add(MmsSmsColumns.ADDRESS_DEVICE_ID);
|
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.MISMATCHED_IDENTITIES);
|
||||||
mmsColumnsPresent.add(MmsSmsColumns.SUBSCRIPTION_ID);
|
mmsColumnsPresent.add(MmsSmsColumns.SUBSCRIPTION_ID);
|
||||||
mmsColumnsPresent.add(MmsSmsColumns.EXPIRES_IN);
|
mmsColumnsPresent.add(MmsSmsColumns.EXPIRES_IN);
|
||||||
@ -268,7 +277,8 @@ public class MmsSmsDatabase extends Database {
|
|||||||
smsColumnsPresent.add(MmsSmsColumns.ADDRESS_DEVICE_ID);
|
smsColumnsPresent.add(MmsSmsColumns.ADDRESS_DEVICE_ID);
|
||||||
smsColumnsPresent.add(MmsSmsColumns.READ);
|
smsColumnsPresent.add(MmsSmsColumns.READ);
|
||||||
smsColumnsPresent.add(MmsSmsColumns.THREAD_ID);
|
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.MISMATCHED_IDENTITIES);
|
||||||
smsColumnsPresent.add(MmsSmsColumns.SUBSCRIPTION_ID);
|
smsColumnsPresent.add(MmsSmsColumns.SUBSCRIPTION_ID);
|
||||||
smsColumnsPresent.add(MmsSmsColumns.EXPIRES_IN);
|
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.IncomingTextMessage;
|
||||||
import org.thoughtcrime.securesms.sms.OutgoingTextMessage;
|
import org.thoughtcrime.securesms.sms.OutgoingTextMessage;
|
||||||
import org.thoughtcrime.securesms.util.JsonUtils;
|
import org.thoughtcrime.securesms.util.JsonUtils;
|
||||||
|
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||||
import org.whispersystems.jobqueue.JobManager;
|
import org.whispersystems.jobqueue.JobManager;
|
||||||
import org.whispersystems.libsignal.util.guava.Optional;
|
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, " +
|
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, " +
|
DATE_RECEIVED + " INTEGER, " + DATE_SENT + " INTEGER, " + PROTOCOL + " INTEGER, " + READ + " INTEGER DEFAULT 0, " +
|
||||||
STATUS + " INTEGER DEFAULT -1," + TYPE + " INTEGER, " + REPLY_PATH_PRESENT + " INTEGER, " +
|
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, " +
|
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 = {
|
public static final String[] CREATE_INDEXS = {
|
||||||
"CREATE INDEX IF NOT EXISTS sms_thread_id_index ON " + TABLE_NAME + " (" + THREAD_ID + ");",
|
"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_RECEIVED + " AS " + NORMALIZED_DATE_RECEIVED,
|
||||||
DATE_SENT + " AS " + NORMALIZED_DATE_SENT,
|
DATE_SENT + " AS " + NORMALIZED_DATE_SENT,
|
||||||
PROTOCOL, READ, STATUS, TYPE,
|
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,
|
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;
|
private final JobManager jobManager;
|
||||||
|
|
||||||
public SmsDatabase(Context context, SQLiteOpenHelper databaseHelper) {
|
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)});
|
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();
|
SQLiteDatabase database = databaseHelper.getWritableDatabase();
|
||||||
Cursor cursor = null;
|
Cursor cursor = null;
|
||||||
boolean foundMessage = false;
|
boolean foundMessage = false;
|
||||||
@ -291,12 +295,13 @@ public class SmsDatabase extends MessagingDatabase {
|
|||||||
if (Types.isOutgoingMessageType(cursor.getLong(cursor.getColumnIndexOrThrow(TYPE)))) {
|
if (Types.isOutgoingMessageType(cursor.getLong(cursor.getColumnIndexOrThrow(TYPE)))) {
|
||||||
Address theirAddress = messageId.getAddress();
|
Address theirAddress = messageId.getAddress();
|
||||||
Address ourAddress = Address.fromSerialized(cursor.getString(cursor.getColumnIndexOrThrow(ADDRESS)));
|
Address ourAddress = Address.fromSerialized(cursor.getString(cursor.getColumnIndexOrThrow(ADDRESS)));
|
||||||
|
String columnName = deliveryReceipt ? DELIVERY_RECEIPT_COUNT : READ_RECEIPT_COUNT;
|
||||||
|
|
||||||
if (ourAddress.equals(theirAddress)) {
|
if (ourAddress.equals(theirAddress)) {
|
||||||
long threadId = cursor.getLong(cursor.getColumnIndexOrThrow(THREAD_ID));
|
long threadId = cursor.getLong(cursor.getColumnIndexOrThrow(THREAD_ID));
|
||||||
|
|
||||||
database.execSQL("UPDATE " + TABLE_NAME +
|
database.execSQL("UPDATE " + TABLE_NAME +
|
||||||
" SET " + RECEIPT_COUNT + " = " + RECEIPT_COUNT + " + 1 WHERE " +
|
" SET " + columnName + " = " + columnName + " + 1 WHERE " +
|
||||||
ID + " = ?",
|
ID + " = ?",
|
||||||
new String[] {String.valueOf(cursor.getLong(cursor.getColumnIndexOrThrow(ID)))});
|
new String[] {String.valueOf(cursor.getLong(cursor.getColumnIndexOrThrow(ID)))});
|
||||||
|
|
||||||
@ -308,7 +313,8 @@ public class SmsDatabase extends MessagingDatabase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!foundMessage) {
|
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 {
|
} finally {
|
||||||
@ -600,7 +606,8 @@ public class SmsDatabase extends MessagingDatabase {
|
|||||||
contentValues.put(TYPE, type);
|
contentValues.put(TYPE, type);
|
||||||
contentValues.put(SUBSCRIPTION_ID, message.getSubscriptionId());
|
contentValues.put(SUBSCRIPTION_ID, message.getSubscriptionId());
|
||||||
contentValues.put(EXPIRES_IN, message.getExpiresIn());
|
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();
|
SQLiteDatabase db = databaseHelper.getWritableDatabase();
|
||||||
long messageId = db.insert(TABLE_NAME, ADDRESS, contentValues);
|
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(),
|
0, message.isSecureMessage() ? MmsSmsColumns.Types.getOutgoingEncryptedMessageType() : MmsSmsColumns.Types.getOutgoingSmsMessageType(),
|
||||||
threadId, 0, new LinkedList<IdentityKeyMismatch>(),
|
threadId, 0, new LinkedList<IdentityKeyMismatch>(),
|
||||||
message.getSubscriptionId(), message.getExpiresIn(),
|
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 dateSent = cursor.getLong(cursor.getColumnIndexOrThrow(SmsDatabase.NORMALIZED_DATE_SENT));
|
||||||
long threadId = cursor.getLong(cursor.getColumnIndexOrThrow(SmsDatabase.THREAD_ID));
|
long threadId = cursor.getLong(cursor.getColumnIndexOrThrow(SmsDatabase.THREAD_ID));
|
||||||
int status = cursor.getInt(cursor.getColumnIndexOrThrow(SmsDatabase.STATUS));
|
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));
|
String mismatchDocument = cursor.getString(cursor.getColumnIndexOrThrow(SmsDatabase.MISMATCHED_IDENTITIES));
|
||||||
int subscriptionId = cursor.getInt(cursor.getColumnIndexOrThrow(SmsDatabase.SUBSCRIPTION_ID));
|
int subscriptionId = cursor.getInt(cursor.getColumnIndexOrThrow(SmsDatabase.SUBSCRIPTION_ID));
|
||||||
long expiresIn = cursor.getLong(cursor.getColumnIndexOrThrow(SmsDatabase.EXPIRES_IN));
|
long expiresIn = cursor.getLong(cursor.getColumnIndexOrThrow(SmsDatabase.EXPIRES_IN));
|
||||||
long expireStarted = cursor.getLong(cursor.getColumnIndexOrThrow(SmsDatabase.EXPIRE_STARTED));
|
long expireStarted = cursor.getLong(cursor.getColumnIndexOrThrow(SmsDatabase.EXPIRE_STARTED));
|
||||||
|
|
||||||
|
if (!TextSecurePreferences.isReadReceiptsEnabled(context)) {
|
||||||
|
readReceiptCount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
List<IdentityKeyMismatch> mismatches = getMismatches(mismatchDocument);
|
List<IdentityKeyMismatch> mismatches = getMismatches(mismatchDocument);
|
||||||
Recipient recipient = Recipient.from(context, address, true);
|
Recipient recipient = Recipient.from(context, address, true);
|
||||||
DisplayRecord.Body body = getBody(cursor);
|
DisplayRecord.Body body = getBody(cursor);
|
||||||
@ -835,9 +847,9 @@ public class SmsDatabase extends MessagingDatabase {
|
|||||||
return new SmsMessageRecord(context, messageId, body, recipient,
|
return new SmsMessageRecord(context, messageId, body, recipient,
|
||||||
recipient,
|
recipient,
|
||||||
addressDeviceId,
|
addressDeviceId,
|
||||||
dateSent, dateReceived, receiptCount, type,
|
dateSent, dateReceived, deliveryReceiptCount, type,
|
||||||
threadId, status, mismatches, subscriptionId,
|
threadId, status, mismatches, subscriptionId,
|
||||||
expiresIn, expireStarted);
|
expiresIn, expireStarted, readReceiptCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<IdentityKeyMismatch> getMismatches(String document) {
|
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.mms.SlideDeck;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||||
import org.thoughtcrime.securesms.util.DelimiterUtil;
|
import org.thoughtcrime.securesms.util.DelimiterUtil;
|
||||||
|
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||||
import org.thoughtcrime.securesms.util.Util;
|
import org.thoughtcrime.securesms.util.Util;
|
||||||
import org.whispersystems.libsignal.InvalidMessageException;
|
import org.whispersystems.libsignal.InvalidMessageException;
|
||||||
import org.whispersystems.libsignal.util.Pair;
|
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 SNIPPET_URI = "snippet_uri";
|
||||||
public static final String ARCHIVED = "archived";
|
public static final String ARCHIVED = "archived";
|
||||||
public static final String STATUS = "status";
|
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 EXPIRES_IN = "expires_in";
|
||||||
public static final String LAST_SEEN = "last_seen";
|
public static final String LAST_SEEN = "last_seen";
|
||||||
private static final String HAS_SENT = "has_sent";
|
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, " +
|
TYPE + " INTEGER DEFAULT 0, " + ERROR + " INTEGER DEFAULT 0, " +
|
||||||
SNIPPET_TYPE + " INTEGER DEFAULT 0, " + SNIPPET_URI + " TEXT DEFAULT NULL, " +
|
SNIPPET_TYPE + " INTEGER DEFAULT 0, " + SNIPPET_URI + " TEXT DEFAULT NULL, " +
|
||||||
ARCHIVED + " INTEGER DEFAULT 0, " + STATUS + " INTEGER DEFAULT 0, " +
|
ARCHIVED + " INTEGER DEFAULT 0, " + STATUS + " INTEGER DEFAULT 0, " +
|
||||||
RECEIPT_COUNT + " INTEGER DEFAULT 0, " + EXPIRES_IN + " INTEGER DEFAULT 0, " +
|
DELIVERY_RECEIPT_COUNT + " INTEGER DEFAULT 0, " + EXPIRES_IN + " INTEGER DEFAULT 0, " +
|
||||||
LAST_SEEN + " INTEGER DEFAULT 0, " + HAS_SENT + " 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 = {
|
public static final String[] CREATE_INDEXS = {
|
||||||
"CREATE INDEX IF NOT EXISTS thread_recipient_ids_index ON " + TABLE_NAME + " (" + ADDRESS + ");",
|
"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 = {
|
private static final String[] THREAD_PROJECTION = {
|
||||||
ID, DATE, MESSAGE_COUNT, ADDRESS, SNIPPET, SNIPPET_CHARSET, READ, TYPE, ERROR, SNIPPET_TYPE,
|
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)
|
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,
|
private void updateThread(long threadId, long count, String body, @Nullable Uri attachment,
|
||||||
long date, int status, int receiptCount, long type, boolean unarchive,
|
long date, int status, int deliveryReceiptCount, long type, boolean unarchive,
|
||||||
long expiresIn)
|
long expiresIn, int readReceiptCount)
|
||||||
{
|
{
|
||||||
ContentValues contentValues = new ContentValues(7);
|
ContentValues contentValues = new ContentValues(7);
|
||||||
contentValues.put(DATE, date - date % 1000);
|
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_URI, attachment == null ? null : attachment.toString());
|
||||||
contentValues.put(SNIPPET_TYPE, type);
|
contentValues.put(SNIPPET_TYPE, type);
|
||||||
contentValues.put(STATUS, status);
|
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);
|
contentValues.put(EXPIRES_IN, expiresIn);
|
||||||
|
|
||||||
if (unarchive) {
|
if (unarchive) {
|
||||||
@ -550,8 +554,8 @@ public class ThreadDatabase extends Database {
|
|||||||
|
|
||||||
if (reader != null && (record = reader.getNext()) != null) {
|
if (reader != null && (record = reader.getNext()) != null) {
|
||||||
updateThread(threadId, count, record.getBody().getBody(), getAttachmentUriFor(record),
|
updateThread(threadId, count, record.getBody().getBody(), getAttachmentUriFor(record),
|
||||||
record.getTimestamp(), record.getDeliveryStatus(), record.getReceiptCount(),
|
record.getTimestamp(), record.getDeliveryStatus(), record.getDeliveryReceiptCount(),
|
||||||
record.getType(), unarchive, record.getExpiresIn());
|
record.getType(), unarchive, record.getExpiresIn(), record.getReadReceiptCount());
|
||||||
notifyConversationListListeners();
|
notifyConversationListListeners();
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
@ -641,14 +645,19 @@ public class ThreadDatabase extends Database {
|
|||||||
long type = cursor.getLong(cursor.getColumnIndexOrThrow(ThreadDatabase.SNIPPET_TYPE));
|
long type = cursor.getLong(cursor.getColumnIndexOrThrow(ThreadDatabase.SNIPPET_TYPE));
|
||||||
boolean archived = cursor.getInt(cursor.getColumnIndex(ThreadDatabase.ARCHIVED)) != 0;
|
boolean archived = cursor.getInt(cursor.getColumnIndex(ThreadDatabase.ARCHIVED)) != 0;
|
||||||
int status = cursor.getInt(cursor.getColumnIndexOrThrow(ThreadDatabase.STATUS));
|
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 expiresIn = cursor.getLong(cursor.getColumnIndexOrThrow(ThreadDatabase.EXPIRES_IN));
|
||||||
long lastSeen = cursor.getLong(cursor.getColumnIndexOrThrow(ThreadDatabase.LAST_SEEN));
|
long lastSeen = cursor.getLong(cursor.getColumnIndexOrThrow(ThreadDatabase.LAST_SEEN));
|
||||||
Uri snippetUri = getSnippetUri(cursor);
|
Uri snippetUri = getSnippetUri(cursor);
|
||||||
|
|
||||||
|
if (!TextSecurePreferences.isReadReceiptsEnabled(context)) {
|
||||||
|
readReceiptCount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
return new ThreadRecord(context, body, snippetUri, recipient, date, count, read == 1,
|
return new ThreadRecord(context, body, snippetUri, recipient, date, count, read == 1,
|
||||||
threadId, receiptCount, status, type, distributionType, archived,
|
threadId, deliveryReceiptCount, status, type, distributionType, archived,
|
||||||
expiresIn, lastSeen);
|
expiresIn, lastSeen, readReceiptCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
private DisplayRecord.Body getPlaintextBody(Cursor cursor) {
|
private DisplayRecord.Body getPlaintextBody(Cursor cursor) {
|
||||||
|
@ -44,12 +44,12 @@ public class ConversationListLoader extends AbstractCursorLoader {
|
|||||||
ThreadDatabase.ID, ThreadDatabase.DATE, ThreadDatabase.MESSAGE_COUNT,
|
ThreadDatabase.ID, ThreadDatabase.DATE, ThreadDatabase.MESSAGE_COUNT,
|
||||||
ThreadDatabase.ADDRESS, ThreadDatabase.SNIPPET, ThreadDatabase.READ,
|
ThreadDatabase.ADDRESS, ThreadDatabase.SNIPPET, ThreadDatabase.READ,
|
||||||
ThreadDatabase.TYPE, ThreadDatabase.SNIPPET_TYPE, ThreadDatabase.SNIPPET_URI,
|
ThreadDatabase.TYPE, ThreadDatabase.SNIPPET_TYPE, ThreadDatabase.SNIPPET_URI,
|
||||||
ThreadDatabase.ARCHIVED, ThreadDatabase.STATUS, ThreadDatabase.RECEIPT_COUNT,
|
ThreadDatabase.ARCHIVED, ThreadDatabase.STATUS, ThreadDatabase.DELIVERY_RECEIPT_COUNT,
|
||||||
ThreadDatabase.EXPIRES_IN, ThreadDatabase.LAST_SEEN}, 1);
|
ThreadDatabase.EXPIRES_IN, ThreadDatabase.LAST_SEEN, ThreadDatabase.READ_RECEIPT_COUNT}, 1);
|
||||||
|
|
||||||
switchToArchiveCursor.addRow(new Object[] {-1L, System.currentTimeMillis(), archivedCount,
|
switchToArchiveCursor.addRow(new Object[] {-1L, System.currentTimeMillis(), archivedCount,
|
||||||
"-1", null, 1, ThreadDatabase.DistributionTypes.ARCHIVE,
|
"-1", null, 1, ThreadDatabase.DistributionTypes.ARCHIVE,
|
||||||
0, null, 0, -1, 0, 0, 0});
|
0, null, 0, -1, 0, 0, 0, -1});
|
||||||
|
|
||||||
cursorList.add(switchToArchiveCursor);
|
cursorList.add(switchToArchiveCursor);
|
||||||
}
|
}
|
||||||
|
@ -42,10 +42,12 @@ public abstract class DisplayRecord {
|
|||||||
private final long threadId;
|
private final long threadId;
|
||||||
private final Body body;
|
private final Body body;
|
||||||
private final int deliveryStatus;
|
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,
|
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.context = context.getApplicationContext();
|
||||||
this.threadId = threadId;
|
this.threadId = threadId;
|
||||||
@ -54,7 +56,8 @@ public abstract class DisplayRecord {
|
|||||||
this.dateReceived = dateReceived;
|
this.dateReceived = dateReceived;
|
||||||
this.type = type;
|
this.type = type;
|
||||||
this.body = body;
|
this.body = body;
|
||||||
this.receiptCount = receiptCount;
|
this.deliveryReceiptCount = deliveryReceiptCount;
|
||||||
|
this.readReceiptCount = readReceiptCount;
|
||||||
this.deliveryStatus = deliveryStatus;
|
this.deliveryStatus = deliveryStatus;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -145,13 +148,21 @@ public abstract class DisplayRecord {
|
|||||||
return deliveryStatus;
|
return deliveryStatus;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getReceiptCount() {
|
public int getDeliveryReceiptCount() {
|
||||||
return receiptCount;
|
return deliveryReceiptCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getReadReceiptCount() {
|
||||||
|
return readReceiptCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isDelivered() {
|
public boolean isDelivered() {
|
||||||
return (deliveryStatus >= SmsDatabase.Status.STATUS_COMPLETE &&
|
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() {
|
public boolean isPendingInsecureSmsFallback() {
|
||||||
|
@ -46,17 +46,17 @@ public class MediaMmsMessageRecord extends MmsMessageRecord {
|
|||||||
|
|
||||||
public MediaMmsMessageRecord(Context context, long id, Recipient conversationRecipient,
|
public MediaMmsMessageRecord(Context context, long id, Recipient conversationRecipient,
|
||||||
Recipient individualRecipient, int recipientDeviceId,
|
Recipient individualRecipient, int recipientDeviceId,
|
||||||
long dateSent, long dateReceived, int receiptCount,
|
long dateSent, long dateReceived, int deliveryReceiptCount,
|
||||||
long threadId, Body body,
|
long threadId, Body body,
|
||||||
@NonNull SlideDeck slideDeck,
|
@NonNull SlideDeck slideDeck,
|
||||||
int partCount, long mailbox,
|
int partCount, long mailbox,
|
||||||
List<IdentityKeyMismatch> mismatches,
|
List<IdentityKeyMismatch> mismatches,
|
||||||
List<NetworkFailure> failures, int subscriptionId,
|
List<NetworkFailure> failures, int subscriptionId,
|
||||||
long expiresIn, long expireStarted)
|
long expiresIn, long expireStarted, int readReceiptCount)
|
||||||
{
|
{
|
||||||
super(context, id, body, conversationRecipient, individualRecipient, recipientDeviceId, dateSent,
|
super(context, id, body, conversationRecipient, individualRecipient, recipientDeviceId, dateSent,
|
||||||
dateReceived, threadId, Status.STATUS_NONE, receiptCount, mailbox, mismatches, failures,
|
dateReceived, threadId, Status.STATUS_NONE, deliveryReceiptCount, mailbox, mismatches, failures,
|
||||||
subscriptionId, expiresIn, expireStarted, slideDeck);
|
subscriptionId, expiresIn, expireStarted, slideDeck, readReceiptCount);
|
||||||
|
|
||||||
this.context = context.getApplicationContext();
|
this.context = context.getApplicationContext();
|
||||||
this.partCount = partCount;
|
this.partCount = partCount;
|
||||||
|
@ -57,13 +57,14 @@ public abstract class MessageRecord extends DisplayRecord {
|
|||||||
MessageRecord(Context context, long id, Body body, Recipient conversationRecipient,
|
MessageRecord(Context context, long id, Body body, Recipient conversationRecipient,
|
||||||
Recipient individualRecipient, int recipientDeviceId,
|
Recipient individualRecipient, int recipientDeviceId,
|
||||||
long dateSent, long dateReceived, long threadId,
|
long dateSent, long dateReceived, long threadId,
|
||||||
int deliveryStatus, int receiptCount, long type,
|
int deliveryStatus, int deliveryReceiptCount, long type,
|
||||||
List<IdentityKeyMismatch> mismatches,
|
List<IdentityKeyMismatch> mismatches,
|
||||||
List<NetworkFailure> networkFailures,
|
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,
|
super(context, body, conversationRecipient, dateSent, dateReceived,
|
||||||
type);
|
threadId, deliveryStatus, deliveryReceiptCount, type, readReceiptCount);
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.individualRecipient = individualRecipient;
|
this.individualRecipient = individualRecipient;
|
||||||
this.recipientDeviceId = recipientDeviceId;
|
this.recipientDeviceId = recipientDeviceId;
|
||||||
|
@ -18,12 +18,12 @@ public abstract class MmsMessageRecord extends MessageRecord {
|
|||||||
|
|
||||||
MmsMessageRecord(Context context, long id, Body body, Recipient conversationRecipient,
|
MmsMessageRecord(Context context, long id, Body body, Recipient conversationRecipient,
|
||||||
Recipient individualRecipient, int recipientDeviceId, long dateSent,
|
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,
|
long type, List<IdentityKeyMismatch> mismatches,
|
||||||
List<NetworkFailure> networkFailures, int subscriptionId, long expiresIn,
|
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;
|
this.slideDeck = slideDeck;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,15 +47,15 @@ public class NotificationMmsMessageRecord extends MmsMessageRecord {
|
|||||||
|
|
||||||
public NotificationMmsMessageRecord(Context context, long id, Recipient conversationRecipient,
|
public NotificationMmsMessageRecord(Context context, long id, Recipient conversationRecipient,
|
||||||
Recipient individualRecipient, int recipientDeviceId,
|
Recipient individualRecipient, int recipientDeviceId,
|
||||||
long dateSent, long dateReceived, int receiptCount,
|
long dateSent, long dateReceived, int deliveryReceiptCount,
|
||||||
long threadId, byte[] contentLocation, long messageSize,
|
long threadId, byte[] contentLocation, long messageSize,
|
||||||
long expiry, int status, byte[] transactionId, long mailbox,
|
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,
|
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,
|
new LinkedList<IdentityKeyMismatch>(), new LinkedList<NetworkFailure>(), subscriptionId,
|
||||||
0, 0, slideDeck);
|
0, 0, slideDeck, readReceiptCount);
|
||||||
|
|
||||||
this.contentLocation = contentLocation;
|
this.contentLocation = contentLocation;
|
||||||
this.messageSize = messageSize;
|
this.messageSize = messageSize;
|
||||||
|
@ -44,15 +44,16 @@ public class SmsMessageRecord extends MessageRecord {
|
|||||||
Recipient individualRecipient,
|
Recipient individualRecipient,
|
||||||
int recipientDeviceId,
|
int recipientDeviceId,
|
||||||
long dateSent, long dateReceived,
|
long dateSent, long dateReceived,
|
||||||
int receiptCount,
|
int deliveryReceiptCount,
|
||||||
long type, long threadId,
|
long type, long threadId,
|
||||||
int status, List<IdentityKeyMismatch> mismatches,
|
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,
|
super(context, id, body, recipient, individualRecipient, recipientDeviceId,
|
||||||
dateSent, dateReceived, threadId, status, receiptCount, type,
|
dateSent, dateReceived, threadId, status, deliveryReceiptCount, type,
|
||||||
mismatches, new LinkedList<NetworkFailure>(), subscriptionId,
|
mismatches, new LinkedList<NetworkFailure>(), subscriptionId,
|
||||||
expiresIn, expireStarted);
|
expiresIn, expireStarted, readReceiptCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getType() {
|
public long getType() {
|
||||||
|
@ -50,10 +50,11 @@ public class ThreadRecord extends DisplayRecord {
|
|||||||
|
|
||||||
public ThreadRecord(@NonNull Context context, @NonNull Body body, @Nullable Uri snippetUri,
|
public ThreadRecord(@NonNull Context context, @NonNull Body body, @Nullable Uri snippetUri,
|
||||||
@NonNull Recipient recipient, long date, long count, boolean read,
|
@NonNull Recipient recipient, long date, long count, boolean read,
|
||||||
long threadId, int receiptCount, int status, long snippetType,
|
long threadId, int deliveryReceiptCount, int status, long snippetType,
|
||||||
int distributionType, boolean archived, long expiresIn, long lastSeen)
|
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.context = context.getApplicationContext();
|
||||||
this.snippetUri = snippetUri;
|
this.snippetUri = snippetUri;
|
||||||
this.count = count;
|
this.count = count;
|
||||||
|
@ -10,7 +10,6 @@ import org.thoughtcrime.securesms.jobs.AttachmentDownloadJob;
|
|||||||
import org.thoughtcrime.securesms.jobs.AvatarDownloadJob;
|
import org.thoughtcrime.securesms.jobs.AvatarDownloadJob;
|
||||||
import org.thoughtcrime.securesms.jobs.CleanPreKeysJob;
|
import org.thoughtcrime.securesms.jobs.CleanPreKeysJob;
|
||||||
import org.thoughtcrime.securesms.jobs.CreateSignedPreKeyJob;
|
import org.thoughtcrime.securesms.jobs.CreateSignedPreKeyJob;
|
||||||
import org.thoughtcrime.securesms.jobs.DeliveryReceiptJob;
|
|
||||||
import org.thoughtcrime.securesms.jobs.GcmRefreshJob;
|
import org.thoughtcrime.securesms.jobs.GcmRefreshJob;
|
||||||
import org.thoughtcrime.securesms.jobs.MultiDeviceBlockedUpdateJob;
|
import org.thoughtcrime.securesms.jobs.MultiDeviceBlockedUpdateJob;
|
||||||
import org.thoughtcrime.securesms.jobs.MultiDeviceContactUpdateJob;
|
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.RetrieveProfileAvatarJob;
|
||||||
import org.thoughtcrime.securesms.jobs.RetrieveProfileJob;
|
import org.thoughtcrime.securesms.jobs.RetrieveProfileJob;
|
||||||
import org.thoughtcrime.securesms.jobs.RotateSignedPreKeyJob;
|
import org.thoughtcrime.securesms.jobs.RotateSignedPreKeyJob;
|
||||||
|
import org.thoughtcrime.securesms.jobs.SendReadReceiptJob;
|
||||||
import org.thoughtcrime.securesms.push.SecurityEventListener;
|
import org.thoughtcrime.securesms.push.SecurityEventListener;
|
||||||
import org.thoughtcrime.securesms.push.SignalServiceNetworkAccess;
|
import org.thoughtcrime.securesms.push.SignalServiceNetworkAccess;
|
||||||
import org.thoughtcrime.securesms.service.MessageRetrievalService;
|
import org.thoughtcrime.securesms.service.MessageRetrievalService;
|
||||||
@ -45,7 +45,6 @@ import dagger.Provides;
|
|||||||
|
|
||||||
@Module(complete = false, injects = {CleanPreKeysJob.class,
|
@Module(complete = false, injects = {CleanPreKeysJob.class,
|
||||||
CreateSignedPreKeyJob.class,
|
CreateSignedPreKeyJob.class,
|
||||||
DeliveryReceiptJob.class,
|
|
||||||
PushGroupSendJob.class,
|
PushGroupSendJob.class,
|
||||||
PushTextSendJob.class,
|
PushTextSendJob.class,
|
||||||
PushMediaSendJob.class,
|
PushMediaSendJob.class,
|
||||||
@ -69,48 +68,56 @@ import dagger.Provides;
|
|||||||
MultiDeviceVerifiedUpdateJob.class,
|
MultiDeviceVerifiedUpdateJob.class,
|
||||||
CreateProfileActivity.class,
|
CreateProfileActivity.class,
|
||||||
RetrieveProfileAvatarJob.class,
|
RetrieveProfileAvatarJob.class,
|
||||||
MultiDeviceProfileKeyUpdateJob.class})
|
MultiDeviceProfileKeyUpdateJob.class,
|
||||||
|
SendReadReceiptJob.class})
|
||||||
public class SignalCommunicationModule {
|
public class SignalCommunicationModule {
|
||||||
|
|
||||||
private final Context context;
|
private final Context context;
|
||||||
private final SignalServiceNetworkAccess networkAccess;
|
private final SignalServiceNetworkAccess networkAccess;
|
||||||
|
|
||||||
|
private SignalServiceAccountManager accountManager;
|
||||||
|
private SignalServiceMessageSender messageSender;
|
||||||
|
private SignalServiceMessageReceiver messageReceiver;
|
||||||
|
|
||||||
public SignalCommunicationModule(Context context, SignalServiceNetworkAccess networkAccess) {
|
public SignalCommunicationModule(Context context, SignalServiceNetworkAccess networkAccess) {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
this.networkAccess = networkAccess;
|
this.networkAccess = networkAccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides SignalServiceAccountManager provideSignalAccountManager() {
|
@Provides
|
||||||
return new SignalServiceAccountManager(networkAccess.getConfiguration(context),
|
synchronized SignalServiceAccountManager provideSignalAccountManager() {
|
||||||
TextSecurePreferences.getLocalNumber(context),
|
if (this.accountManager == null) {
|
||||||
TextSecurePreferences.getPushServerPassword(context),
|
this.accountManager = new SignalServiceAccountManager(networkAccess.getConfiguration(context),
|
||||||
|
new DynamicCredentialsProvider(context),
|
||||||
BuildConfig.USER_AGENT);
|
BuildConfig.USER_AGENT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return this.accountManager;
|
||||||
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
SignalMessageSenderFactory provideSignalMessageSenderFactory() {
|
synchronized SignalServiceMessageSender provideSignalMessageSender() {
|
||||||
return new SignalMessageSenderFactory() {
|
if (this.messageSender == null) {
|
||||||
@Override
|
this.messageSender = new SignalServiceMessageSender(networkAccess.getConfiguration(context),
|
||||||
public SignalServiceMessageSender create() {
|
new DynamicCredentialsProvider(context),
|
||||||
return new SignalServiceMessageSender(networkAccess.getConfiguration(context),
|
|
||||||
TextSecurePreferences.getLocalNumber(context),
|
|
||||||
TextSecurePreferences.getPushServerPassword(context),
|
|
||||||
new SignalProtocolStoreImpl(context),
|
new SignalProtocolStoreImpl(context),
|
||||||
BuildConfig.USER_AGENT,
|
BuildConfig.USER_AGENT,
|
||||||
Optional.fromNullable(MessageRetrievalService.getPipe()),
|
Optional.fromNullable(MessageRetrievalService.getPipe()),
|
||||||
Optional.<SignalServiceMessageSender.EventListener>of(new SecurityEventListener(context)));
|
Optional.<SignalServiceMessageSender.EventListener>of(new SecurityEventListener(context)));
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
return this.messageSender;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides SignalServiceMessageReceiver provideSignalMessageReceiver() {
|
@Provides
|
||||||
return new SignalServiceMessageReceiver(networkAccess.getConfiguration(context),
|
synchronized SignalServiceMessageReceiver provideSignalMessageReceiver() {
|
||||||
|
if (this.messageReceiver == null) {
|
||||||
|
this.messageReceiver = new SignalServiceMessageReceiver(networkAccess.getConfiguration(context),
|
||||||
new DynamicCredentialsProvider(context),
|
new DynamicCredentialsProvider(context),
|
||||||
BuildConfig.USER_AGENT);
|
BuildConfig.USER_AGENT);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static interface SignalMessageSenderFactory {
|
return this.messageReceiver;
|
||||||
public SignalServiceMessageSender create();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class DynamicCredentialsProvider implements CredentialsProvider {
|
private static class DynamicCredentialsProvider implements CredentialsProvider {
|
||||||
|
@ -30,11 +30,9 @@ public class GcmBroadcastReceiver extends WakefulBroadcastReceiver {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
String messageData = intent.getStringExtra("message");
|
|
||||||
String receiptData = intent.getStringExtra("receipt");
|
String receiptData = intent.getStringExtra("receipt");
|
||||||
|
|
||||||
if (!TextUtils.isEmpty(messageData)) handleReceivedMessage(context, messageData);
|
if (!TextUtils.isEmpty(receiptData)) handleReceivedMessage(context, receiptData);
|
||||||
else if (!TextUtils.isEmpty(receiptData)) handleReceivedMessage(context, receiptData);
|
|
||||||
else if (intent.hasExtra("notification")) handleReceivedNotification(context);
|
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;
|
||||||
import org.thoughtcrime.securesms.database.RecipientDatabase.BlockedReader;
|
import org.thoughtcrime.securesms.database.RecipientDatabase.BlockedReader;
|
||||||
import org.thoughtcrime.securesms.dependencies.InjectableType;
|
import org.thoughtcrime.securesms.dependencies.InjectableType;
|
||||||
import org.thoughtcrime.securesms.dependencies.SignalCommunicationModule.SignalMessageSenderFactory;
|
|
||||||
import org.thoughtcrime.securesms.jobs.requirements.MasterSecretRequirement;
|
import org.thoughtcrime.securesms.jobs.requirements.MasterSecretRequirement;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||||
import org.whispersystems.jobqueue.JobParameters;
|
import org.whispersystems.jobqueue.JobParameters;
|
||||||
@ -30,7 +29,7 @@ public class MultiDeviceBlockedUpdateJob extends MasterSecretJob implements Inje
|
|||||||
|
|
||||||
private static final String TAG = MultiDeviceBlockedUpdateJob.class.getSimpleName();
|
private static final String TAG = MultiDeviceBlockedUpdateJob.class.getSimpleName();
|
||||||
|
|
||||||
@Inject transient SignalMessageSenderFactory messageSenderFactory;
|
@Inject transient SignalServiceMessageSender messageSender;
|
||||||
|
|
||||||
public MultiDeviceBlockedUpdateJob(Context context) {
|
public MultiDeviceBlockedUpdateJob(Context context) {
|
||||||
super(context, JobParameters.newBuilder()
|
super(context, JobParameters.newBuilder()
|
||||||
@ -46,7 +45,6 @@ public class MultiDeviceBlockedUpdateJob extends MasterSecretJob implements Inje
|
|||||||
throws IOException, UntrustedIdentityException
|
throws IOException, UntrustedIdentityException
|
||||||
{
|
{
|
||||||
RecipientDatabase database = DatabaseFactory.getRecipientDatabase(context);
|
RecipientDatabase database = DatabaseFactory.getRecipientDatabase(context);
|
||||||
SignalServiceMessageSender messageSender = messageSenderFactory.create();
|
|
||||||
BlockedReader reader = database.readerForBlocked(database.getBlocked());
|
BlockedReader reader = database.readerForBlocked(database.getBlocked());
|
||||||
List<String> blocked = new LinkedList<>();
|
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.DatabaseFactory;
|
||||||
import org.thoughtcrime.securesms.database.IdentityDatabase;
|
import org.thoughtcrime.securesms.database.IdentityDatabase;
|
||||||
import org.thoughtcrime.securesms.dependencies.InjectableType;
|
import org.thoughtcrime.securesms.dependencies.InjectableType;
|
||||||
import org.thoughtcrime.securesms.dependencies.SignalCommunicationModule.SignalMessageSenderFactory;
|
|
||||||
import org.thoughtcrime.securesms.jobs.requirements.MasterSecretRequirement;
|
import org.thoughtcrime.securesms.jobs.requirements.MasterSecretRequirement;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||||
import org.thoughtcrime.securesms.util.Base64;
|
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();
|
private static final String TAG = MultiDeviceContactUpdateJob.class.getSimpleName();
|
||||||
|
|
||||||
@Inject transient SignalMessageSenderFactory messageSenderFactory;
|
@Inject transient SignalServiceMessageSender messageSender;
|
||||||
|
|
||||||
private final @Nullable String address;
|
private final @Nullable String address;
|
||||||
|
|
||||||
@ -90,7 +89,6 @@ public class MultiDeviceContactUpdateJob extends MasterSecretJob implements Inje
|
|||||||
private void generateSingleContactUpdate(@NonNull Address address)
|
private void generateSingleContactUpdate(@NonNull Address address)
|
||||||
throws IOException, UntrustedIdentityException, NetworkException
|
throws IOException, UntrustedIdentityException, NetworkException
|
||||||
{
|
{
|
||||||
SignalServiceMessageSender messageSender = messageSenderFactory.create();
|
|
||||||
File contactDataFile = createTempFile("multidevice-contact-update");
|
File contactDataFile = createTempFile("multidevice-contact-update");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -119,7 +117,6 @@ public class MultiDeviceContactUpdateJob extends MasterSecretJob implements Inje
|
|||||||
private void generateFullContactUpdate()
|
private void generateFullContactUpdate()
|
||||||
throws IOException, UntrustedIdentityException, NetworkException
|
throws IOException, UntrustedIdentityException, NetworkException
|
||||||
{
|
{
|
||||||
SignalServiceMessageSender messageSender = messageSenderFactory.create();
|
|
||||||
File contactDataFile = createTempFile("multidevice-contact-update");
|
File contactDataFile = createTempFile("multidevice-contact-update");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -9,7 +9,6 @@ import org.thoughtcrime.securesms.database.Address;
|
|||||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||||
import org.thoughtcrime.securesms.database.GroupDatabase;
|
import org.thoughtcrime.securesms.database.GroupDatabase;
|
||||||
import org.thoughtcrime.securesms.dependencies.InjectableType;
|
import org.thoughtcrime.securesms.dependencies.InjectableType;
|
||||||
import org.thoughtcrime.securesms.dependencies.SignalCommunicationModule;
|
|
||||||
import org.thoughtcrime.securesms.jobs.requirements.MasterSecretRequirement;
|
import org.thoughtcrime.securesms.jobs.requirements.MasterSecretRequirement;
|
||||||
import org.whispersystems.jobqueue.JobParameters;
|
import org.whispersystems.jobqueue.JobParameters;
|
||||||
import org.whispersystems.jobqueue.requirements.NetworkRequirement;
|
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 long serialVersionUID = 1L;
|
||||||
private static final String TAG = MultiDeviceGroupUpdateJob.class.getSimpleName();
|
private static final String TAG = MultiDeviceGroupUpdateJob.class.getSimpleName();
|
||||||
|
|
||||||
@Inject
|
@Inject transient SignalServiceMessageSender messageSender;
|
||||||
transient SignalCommunicationModule.SignalMessageSenderFactory messageSenderFactory;
|
|
||||||
|
|
||||||
public MultiDeviceGroupUpdateJob(Context context) {
|
public MultiDeviceGroupUpdateJob(Context context) {
|
||||||
super(context, JobParameters.newBuilder()
|
super(context, JobParameters.newBuilder()
|
||||||
@ -52,7 +50,6 @@ public class MultiDeviceGroupUpdateJob extends MasterSecretJob implements Inject
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onRun(MasterSecret masterSecret) throws Exception {
|
public void onRun(MasterSecret masterSecret) throws Exception {
|
||||||
SignalServiceMessageSender messageSender = messageSenderFactory.create();
|
|
||||||
File contactDataFile = createTempFile("multidevice-contact-update");
|
File contactDataFile = createTempFile("multidevice-contact-update");
|
||||||
GroupDatabase.Reader reader = null;
|
GroupDatabase.Reader reader = null;
|
||||||
|
|
||||||
|
@ -7,11 +7,11 @@ import android.util.Log;
|
|||||||
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
||||||
import org.thoughtcrime.securesms.crypto.ProfileKeyUtil;
|
import org.thoughtcrime.securesms.crypto.ProfileKeyUtil;
|
||||||
import org.thoughtcrime.securesms.dependencies.InjectableType;
|
import org.thoughtcrime.securesms.dependencies.InjectableType;
|
||||||
import org.thoughtcrime.securesms.dependencies.SignalCommunicationModule.SignalMessageSenderFactory;
|
|
||||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||||
import org.whispersystems.jobqueue.JobParameters;
|
import org.whispersystems.jobqueue.JobParameters;
|
||||||
import org.whispersystems.jobqueue.requirements.NetworkRequirement;
|
import org.whispersystems.jobqueue.requirements.NetworkRequirement;
|
||||||
import org.whispersystems.libsignal.util.guava.Optional;
|
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.crypto.UntrustedIdentityException;
|
||||||
import org.whispersystems.signalservice.api.messages.SignalServiceAttachment;
|
import org.whispersystems.signalservice.api.messages.SignalServiceAttachment;
|
||||||
import org.whispersystems.signalservice.api.messages.SignalServiceAttachmentStream;
|
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 long serialVersionUID = 1L;
|
||||||
private static final String TAG = MultiDeviceProfileKeyUpdateJob.class.getSimpleName();
|
private static final String TAG = MultiDeviceProfileKeyUpdateJob.class.getSimpleName();
|
||||||
|
|
||||||
@Inject SignalMessageSenderFactory messageSender;
|
@Inject transient SignalServiceMessageSender messageSender;
|
||||||
|
|
||||||
public MultiDeviceProfileKeyUpdateJob(Context context) {
|
public MultiDeviceProfileKeyUpdateJob(Context context) {
|
||||||
super(context, JobParameters.newBuilder()
|
super(context, JobParameters.newBuilder()
|
||||||
@ -71,7 +71,7 @@ public class MultiDeviceProfileKeyUpdateJob extends MasterSecretJob implements I
|
|||||||
|
|
||||||
SignalServiceSyncMessage syncMessage = SignalServiceSyncMessage.forContacts(new ContactsMessage(attachmentStream, false));
|
SignalServiceSyncMessage syncMessage = SignalServiceSyncMessage.forContacts(new ContactsMessage(attachmentStream, false));
|
||||||
|
|
||||||
messageSender.create().sendMessage(syncMessage);
|
messageSender.sendMessage(syncMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -6,7 +6,6 @@ import android.util.Log;
|
|||||||
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
||||||
import org.thoughtcrime.securesms.database.MessagingDatabase.SyncMessageId;
|
import org.thoughtcrime.securesms.database.MessagingDatabase.SyncMessageId;
|
||||||
import org.thoughtcrime.securesms.dependencies.InjectableType;
|
import org.thoughtcrime.securesms.dependencies.InjectableType;
|
||||||
import org.thoughtcrime.securesms.dependencies.SignalCommunicationModule;
|
|
||||||
import org.thoughtcrime.securesms.jobs.requirements.MasterSecretRequirement;
|
import org.thoughtcrime.securesms.jobs.requirements.MasterSecretRequirement;
|
||||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||||
import org.whispersystems.jobqueue.JobParameters;
|
import org.whispersystems.jobqueue.JobParameters;
|
||||||
@ -31,8 +30,7 @@ public class MultiDeviceReadUpdateJob extends MasterSecretJob implements Injecta
|
|||||||
|
|
||||||
private final List<SerializableSyncMessageId> messageIds;
|
private final List<SerializableSyncMessageId> messageIds;
|
||||||
|
|
||||||
@Inject
|
@Inject transient SignalServiceMessageSender messageSender;
|
||||||
transient SignalCommunicationModule.SignalMessageSenderFactory messageSenderFactory;
|
|
||||||
|
|
||||||
public MultiDeviceReadUpdateJob(Context context, List<SyncMessageId> messageIds) {
|
public MultiDeviceReadUpdateJob(Context context, List<SyncMessageId> messageIds) {
|
||||||
super(context, JobParameters.newBuilder()
|
super(context, JobParameters.newBuilder()
|
||||||
@ -62,7 +60,6 @@ public class MultiDeviceReadUpdateJob extends MasterSecretJob implements Injecta
|
|||||||
readMessages.add(new ReadMessage(messageId.sender, messageId.timestamp));
|
readMessages.add(new ReadMessage(messageId.sender, messageId.timestamp));
|
||||||
}
|
}
|
||||||
|
|
||||||
SignalServiceMessageSender messageSender = messageSenderFactory.create();
|
|
||||||
messageSender.sendMessage(SignalServiceSyncMessage.forRead(readMessages));
|
messageSender.sendMessage(SignalServiceSyncMessage.forRead(readMessages));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,7 +7,6 @@ import android.util.Log;
|
|||||||
import org.thoughtcrime.securesms.database.Address;
|
import org.thoughtcrime.securesms.database.Address;
|
||||||
import org.thoughtcrime.securesms.database.IdentityDatabase.VerifiedStatus;
|
import org.thoughtcrime.securesms.database.IdentityDatabase.VerifiedStatus;
|
||||||
import org.thoughtcrime.securesms.dependencies.InjectableType;
|
import org.thoughtcrime.securesms.dependencies.InjectableType;
|
||||||
import org.thoughtcrime.securesms.dependencies.SignalCommunicationModule;
|
|
||||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||||
import org.whispersystems.jobqueue.JobParameters;
|
import org.whispersystems.jobqueue.JobParameters;
|
||||||
import org.whispersystems.jobqueue.requirements.NetworkRequirement;
|
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();
|
private static final String TAG = MultiDeviceVerifiedUpdateJob.class.getSimpleName();
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
transient SignalCommunicationModule.SignalMessageSenderFactory messageSenderFactory;
|
transient SignalServiceMessageSender messageSender;
|
||||||
|
|
||||||
private final String destination;
|
private final String destination;
|
||||||
private final byte[] identityKey;
|
private final byte[] identityKey;
|
||||||
@ -65,7 +64,6 @@ public class MultiDeviceVerifiedUpdateJob extends ContextJob implements Injectab
|
|||||||
|
|
||||||
Address canonicalDestination = Address.fromSerialized(destination);
|
Address canonicalDestination = Address.fromSerialized(destination);
|
||||||
VerifiedMessage.VerifiedState verifiedState = getVerifiedState(verifiedStatus);
|
VerifiedMessage.VerifiedState verifiedState = getVerifiedState(verifiedStatus);
|
||||||
SignalServiceMessageSender messageSender = messageSenderFactory.create();
|
|
||||||
VerifiedMessage verifiedMessage = new VerifiedMessage(canonicalDestination.toPhoneString(), new IdentityKey(identityKey, 0), verifiedState, timestamp);
|
VerifiedMessage verifiedMessage = new VerifiedMessage(canonicalDestination.toPhoneString(), new IdentityKey(identityKey, 0), verifiedState, timestamp);
|
||||||
|
|
||||||
messageSender.sendMessage(SignalServiceSyncMessage.forVerified(verifiedMessage));
|
messageSender.sendMessage(SignalServiceSyncMessage.forVerified(verifiedMessage));
|
||||||
|
@ -39,7 +39,7 @@ public class PushContentReceiveJob extends PushReceivedJob {
|
|||||||
String sessionKey = TextSecurePreferences.getSignalingKey(context);
|
String sessionKey = TextSecurePreferences.getSignalingKey(context);
|
||||||
SignalServiceEnvelope envelope = new SignalServiceEnvelope(data, sessionKey);
|
SignalServiceEnvelope envelope = new SignalServiceEnvelope(data, sessionKey);
|
||||||
|
|
||||||
handle(envelope, true);
|
handle(envelope);
|
||||||
} catch (IOException | InvalidVersionException e) {
|
} catch (IOException | InvalidVersionException e) {
|
||||||
Log.w(TAG, 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.SignalServiceDataMessage;
|
||||||
import org.whispersystems.signalservice.api.messages.SignalServiceEnvelope;
|
import org.whispersystems.signalservice.api.messages.SignalServiceEnvelope;
|
||||||
import org.whispersystems.signalservice.api.messages.SignalServiceGroup;
|
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.AnswerMessage;
|
||||||
import org.whispersystems.signalservice.api.messages.calls.BusyMessage;
|
import org.whispersystems.signalservice.api.messages.calls.BusyMessage;
|
||||||
import org.whispersystems.signalservice.api.messages.calls.HangupMessage;
|
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.getIceUpdateMessages().isPresent()) handleCallIceUpdateMessage(envelope, message.getIceUpdateMessages().get());
|
||||||
else if (message.getHangupMessage().isPresent()) handleCallHangupMessage(envelope, message.getHangupMessage().get(), smsMessageId);
|
else if (message.getHangupMessage().isPresent()) handleCallHangupMessage(envelope, message.getHangupMessage().get(), smsMessageId);
|
||||||
else if (message.getBusyMessage().isPresent()) handleCallBusyMessage(envelope, message.getBusyMessage().get());
|
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 {
|
} else {
|
||||||
Log.w(TAG, "Got unrecognized message...");
|
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) {
|
private Optional<InsertResult> insertPlaceholder(@NonNull SignalServiceEnvelope envelope) {
|
||||||
EncryptingSmsDatabase database = DatabaseFactory.getEncryptingSmsDatabase(context);
|
EncryptingSmsDatabase database = DatabaseFactory.getEncryptingSmsDatabase(context);
|
||||||
IncomingTextMessage textMessage = new IncomingTextMessage(Address.fromExternal(context, envelope.getSource()),
|
IncomingTextMessage textMessage = new IncomingTextMessage(Address.fromExternal(context, envelope.getSource()),
|
||||||
|
@ -43,15 +43,13 @@ import java.util.List;
|
|||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
import static org.thoughtcrime.securesms.dependencies.SignalCommunicationModule.SignalMessageSenderFactory;
|
|
||||||
|
|
||||||
public class PushGroupSendJob extends PushSendJob implements InjectableType {
|
public class PushGroupSendJob extends PushSendJob implements InjectableType {
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
private static final String TAG = PushGroupSendJob.class.getSimpleName();
|
private static final String TAG = PushGroupSendJob.class.getSimpleName();
|
||||||
|
|
||||||
@Inject transient SignalMessageSenderFactory messageSenderFactory;
|
@Inject transient SignalServiceMessageSender messageSender;
|
||||||
|
|
||||||
private final long messageId;
|
private final long messageId;
|
||||||
private final long filterRecipientId; // Deprecated
|
private final long filterRecipientId; // Deprecated
|
||||||
@ -137,7 +135,6 @@ public class PushGroupSendJob extends PushSendJob implements InjectableType {
|
|||||||
throws IOException, RecipientFormattingException, InvalidNumberException,
|
throws IOException, RecipientFormattingException, InvalidNumberException,
|
||||||
EncapsulatedExceptions, UndeliverableMessageException
|
EncapsulatedExceptions, UndeliverableMessageException
|
||||||
{
|
{
|
||||||
SignalServiceMessageSender messageSender = messageSenderFactory.create();
|
|
||||||
String groupId = message.getRecipient().getAddress().toGroupString();
|
String groupId = message.getRecipient().getAddress().toGroupString();
|
||||||
Optional<byte[]> profileKey = getProfileKey(message.getRecipient());
|
Optional<byte[]> profileKey = getProfileKey(message.getRecipient());
|
||||||
List<Recipient> recipients = DatabaseFactory.getGroupDatabase(context).getGroupMembers(groupId, false);
|
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;
|
||||||
import org.thoughtcrime.securesms.database.GroupDatabase.GroupRecord;
|
import org.thoughtcrime.securesms.database.GroupDatabase.GroupRecord;
|
||||||
import org.thoughtcrime.securesms.dependencies.InjectableType;
|
import org.thoughtcrime.securesms.dependencies.InjectableType;
|
||||||
import org.thoughtcrime.securesms.dependencies.SignalCommunicationModule.SignalMessageSenderFactory;
|
|
||||||
import org.thoughtcrime.securesms.util.GroupUtil;
|
import org.thoughtcrime.securesms.util.GroupUtil;
|
||||||
import org.whispersystems.jobqueue.JobParameters;
|
import org.whispersystems.jobqueue.JobParameters;
|
||||||
import org.whispersystems.jobqueue.requirements.NetworkRequirement;
|
import org.whispersystems.jobqueue.requirements.NetworkRequirement;
|
||||||
@ -37,7 +36,7 @@ public class PushGroupUpdateJob extends ContextJob implements InjectableType {
|
|||||||
|
|
||||||
private static final long serialVersionUID = 0L;
|
private static final long serialVersionUID = 0L;
|
||||||
|
|
||||||
@Inject transient SignalMessageSenderFactory messageSenderFactory;
|
@Inject transient SignalServiceMessageSender messageSender;
|
||||||
|
|
||||||
private final String source;
|
private final String source;
|
||||||
private final byte[] groupId;
|
private final byte[] groupId;
|
||||||
@ -59,7 +58,6 @@ public class PushGroupUpdateJob extends ContextJob implements InjectableType {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onRun() throws IOException, UntrustedIdentityException {
|
public void onRun() throws IOException, UntrustedIdentityException {
|
||||||
SignalServiceMessageSender messageSender = messageSenderFactory.create();
|
|
||||||
GroupDatabase groupDatabase = DatabaseFactory.getGroupDatabase(context);
|
GroupDatabase groupDatabase = DatabaseFactory.getGroupDatabase(context);
|
||||||
Optional<GroupRecord> record = groupDatabase.getGroup(GroupUtil.getEncodedId(groupId, false));
|
Optional<GroupRecord> record = groupDatabase.getGroup(GroupUtil.getEncodedId(groupId, false));
|
||||||
SignalServiceAttachment avatar = null;
|
SignalServiceAttachment avatar = null;
|
||||||
|
@ -32,15 +32,13 @@ import java.util.List;
|
|||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
import static org.thoughtcrime.securesms.dependencies.SignalCommunicationModule.SignalMessageSenderFactory;
|
|
||||||
|
|
||||||
public class PushMediaSendJob extends PushSendJob implements InjectableType {
|
public class PushMediaSendJob extends PushSendJob implements InjectableType {
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
private static final String TAG = PushMediaSendJob.class.getSimpleName();
|
private static final String TAG = PushMediaSendJob.class.getSimpleName();
|
||||||
|
|
||||||
@Inject transient SignalMessageSenderFactory messageSenderFactory;
|
@Inject transient SignalServiceMessageSender messageSender;
|
||||||
|
|
||||||
private final long messageId;
|
private final long messageId;
|
||||||
|
|
||||||
@ -107,8 +105,6 @@ public class PushMediaSendJob extends PushSendJob implements InjectableType {
|
|||||||
throw new UndeliverableMessageException("No destination address.");
|
throw new UndeliverableMessageException("No destination address.");
|
||||||
}
|
}
|
||||||
|
|
||||||
SignalServiceMessageSender messageSender = messageSenderFactory.create();
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
SignalServiceAddress address = getPushAddress(message.getRecipient().getAddress());
|
SignalServiceAddress address = getPushAddress(message.getRecipient().getAddress());
|
||||||
MediaConstraints mediaConstraints = MediaConstraints.getPushMediaConstraints();
|
MediaConstraints mediaConstraints = MediaConstraints.getPushMediaConstraints();
|
||||||
|
@ -4,7 +4,6 @@ import android.content.Context;
|
|||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.dependencies.InjectableType;
|
import org.thoughtcrime.securesms.dependencies.InjectableType;
|
||||||
import org.thoughtcrime.securesms.notifications.MessageNotifier;
|
|
||||||
import org.whispersystems.jobqueue.JobParameters;
|
import org.whispersystems.jobqueue.JobParameters;
|
||||||
import org.whispersystems.jobqueue.requirements.NetworkRequirement;
|
import org.whispersystems.jobqueue.requirements.NetworkRequirement;
|
||||||
import org.whispersystems.signalservice.api.SignalServiceMessageReceiver;
|
import org.whispersystems.signalservice.api.SignalServiceMessageReceiver;
|
||||||
@ -37,7 +36,7 @@ public class PushNotificationReceiveJob extends PushReceivedJob implements Injec
|
|||||||
receiver.retrieveMessages(new SignalServiceMessageReceiver.MessageReceivedCallback() {
|
receiver.retrieveMessages(new SignalServiceMessageReceiver.MessageReceivedCallback() {
|
||||||
@Override
|
@Override
|
||||||
public void onMessage(SignalServiceEnvelope envelope) {
|
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.DatabaseFactory;
|
||||||
import org.thoughtcrime.securesms.database.MessagingDatabase.SyncMessageId;
|
import org.thoughtcrime.securesms.database.MessagingDatabase.SyncMessageId;
|
||||||
import org.thoughtcrime.securesms.database.RecipientDatabase;
|
import org.thoughtcrime.securesms.database.RecipientDatabase;
|
||||||
import org.thoughtcrime.securesms.database.RecipientDatabase.RecipientSettings;
|
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||||
import org.thoughtcrime.securesms.service.KeyCachingService;
|
import org.thoughtcrime.securesms.service.KeyCachingService;
|
||||||
import org.thoughtcrime.securesms.util.Util;
|
|
||||||
import org.whispersystems.jobqueue.JobManager;
|
import org.whispersystems.jobqueue.JobManager;
|
||||||
import org.whispersystems.jobqueue.JobParameters;
|
import org.whispersystems.jobqueue.JobParameters;
|
||||||
import org.whispersystems.libsignal.util.guava.Optional;
|
|
||||||
import org.whispersystems.signalservice.api.messages.SignalServiceEnvelope;
|
import org.whispersystems.signalservice.api.messages.SignalServiceEnvelope;
|
||||||
|
|
||||||
import java.util.LinkedList;
|
|
||||||
|
|
||||||
public abstract class PushReceivedJob extends ContextJob {
|
public abstract class PushReceivedJob extends ContextJob {
|
||||||
|
|
||||||
private static final String TAG = PushReceivedJob.class.getSimpleName();
|
private static final String TAG = PushReceivedJob.class.getSimpleName();
|
||||||
@ -28,7 +23,7 @@ public abstract class PushReceivedJob extends ContextJob {
|
|||||||
super(context, parameters);
|
super(context, parameters);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void handle(SignalServiceEnvelope envelope, boolean sendExplicitReceipt) {
|
public void handle(SignalServiceEnvelope envelope) {
|
||||||
Address source = Address.fromExternal(context, envelope.getSource());
|
Address source = Address.fromExternal(context, envelope.getSource());
|
||||||
Recipient recipient = Recipient.from(context, source, false);
|
Recipient recipient = Recipient.from(context, source, false);
|
||||||
|
|
||||||
@ -40,13 +35,13 @@ public abstract class PushReceivedJob extends ContextJob {
|
|||||||
if (envelope.isReceipt()) {
|
if (envelope.isReceipt()) {
|
||||||
handleReceipt(envelope);
|
handleReceipt(envelope);
|
||||||
} else if (envelope.isPreKeySignalMessage() || envelope.isSignalMessage()) {
|
} else if (envelope.isPreKeySignalMessage() || envelope.isSignalMessage()) {
|
||||||
handleMessage(envelope, source, sendExplicitReceipt);
|
handleMessage(envelope, source);
|
||||||
} else {
|
} else {
|
||||||
Log.w(TAG, "Received envelope of unknown type: " + envelope.getType());
|
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);
|
Recipient recipients = Recipient.from(context, source, false);
|
||||||
JobManager jobManager = ApplicationContext.getInstance(context).getJobManager();
|
JobManager jobManager = ApplicationContext.getInstance(context).getJobManager();
|
||||||
|
|
||||||
@ -56,12 +51,6 @@ public abstract class PushReceivedJob extends ContextJob {
|
|||||||
} else {
|
} else {
|
||||||
Log.w(TAG, "*** Received blocked push message, ignoring...");
|
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) {
|
private void handleReceipt(SignalServiceEnvelope envelope) {
|
||||||
|
@ -27,15 +27,13 @@ import java.io.IOException;
|
|||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
import static org.thoughtcrime.securesms.dependencies.SignalCommunicationModule.SignalMessageSenderFactory;
|
|
||||||
|
|
||||||
public class PushTextSendJob extends PushSendJob implements InjectableType {
|
public class PushTextSendJob extends PushSendJob implements InjectableType {
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
private static final String TAG = PushTextSendJob.class.getSimpleName();
|
private static final String TAG = PushTextSendJob.class.getSimpleName();
|
||||||
|
|
||||||
@Inject transient SignalMessageSenderFactory messageSenderFactory;
|
@Inject transient SignalServiceMessageSender messageSender;
|
||||||
|
|
||||||
private final long messageId;
|
private final long messageId;
|
||||||
|
|
||||||
@ -101,7 +99,6 @@ public class PushTextSendJob extends PushSendJob implements InjectableType {
|
|||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
SignalServiceAddress address = getPushAddress(message.getIndividualRecipient().getAddress());
|
SignalServiceAddress address = getPushAddress(message.getIndividualRecipient().getAddress());
|
||||||
SignalServiceMessageSender messageSender = messageSenderFactory.create();
|
|
||||||
Optional<byte[]> profileKey = getProfileKey(message.getIndividualRecipient());
|
Optional<byte[]> profileKey = getProfileKey(message.getIndividualRecipient());
|
||||||
SignalServiceDataMessage textSecureMessage = SignalServiceDataMessage.newBuilder()
|
SignalServiceDataMessage textSecureMessage = SignalServiceDataMessage.newBuilder()
|
||||||
.withTimestamp(message.getDateSent())
|
.withTimestamp(message.getDateSent())
|
||||||
|
@ -4,7 +4,6 @@ import android.content.Context;
|
|||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.dependencies.InjectableType;
|
import org.thoughtcrime.securesms.dependencies.InjectableType;
|
||||||
import org.thoughtcrime.securesms.dependencies.SignalCommunicationModule.SignalMessageSenderFactory;
|
|
||||||
import org.whispersystems.jobqueue.JobParameters;
|
import org.whispersystems.jobqueue.JobParameters;
|
||||||
import org.whispersystems.jobqueue.requirements.NetworkRequirement;
|
import org.whispersystems.jobqueue.requirements.NetworkRequirement;
|
||||||
import org.whispersystems.signalservice.api.SignalServiceMessageSender;
|
import org.whispersystems.signalservice.api.SignalServiceMessageSender;
|
||||||
@ -25,7 +24,7 @@ public class RequestGroupInfoJob extends ContextJob implements InjectableType {
|
|||||||
|
|
||||||
private static final long serialVersionUID = 0L;
|
private static final long serialVersionUID = 0L;
|
||||||
|
|
||||||
@Inject transient SignalMessageSenderFactory messageSenderFactory;
|
@Inject transient SignalServiceMessageSender messageSender;
|
||||||
|
|
||||||
private final String source;
|
private final String source;
|
||||||
private final byte[] groupId;
|
private final byte[] groupId;
|
||||||
@ -46,8 +45,6 @@ public class RequestGroupInfoJob extends ContextJob implements InjectableType {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onRun() throws IOException, UntrustedIdentityException {
|
public void onRun() throws IOException, UntrustedIdentityException {
|
||||||
SignalServiceMessageSender messageSender = messageSenderFactory.create();
|
|
||||||
|
|
||||||
SignalServiceGroup group = SignalServiceGroup.newBuilder(Type.REQUEST_INFO)
|
SignalServiceGroup group = SignalServiceGroup.newBuilder(Type.REQUEST_INFO)
|
||||||
.withId(groupId)
|
.withId(groupId)
|
||||||
.build();
|
.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.support.v4.app.NotificationManagerCompat;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
|
import com.annimon.stream.Collectors;
|
||||||
|
import com.annimon.stream.Stream;
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.ApplicationContext;
|
import org.thoughtcrime.securesms.ApplicationContext;
|
||||||
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
||||||
|
import org.thoughtcrime.securesms.database.Address;
|
||||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||||
import org.thoughtcrime.securesms.database.MessagingDatabase.ExpirationInfo;
|
import org.thoughtcrime.securesms.database.MessagingDatabase.ExpirationInfo;
|
||||||
import org.thoughtcrime.securesms.database.MessagingDatabase.MarkedMessageInfo;
|
import org.thoughtcrime.securesms.database.MessagingDatabase.MarkedMessageInfo;
|
||||||
import org.thoughtcrime.securesms.database.MessagingDatabase.SyncMessageId;
|
import org.thoughtcrime.securesms.database.MessagingDatabase.SyncMessageId;
|
||||||
import org.thoughtcrime.securesms.jobs.MultiDeviceReadUpdateJob;
|
import org.thoughtcrime.securesms.jobs.MultiDeviceReadUpdateJob;
|
||||||
|
import org.thoughtcrime.securesms.jobs.SendReadReceiptJob;
|
||||||
import org.thoughtcrime.securesms.service.ExpiringMessageManager;
|
import org.thoughtcrime.securesms.service.ExpiringMessageManager;
|
||||||
|
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
public class MarkReadReceiver extends MasterSecretBroadcastReceiver {
|
public class MarkReadReceiver extends MasterSecretBroadcastReceiver {
|
||||||
|
|
||||||
@ -72,6 +78,18 @@ public class MarkReadReceiver extends MasterSecretBroadcastReceiver {
|
|||||||
ApplicationContext.getInstance(context)
|
ApplicationContext.getInstance(context)
|
||||||
.getJobManager()
|
.getJobManager()
|
||||||
.add(new MultiDeviceReadUpdateJob(context, syncMessageIds));
|
.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) {
|
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());
|
Log.w(TAG, "Retrieved envelope! " + envelope.getSource());
|
||||||
|
|
||||||
PushContentReceiveJob receiveJob = new PushContentReceiveJob(MessageRetrievalService.this);
|
PushContentReceiveJob receiveJob = new PushContentReceiveJob(MessageRetrievalService.this);
|
||||||
receiveJob.handle(envelope, false);
|
receiveJob.handle(envelope);
|
||||||
|
|
||||||
decrementPushReceived();
|
decrementPushReceived();
|
||||||
}
|
}
|
||||||
|
@ -29,7 +29,6 @@ import org.thoughtcrime.securesms.contacts.ContactAccessor;
|
|||||||
import org.thoughtcrime.securesms.database.Address;
|
import org.thoughtcrime.securesms.database.Address;
|
||||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||||
import org.thoughtcrime.securesms.dependencies.InjectableType;
|
import org.thoughtcrime.securesms.dependencies.InjectableType;
|
||||||
import org.thoughtcrime.securesms.dependencies.SignalCommunicationModule.SignalMessageSenderFactory;
|
|
||||||
import org.thoughtcrime.securesms.events.WebRtcViewModel;
|
import org.thoughtcrime.securesms.events.WebRtcViewModel;
|
||||||
import org.thoughtcrime.securesms.notifications.MessageNotifier;
|
import org.thoughtcrime.securesms.notifications.MessageNotifier;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||||
@ -148,10 +147,9 @@ public class WebRtcCallService extends Service implements InjectableType, PeerCo
|
|||||||
private boolean remoteVideoEnabled = false;
|
private boolean remoteVideoEnabled = false;
|
||||||
private boolean bluetoothAvailable = false;
|
private boolean bluetoothAvailable = false;
|
||||||
|
|
||||||
@Inject public SignalMessageSenderFactory messageSenderFactory;
|
@Inject public SignalServiceMessageSender messageSender;
|
||||||
@Inject public SignalServiceAccountManager accountManager;
|
@Inject public SignalServiceAccountManager accountManager;
|
||||||
|
|
||||||
private SignalServiceMessageSender messageSender;
|
|
||||||
private PeerConnectionFactory peerConnectionFactory;
|
private PeerConnectionFactory peerConnectionFactory;
|
||||||
private SignalAudioManager audioManager;
|
private SignalAudioManager audioManager;
|
||||||
private BluetoothStateManager bluetoothStateManager;
|
private BluetoothStateManager bluetoothStateManager;
|
||||||
@ -271,7 +269,6 @@ public class WebRtcCallService extends Service implements InjectableType, PeerCo
|
|||||||
this.peerConnectionFactory = new PeerConnectionFactory(new PeerConnectionFactoryOptions());
|
this.peerConnectionFactory = new PeerConnectionFactory(new PeerConnectionFactoryOptions());
|
||||||
this.audioManager = new SignalAudioManager(this);
|
this.audioManager = new SignalAudioManager(this);
|
||||||
this.bluetoothStateManager = new BluetoothStateManager(this, this);
|
this.bluetoothStateManager = new BluetoothStateManager(this, this);
|
||||||
this.messageSender = messageSenderFactory.create();
|
|
||||||
this.messageSender.setSoTimeoutMillis(TimeUnit.SECONDS.toMillis(10));
|
this.messageSender.setSoTimeoutMillis(TimeUnit.SECONDS.toMillis(10));
|
||||||
this.accountManager.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 ALWAYS_RELAY_CALLS_PREF = "pref_turn_only";
|
||||||
private static final String PROFILE_KEY_PREF = "pref_profile_key";
|
private static final String PROFILE_KEY_PREF = "pref_profile_key";
|
||||||
private static final String PROFILE_NAME_PREF = "pref_profile_name";
|
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) {
|
public static @Nullable String getProfileKey(Context context) {
|
||||||
return getStringPreference(context, PROFILE_KEY_PREF, null);
|
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