Improve UI send latency

// FREEBIE
This commit is contained in:
Moxie Marlinspike 2017-04-22 16:29:26 -07:00
parent 4d889a45e2
commit cb670d6783
30 changed files with 459 additions and 94 deletions

View File

@ -102,6 +102,7 @@ import org.thoughtcrime.securesms.database.MessagingDatabase.MarkedMessageInfo;
import org.thoughtcrime.securesms.database.MmsSmsColumns.Types;
import org.thoughtcrime.securesms.database.RecipientPreferenceDatabase.RecipientPreferenceEvent;
import org.thoughtcrime.securesms.database.RecipientPreferenceDatabase.RecipientsPreferences;
import org.thoughtcrime.securesms.database.SmsDatabase;
import org.thoughtcrime.securesms.database.ThreadDatabase;
import org.thoughtcrime.securesms.jobs.MultiDeviceBlockedUpdateJob;
import org.thoughtcrime.securesms.mms.AttachmentManager;
@ -274,7 +275,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
if (!Util.isEmpty(composeText) || attachmentManager.isAttachmentPresent()) {
saveDraft();
attachmentManager.clear();
attachmentManager.clear(false);
composeText.setText("");
}
@ -566,7 +567,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
recipients.setExpireMessages(expirationTime);
OutgoingExpirationUpdateMessage outgoingMessage = new OutgoingExpirationUpdateMessage(getRecipients(), System.currentTimeMillis(), expirationTime * 1000);
MessageSender.send(ConversationActivity.this, masterSecret, outgoingMessage, threadId, false);
MessageSender.send(ConversationActivity.this, masterSecret, outgoingMessage, threadId, false, null);
return null;
}
@ -692,7 +693,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
new AsyncTask<OutgoingEndSessionMessage, Void, Long>() {
@Override
protected Long doInBackground(OutgoingEndSessionMessage... messages) {
return MessageSender.send(context, masterSecret, messages[0], threadId, false);
return MessageSender.send(context, masterSecret, messages[0], threadId, false, null);
}
@Override
@ -740,7 +741,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
.build();
OutgoingGroupMediaMessage outgoingMessage = new OutgoingGroupMediaMessage(getRecipients(), context, null, System.currentTimeMillis(), 0);
MessageSender.send(self, masterSecret, outgoingMessage, threadId, false);
MessageSender.send(self, masterSecret, outgoingMessage, threadId, false, null);
DatabaseFactory.getGroupDatabase(self).remove(groupId, TextSecurePreferences.getLocalNumber(self));
initializeEnabledCheck();
} catch (IOException e) {
@ -1511,13 +1512,19 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
outgoingMessage = new OutgoingSecureMediaMessage(outgoingMessage);
}
attachmentManager.clear();
attachmentManager.clear(false);
composeText.setText("");
final long id = fragment.stageOutgoingMessage(outgoingMessage);
new AsyncTask<OutgoingMediaMessage, Void, Long>() {
@Override
protected Long doInBackground(OutgoingMediaMessage... messages) {
return MessageSender.send(context, masterSecret, messages[0], threadId, forceSms);
return MessageSender.send(context, masterSecret, messages[0], threadId, forceSms, new SmsDatabase.InsertListener() {
@Override
public void onComplete() {
fragment.releaseOutgoingMessage(id);
}
});
}
@Override
@ -1543,11 +1550,17 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
}
this.composeText.setText("");
final long id = fragment.stageOutgoingMessage(message);
new AsyncTask<OutgoingTextMessage, Void, Long>() {
@Override
protected Long doInBackground(OutgoingTextMessage... messages) {
return MessageSender.send(context, masterSecret, messages[0], threadId, forceSms);
return MessageSender.send(context, masterSecret, messages[0], threadId, forceSms, new SmsDatabase.InsertListener() {
@Override
public void onComplete() {
fragment.releaseOutgoingMessage(id);
}
});
}
@Override

View File

@ -33,12 +33,14 @@ import android.widget.TextView;
import org.thoughtcrime.securesms.ConversationAdapter.HeaderViewHolder;
import org.thoughtcrime.securesms.crypto.MasterSecret;
import org.thoughtcrime.securesms.database.CursorRecyclerViewAdapter;
import org.thoughtcrime.securesms.database.AttachmentDatabase;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.FastCursorRecyclerViewAdapter;
import org.thoughtcrime.securesms.database.MmsSmsColumns;
import org.thoughtcrime.securesms.database.MmsSmsDatabase;
import org.thoughtcrime.securesms.database.model.MessageRecord;
import org.thoughtcrime.securesms.database.model.MmsMessageRecord;
import org.thoughtcrime.securesms.mms.SlideDeck;
import org.thoughtcrime.securesms.recipients.Recipients;
import org.thoughtcrime.securesms.util.Conversions;
import org.thoughtcrime.securesms.util.DateUtils;
@ -67,7 +69,7 @@ import java.util.Set;
*
*/
public class ConversationAdapter <V extends View & BindableConversationItem>
extends CursorRecyclerViewAdapter<ConversationAdapter.ViewHolder>
extends FastCursorRecyclerViewAdapter<ConversationAdapter.ViewHolder, MessageRecord>
implements StickyHeaderDecoration.StickyHeaderAdapter<HeaderViewHolder>
{
@ -179,14 +181,13 @@ public class ConversationAdapter <V extends View & BindableConversationItem>
@Override
public void changeCursor(Cursor cursor) {
messageRecordCache.clear();
super.cleanFastRecords();
super.changeCursor(cursor);
}
@Override
public void onBindItemViewHolder(ViewHolder viewHolder, @NonNull Cursor cursor) {
long start = System.currentTimeMillis();
MessageRecord messageRecord = getMessageRecord(cursor);
protected void onBindItemViewHolder(ViewHolder viewHolder, @NonNull MessageRecord messageRecord) {
long start = System.currentTimeMillis();
viewHolder.getView().bind(masterSecret, messageRecord, locale, batchSelected, recipients);
Log.w(TAG, "Bind time: " + (System.currentTimeMillis() - start));
}
@ -237,9 +238,7 @@ public class ConversationAdapter <V extends View & BindableConversationItem>
}
@Override
public int getItemViewType(@NonNull Cursor cursor) {
MessageRecord messageRecord = getMessageRecord(cursor);
public int getItemViewType(@NonNull MessageRecord messageRecord) {
if (messageRecord.isGroupAction() || messageRecord.isCallLog() || messageRecord.isJoined() ||
messageRecord.isExpirationTimerUpdate() || messageRecord.isEndSession() || messageRecord.isIdentityUpdate()) {
return MESSAGE_TYPE_UPDATE;
@ -259,14 +258,39 @@ public class ConversationAdapter <V extends View & BindableConversationItem>
}
}
@Override
protected boolean isRecordForId(@NonNull MessageRecord record, long id) {
return record.getId() == id;
}
@Override
public long getItemId(@NonNull Cursor cursor) {
String fastPreflightId = cursor.getString(cursor.getColumnIndexOrThrow(AttachmentDatabase.FAST_PREFLIGHT_ID));
if (fastPreflightId != null) {
return Long.valueOf(fastPreflightId);
}
final String unique = cursor.getString(cursor.getColumnIndexOrThrow(MmsSmsColumns.UNIQUE_ROW_ID));
final byte[] bytes = digest.digest(unique.getBytes());
return Conversions.byteArrayToLong(bytes);
}
private MessageRecord getMessageRecord(Cursor cursor) {
@Override
protected long getItemId(@NonNull MessageRecord record) {
if (record.isOutgoing() && record.isMms()) {
SlideDeck slideDeck = ((MmsMessageRecord)record).getSlideDeck();
if (slideDeck.getThumbnailSlide() != null && slideDeck.getThumbnailSlide().getFastPreflightId() != null) {
return Long.valueOf(slideDeck.getThumbnailSlide().getFastPreflightId());
}
}
return record.getId();
}
@Override
protected MessageRecord getRecordFromCursor(@NonNull Cursor cursor) {
long messageId = cursor.getLong(cursor.getColumnIndexOrThrow(MmsSmsColumns.ID));
String type = cursor.getString(cursor.getColumnIndexOrThrow(MmsSmsDatabase.TRANSPORT));
@ -293,8 +317,7 @@ public class ConversationAdapter <V extends View & BindableConversationItem>
int count = getItemCount();
for (int i=0;i<count;i++) {
Cursor cursor = getCursorAtPositionOrThrow(i);
MessageRecord messageRecord = getMessageRecord(cursor);
MessageRecord messageRecord = getRecordForPositionOrThrow(i);
if (messageRecord.isOutgoing() || messageRecord.getDateReceived() <= lastSeen) {
return i;
@ -339,8 +362,7 @@ public class ConversationAdapter <V extends View & BindableConversationItem>
if (position >= getItemCount()) return -1;
if (position < 0) return -1;
Cursor cursor = getCursorAtPositionOrThrow(position);
MessageRecord record = getMessageRecord(cursor);
MessageRecord record = getRecordForPositionOrThrow(position);
calendar.setTime(new Date(record.getDateSent()));
return Util.hashCode(calendar.get(Calendar.YEAR), calendar.get(Calendar.DAY_OF_YEAR));
@ -353,8 +375,7 @@ public class ConversationAdapter <V extends View & BindableConversationItem>
if (position >= getItemCount()) return 0;
if (position < 0) return 0;
Cursor cursor = getCursorAtPositionOrThrow(position);
MessageRecord messageRecord = getMessageRecord(cursor);
MessageRecord messageRecord = getRecordForPositionOrThrow(position);
if (messageRecord.isOutgoing()) return 0;
else return messageRecord.getDateReceived();
@ -371,8 +392,8 @@ public class ConversationAdapter <V extends View & BindableConversationItem>
@Override
public void onBindHeaderViewHolder(HeaderViewHolder viewHolder, int position) {
Cursor cursor = getCursorAtPositionOrThrow(position);
viewHolder.setText(DateUtils.getRelativeDate(getContext(), locale, getMessageRecord(cursor).getDateReceived()));
MessageRecord messageRecord = getRecordForPositionOrThrow(position);
viewHolder.setText(DateUtils.getRelativeDate(getContext(), locale, messageRecord.getDateReceived()));
}
public void onBindLastSeenViewHolder(HeaderViewHolder viewHolder, int position) {

View File

@ -54,20 +54,30 @@ import org.thoughtcrime.securesms.ConversationAdapter.HeaderViewHolder;
import org.thoughtcrime.securesms.ConversationAdapter.ItemClickListener;
import org.thoughtcrime.securesms.crypto.MasterSecret;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.MmsSmsColumns;
import org.thoughtcrime.securesms.database.MmsSmsDatabase;
import org.thoughtcrime.securesms.database.documents.IdentityKeyMismatch;
import org.thoughtcrime.securesms.database.documents.NetworkFailure;
import org.thoughtcrime.securesms.database.loaders.ConversationLoader;
import org.thoughtcrime.securesms.database.model.DisplayRecord;
import org.thoughtcrime.securesms.database.model.MediaMmsMessageRecord;
import org.thoughtcrime.securesms.database.model.MessageRecord;
import org.thoughtcrime.securesms.database.model.SmsMessageRecord;
import org.thoughtcrime.securesms.mms.OutgoingMediaMessage;
import org.thoughtcrime.securesms.mms.Slide;
import org.thoughtcrime.securesms.mms.SlideDeck;
import org.thoughtcrime.securesms.recipients.RecipientFactory;
import org.thoughtcrime.securesms.recipients.Recipients;
import org.thoughtcrime.securesms.sms.MessageSender;
import org.thoughtcrime.securesms.sms.OutgoingTextMessage;
import org.thoughtcrime.securesms.util.SaveAttachmentTask;
import org.thoughtcrime.securesms.util.SaveAttachmentTask.Attachment;
import org.thoughtcrime.securesms.util.StickyHeaderDecoration;
import org.thoughtcrime.securesms.util.ViewUtil;
import org.thoughtcrime.securesms.util.task.ProgressDialogAsyncTask;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedList;
@ -448,6 +458,32 @@ public class ConversationFragment extends Fragment
}
}
public long stageOutgoingMessage(OutgoingMediaMessage message) {
MessageRecord messageRecord = DatabaseFactory.getMmsDatabase(getContext()).readerFor(message, threadId).getCurrent();
if (getListAdapter() != null) {
getListAdapter().addFastRecord(messageRecord);
}
return messageRecord.getId();
}
public long stageOutgoingMessage(OutgoingTextMessage message) {
MessageRecord messageRecord = DatabaseFactory.getSmsDatabase(getContext()).readerFor(message, threadId).getCurrent();
if (getListAdapter() != null) {
getListAdapter().addFastRecord(messageRecord);
}
return messageRecord.getId();
}
public void releaseOutgoingMessage(long id) {
if (getListAdapter() != null) {
getListAdapter().releaseFastRecord(id);
}
}
private void scrollToLastSeenPosition(final int lastSeenPosition) {
if (lastSeenPosition > 0) {
list.post(new Runnable() {

View File

@ -236,7 +236,7 @@ public class InviteActivity extends PassphraseRequiredActionBarActivity implemen
Optional<RecipientsPreferences> preferences = DatabaseFactory.getRecipientPreferenceDatabase(context).getRecipientsPreferences(recipients.getIds());
int subscriptionId = preferences.isPresent() ? preferences.get().getDefaultSubscriptionId().or(-1) : -1;
MessageSender.send(context, masterSecret, new OutgoingTextMessage(recipients, message, subscriptionId), -1L, true);
MessageSender.send(context, masterSecret, new OutgoingTextMessage(recipients, message, subscriptionId), -1L, true, null);
if (recipients.getPrimaryRecipient().getContactUri() != null) {
DatabaseFactory.getRecipientPreferenceDatabase(context).setSeenInviteReminder(recipients, true);

View File

@ -28,18 +28,22 @@ public abstract class Attachment {
@Nullable
private final byte[] digest;
@Nullable
private final String fastPreflightId;
public Attachment(@NonNull String contentType, int transferState, long size, @Nullable String fileName,
@Nullable String location, @Nullable String key, @Nullable String relay,
@Nullable byte[] digest)
@Nullable byte[] digest, @Nullable String fastPreflightId)
{
this.contentType = contentType;
this.transferState = transferState;
this.size = size;
this.fileName = fileName;
this.location = location;
this.key = key;
this.relay = relay;
this.digest = digest;
this.contentType = contentType;
this.transferState = transferState;
this.size = size;
this.fileName = fileName;
this.location = location;
this.key = key;
this.relay = relay;
this.digest = digest;
this.fastPreflightId = fastPreflightId;
}
@Nullable
@ -90,4 +94,9 @@ public abstract class Attachment {
public byte[] getDigest() {
return digest;
}
@Nullable
public String getFastPreflightId() {
return fastPreflightId;
}
}

View File

@ -16,9 +16,9 @@ public class DatabaseAttachment extends Attachment {
boolean hasData, boolean hasThumbnail,
String contentType, int transferProgress, long size,
String fileName, String location, String key, String relay,
byte[] digest)
byte[] digest, String fastPreflightId)
{
super(contentType, transferProgress, size, fileName, location, key, relay, digest);
super(contentType, transferProgress, size, fileName, location, key, relay, digest, fastPreflightId);
this.attachmentId = attachmentId;
this.hasData = hasData;
this.hasThumbnail = hasThumbnail;

View File

@ -10,7 +10,7 @@ import org.thoughtcrime.securesms.database.MmsDatabase;
public class MmsNotificationAttachment extends Attachment {
public MmsNotificationAttachment(int status, long size) {
super("application/mms", getTransferStateFromStatus(status), size, null, null, null, null, null);
super("application/mms", getTransferStateFromStatus(status), size, null, null, null, null, null, null);
}
@Nullable

View File

@ -20,7 +20,7 @@ public class PointerAttachment extends Attachment {
@NonNull String key, @NonNull String relay,
@Nullable byte[] digest)
{
super(contentType, transferState, size, fileName, location, key, relay, digest);
super(contentType, transferState, size, fileName, location, key, relay, digest, null);
}
@Nullable

View File

@ -12,14 +12,14 @@ public class UriAttachment extends Attachment {
public UriAttachment(@NonNull Uri uri, @NonNull String contentType, int transferState, long size,
@Nullable String fileName)
{
this(uri, uri, contentType, transferState, size, fileName);
this(uri, uri, contentType, transferState, size, fileName, null);
}
public UriAttachment(@NonNull Uri dataUri, @Nullable Uri thumbnailUri,
@NonNull String contentType, int transferState, long size,
@Nullable String fileName)
@Nullable String fileName, @Nullable String fastPreflightId)
{
super(contentType, transferState, size, fileName, null, null, null, null);
super(contentType, transferState, size, fileName, null, null, null, null, fastPreflightId);
this.dataUri = dataUri;
this.thumbnailUri = thumbnailUri;
}

View File

@ -66,7 +66,7 @@ public class ThumbnailView extends FrameLayout {
if (attrs != null) {
TypedArray typedArray = context.getTheme().obtainStyledAttributes(attrs, R.styleable.ThumbnailView, 0, 0);
backgroundColorHint = typedArray.getColor(0, Color.BLACK);
backgroundColorHint = typedArray.getColor(R.styleable.ThumbnailView_backgroundColorHint, Color.BLACK);
typedArray.recycle();
}
}
@ -120,13 +120,22 @@ public class ThumbnailView extends FrameLayout {
return;
}
if (this.slide != null && this.slide.getFastPreflightId() != null &&
this.slide.getFastPreflightId().equals(slide.getFastPreflightId()))
{
Log.w(TAG, "Not re-loading slide for fast preflight: " + slide.getFastPreflightId());
this.slide = slide;
return;
}
if (!isContextValid()) {
Log.w(TAG, "Not loading slide, context is invalid");
return;
}
Log.w(TAG, "loading part with id " + slide.asAttachment().getDataUri()
+ ", progress " + slide.getTransferState());
+ ", progress " + slide.getTransferState() + ", fast preflight id: " +
slide.asAttachment().getFastPreflightId());
this.slide = slide;

View File

@ -86,6 +86,7 @@ public class AttachmentDatabase extends Database {
static final String THUMBNAIL_ASPECT_RATIO = "aspect_ratio";
static final String UNIQUE_ID = "unique_id";
static final String DIGEST = "digest";
public static final String FAST_PREFLIGHT_ID = "fast_preflight_id";
public static final int TRANSFER_PROGRESS_DONE = 0;
public static final int TRANSFER_PROGRESS_STARTED = 1;
@ -98,7 +99,7 @@ public class AttachmentDatabase extends Database {
MMS_ID, CONTENT_TYPE, NAME, CONTENT_DISPOSITION,
CONTENT_LOCATION, DATA, THUMBNAIL, TRANSFER_STATE,
SIZE, FILE_NAME, THUMBNAIL, THUMBNAIL_ASPECT_RATIO,
UNIQUE_ID, DIGEST};
UNIQUE_ID, DIGEST, FAST_PREFLIGHT_ID};
public static final String CREATE_TABLE = "CREATE TABLE " + TABLE_NAME + " (" + ROW_ID + " INTEGER PRIMARY KEY, " +
MMS_ID + " INTEGER, " + "seq" + " INTEGER DEFAULT 0, " +
@ -108,7 +109,7 @@ public class AttachmentDatabase extends Database {
"ctt_t" + " TEXT, " + "encrypted" + " INTEGER, " +
TRANSFER_STATE + " INTEGER, "+ DATA + " TEXT, " + SIZE + " INTEGER, " +
FILE_NAME + " TEXT, " + THUMBNAIL + " TEXT, " + THUMBNAIL_ASPECT_RATIO + " REAL, " +
UNIQUE_ID + " INTEGER NOT NULL, " + DIGEST + " BLOB);";
UNIQUE_ID + " INTEGER NOT NULL, " + DIGEST + " BLOB, " + FAST_PREFLIGHT_ID + " TEXT);";
public static final String[] CREATE_INDEXS = {
"CREATE INDEX IF NOT EXISTS part_mms_id_index ON " + TABLE_NAME + " (" + MMS_ID + ");",
@ -276,6 +277,7 @@ public class AttachmentDatabase extends Database {
values.put(CONTENT_DISPOSITION, (String)null);
values.put(DIGEST, (byte[])null);
values.put(NAME, (String) null);
values.put(FAST_PREFLIGHT_ID, (String)null);
if (database.update(TABLE_NAME, values, PART_ID_WHERE, attachmentId.toStrings()) == 0) {
//noinspection ResultOfMethodCallIgnored
@ -334,7 +336,8 @@ public class AttachmentDatabase extends Database {
databaseAttachment.getLocation(),
databaseAttachment.getKey(),
databaseAttachment.getRelay(),
databaseAttachment.getDigest());
databaseAttachment.getDigest(),
databaseAttachment.getFastPreflightId());
}
@ -485,7 +488,8 @@ public class AttachmentDatabase extends Database {
cursor.getString(cursor.getColumnIndexOrThrow(CONTENT_LOCATION)),
cursor.getString(cursor.getColumnIndexOrThrow(CONTENT_DISPOSITION)),
cursor.getString(cursor.getColumnIndexOrThrow(NAME)),
cursor.getBlob(cursor.getColumnIndexOrThrow(DIGEST)));
cursor.getBlob(cursor.getColumnIndexOrThrow(DIGEST)),
cursor.getString(cursor.getColumnIndexOrThrow(FAST_PREFLIGHT_ID)));
}
@ -519,6 +523,7 @@ public class AttachmentDatabase extends Database {
contentValues.put(NAME, attachment.getRelay());
contentValues.put(FILE_NAME, fileName);
contentValues.put(SIZE, attachment.getSize());
contentValues.put(FAST_PREFLIGHT_ID, attachment.getFastPreflightId());
if (partData != null) {
contentValues.put(DATA, partData.first.getAbsolutePath());

View File

@ -115,6 +115,7 @@ public abstract class CursorRecyclerViewAdapter<VH extends RecyclerView.ViewHold
if (!isActiveCursor()) return 0;
return cursor.getCount()
+ getFastAccessSize()
+ (hasHeaderView() ? 1 : 0)
+ (hasFooterView() ? 1 : 0);
}
@ -144,16 +145,22 @@ public abstract class CursorRecyclerViewAdapter<VH extends RecyclerView.ViewHold
@Override
public final void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int position) {
if (!isHeaderPosition(position) && !isFooterPosition(position)) {
onBindItemViewHolder((VH)viewHolder, getCursorAtPositionOrThrow(position));
if (isFastAccessPosition(position)) onBindFastAccessItemViewHolder((VH)viewHolder, position);
else onBindItemViewHolder((VH)viewHolder, getCursorAtPositionOrThrow(position));
}
}
public abstract void onBindItemViewHolder(VH viewHolder, @NonNull Cursor cursor);
protected void onBindFastAccessItemViewHolder(VH viewHolder, int position) {
}
@Override
public final int getItemViewType(int position) {
if (isHeaderPosition(position)) return HEADER_TYPE;
if (isFooterPosition(position)) return FOOTER_TYPE;
if (isHeaderPosition(position)) return HEADER_TYPE;
if (isFooterPosition(position)) return FOOTER_TYPE;
if (isFastAccessPosition(position)) return getFastAccessItemViewType(position);
return getItemViewType(getCursorAtPositionOrThrow(position));
}
@ -163,8 +170,9 @@ public abstract class CursorRecyclerViewAdapter<VH extends RecyclerView.ViewHold
@Override
public final long getItemId(int position) {
if (isHeaderPosition(position)) return HEADER_ID;
if (isFooterPosition(position)) return FOOTER_ID;
if (isHeaderPosition(position)) return HEADER_ID;
if (isFooterPosition(position)) return FOOTER_ID;
if (isFastAccessPosition(position)) return getFastAccessItemId(position);
long itemId = getItemId(getCursorAtPositionOrThrow(position));
return itemId <= Long.MIN_VALUE + 1 ? itemId + 2 : itemId;
}
@ -196,7 +204,27 @@ public abstract class CursorRecyclerViewAdapter<VH extends RecyclerView.ViewHold
}
private int getCursorPosition(int position) {
return hasHeaderView() ? position - 1 : position;
if (hasHeaderView()) {
position -= 1;
}
return position - getFastAccessSize();
}
protected int getFastAccessItemViewType(int position) {
return 0;
}
protected boolean isFastAccessPosition(int position) {
return false;
}
protected long getFastAccessItemId(int position) {
return 0;
}
protected int getFastAccessSize() {
return 0;
}
private class AdapterDataSetObserver extends DataSetObserver {

View File

@ -77,7 +77,8 @@ public class DatabaseFactory {
private static final int INTRODUCED_DIGEST = 30;
private static final int INTRODUCED_NOTIFIED = 31;
private static final int INTRODUCED_DOCUMENTS = 32;
private static final int DATABASE_VERSION = 32;
private static final int INTRODUCED_FAST_PREFLIGHT = 33;
private static final int DATABASE_VERSION = 33;
private static final String DATABASE_NAME = "messages.db";
private static final Object lock = new Object();
@ -858,6 +859,10 @@ public class DatabaseFactory {
db.execSQL("ALTER TABLE part ADD COLUMN file_name TEXT");
}
if (oldVersion < INTRODUCED_FAST_PREFLIGHT) {
db.execSQL("ALTER TABLE part ADD COLUMN fast_preflight_id TEXT");
}
db.setTransactionSuccessful();
db.endTransaction();
}

View File

@ -64,7 +64,7 @@ public class EncryptingSmsDatabase extends SmsDatabase {
public long insertMessageOutbox(MasterSecretUnion masterSecret, long threadId,
OutgoingTextMessage message, boolean forceSms,
long timestamp)
long timestamp, InsertListener insertListener)
{
long type = Types.BASE_SENDING_TYPE;
@ -76,7 +76,7 @@ public class EncryptingSmsDatabase extends SmsDatabase {
type |= Types.ENCRYPTION_ASYMMETRIC_BIT;
}
return insertMessageOutbox(threadId, message, type, forceSms, timestamp);
return insertMessageOutbox(threadId, message, type, forceSms, timestamp, insertListener);
}
public Optional<InsertResult> insertMessageInbox(@NonNull MasterSecretUnion masterSecret,

View File

@ -0,0 +1,111 @@
package org.thoughtcrime.securesms.database;
import android.content.Context;
import android.database.Cursor;
import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
public abstract class FastCursorRecyclerViewAdapter<VH extends RecyclerView.ViewHolder, T>
extends CursorRecyclerViewAdapter<VH>
{
private static final String TAG = FastCursorRecyclerViewAdapter.class.getSimpleName();
private final LinkedList<T> fastRecords = new LinkedList<>();
private final List<Long> releasedRecordIds = new LinkedList<>();
protected FastCursorRecyclerViewAdapter(Context context, Cursor cursor) {
super(context, cursor);
}
public void addFastRecord(@NonNull T record) {
fastRecords.addFirst(record);
notifyDataSetChanged();
}
public void releaseFastRecord(long id) {
synchronized (releasedRecordIds) {
releasedRecordIds.add(id);
}
}
protected void cleanFastRecords() {
synchronized (releasedRecordIds) {
Iterator<Long> releaseIdIterator = releasedRecordIds.iterator();
while (releaseIdIterator.hasNext()) {
long releasedId = releaseIdIterator.next();
Iterator<T> fastRecordIterator = fastRecords.iterator();
while (fastRecordIterator.hasNext()) {
if (isRecordForId(fastRecordIterator.next(), releasedId)) {
fastRecordIterator.remove();
releaseIdIterator.remove();
break;
}
}
}
}
}
protected abstract T getRecordFromCursor(@NonNull Cursor cursor);
protected abstract void onBindItemViewHolder(VH viewHolder, @NonNull T record);
protected abstract long getItemId(@NonNull T record);
protected abstract int getItemViewType(@NonNull T record);
protected abstract boolean isRecordForId(@NonNull T record, long id);
@Override
public int getItemViewType(@NonNull Cursor cursor) {
T record = getRecordFromCursor(cursor);
return getItemViewType(record);
}
@Override
public void onBindItemViewHolder(VH viewHolder, @NonNull Cursor cursor) {
T record = getRecordFromCursor(cursor);
onBindItemViewHolder(viewHolder, record);
}
@Override
public void onBindFastAccessItemViewHolder(VH viewHolder, int position) {
onBindItemViewHolder(viewHolder, fastRecords.get(getCalculatedPosition(position)));
}
@Override
protected int getFastAccessSize() {
return fastRecords.size();
}
protected T getRecordForPositionOrThrow(int position) {
if (isFastAccessPosition(position)) {
return fastRecords.get(getCalculatedPosition(position));
} else {
Cursor cursor = getCursorAtPositionOrThrow(position);
return getRecordFromCursor(cursor);
}
}
protected int getFastAccessItemViewType(int position) {
return getItemViewType(fastRecords.get(getCalculatedPosition(position)));
}
protected boolean isFastAccessPosition(int position) {
position = getCalculatedPosition(position);
return position >= 0 && position < fastRecords.size();
}
protected long getFastAccessItemId(int position) {
return getItemId(fastRecords.get(getCalculatedPosition(position)));
}
private int getCalculatedPosition(int position) {
return hasHeaderView() ? position - 1 : position;
}
}

View File

@ -26,6 +26,7 @@ public class MediaDatabase extends Database {
+ AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.CONTENT_LOCATION + ", "
+ AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.CONTENT_DISPOSITION + ", "
+ AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.DIGEST + ", "
+ AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.FAST_PREFLIGHT_ID + ", "
+ AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.NAME + ", "
+ MmsDatabase.TABLE_NAME + "." + MmsDatabase.MESSAGE_BOX + ", "
+ MmsDatabase.TABLE_NAME + "." + MmsDatabase.DATE_SENT + ", "

View File

@ -19,6 +19,7 @@ package org.thoughtcrime.securesms.database;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.MatrixCursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.net.Uri;
@ -69,6 +70,8 @@ import org.whispersystems.libsignal.util.guava.Optional;
import org.whispersystems.signalservice.api.util.InvalidNumberException;
import java.io.IOException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
@ -144,6 +147,7 @@ public class MmsDatabase extends MessagingDatabase {
AttachmentDatabase.CONTENT_TYPE,
AttachmentDatabase.CONTENT_LOCATION,
AttachmentDatabase.DIGEST,
AttachmentDatabase.FAST_PREFLIGHT_ID,
AttachmentDatabase.CONTENT_DISPOSITION,
AttachmentDatabase.NAME,
AttachmentDatabase.TRANSFER_STATE
@ -694,7 +698,8 @@ public class MmsDatabase extends MessagingDatabase {
databaseAttachment.getLocation(),
databaseAttachment.getKey(),
databaseAttachment.getRelay(),
databaseAttachment.getDigest()));
databaseAttachment.getDigest(),
databaseAttachment.getFastPreflightId()));
}
return insertMediaMessage(new MasterSecretUnion(masterSecret),
@ -867,7 +872,8 @@ public class MmsDatabase extends MessagingDatabase {
public long insertMessageOutbox(@NonNull MasterSecretUnion masterSecret,
@NonNull OutgoingMediaMessage message,
long threadId, boolean forceSms)
long threadId, boolean forceSms,
SmsDatabase.InsertListener insertListener)
throws MmsException
{
long type = Types.BASE_SENDING_TYPE;
@ -924,6 +930,10 @@ public class MmsDatabase extends MessagingDatabase {
long messageId = insertMediaMessage(masterSecret, addresses, message.getBody(),
message.getAttachments(), contentValues);
if (insertListener != null) {
insertListener.onComplete();
}
DatabaseFactory.getThreadDatabase(context).setLastSeen(threadId);
jobManager.add(new TrimThreadJob(context, threadId));
@ -1106,6 +1116,10 @@ public class MmsDatabase extends MessagingDatabase {
return new Reader(masterSecret, cursor);
}
public OutgoingMessageReader readerFor(OutgoingMediaMessage message, long threadId) {
return new OutgoingMessageReader(message, threadId);
}
public static class Status {
public static final int DOWNLOAD_INITIALIZED = 1;
public static final int DOWNLOAD_NO_CONNECTIVITY = 2;
@ -1115,6 +1129,39 @@ public class MmsDatabase extends MessagingDatabase {
public static final int DOWNLOAD_APN_UNAVAILABLE = 6;
}
public class OutgoingMessageReader {
private final OutgoingMediaMessage message;
private final long id;
private final long threadId;
public OutgoingMessageReader(OutgoingMediaMessage message, long threadId) {
try {
this.message = message;
this.id = SecureRandom.getInstance("SHA1PRNG").nextLong();
this.threadId = threadId;
} catch (NoSuchAlgorithmException e) {
throw new AssertionError(e);
}
}
public MessageRecord getCurrent() {
SlideDeck slideDeck = new SlideDeck(context, message.getAttachments());
return new MediaMmsMessageRecord(context, id, message.getRecipients(),
message.getRecipients().getPrimaryRecipient(),
1, System.currentTimeMillis(), System.currentTimeMillis(),
0, threadId, new DisplayRecord.Body(message.getBody(), true),
slideDeck, slideDeck.getSlides().size(),
message.isSecure() ? MmsSmsColumns.Types.getOutgoingEncryptedMessageType() : MmsSmsColumns.Types.getOutgoingSmsMessageType(),
new LinkedList<IdentityKeyMismatch>(),
new LinkedList<NetworkFailure>(),
message.getSubscriptionId(),
message.getExpiresIn(),
System.currentTimeMillis());
}
}
public class Reader {
private final Cursor cursor;

View File

@ -97,6 +97,14 @@ public interface MmsSmsColumns {
return false;
}
public static long getOutgoingEncryptedMessageType() {
return Types.BASE_SENDING_TYPE | Types.SECURE_MESSAGE_BIT | Types.PUSH_MESSAGE_BIT;
}
public static long getOutgoingSmsMessageType() {
return Types.BASE_SENDING_TYPE;
}
public static boolean isForcedSms(long type) {
return (type & MESSAGE_FORCE_SMS_BIT) != 0;
}

View File

@ -70,6 +70,7 @@ public class MmsSmsDatabase extends Database {
AttachmentDatabase.CONTENT_TYPE,
AttachmentDatabase.CONTENT_LOCATION,
AttachmentDatabase.DIGEST,
AttachmentDatabase.FAST_PREFLIGHT_ID,
AttachmentDatabase.CONTENT_DISPOSITION,
AttachmentDatabase.NAME,
AttachmentDatabase.TRANSFER_STATE};
@ -165,6 +166,7 @@ public class MmsSmsDatabase extends Database {
AttachmentDatabase.CONTENT_TYPE,
AttachmentDatabase.CONTENT_LOCATION,
AttachmentDatabase.DIGEST,
AttachmentDatabase.FAST_PREFLIGHT_ID,
AttachmentDatabase.CONTENT_DISPOSITION,
AttachmentDatabase.NAME,
AttachmentDatabase.TRANSFER_STATE};
@ -194,6 +196,7 @@ public class MmsSmsDatabase extends Database {
AttachmentDatabase.CONTENT_TYPE,
AttachmentDatabase.CONTENT_LOCATION,
AttachmentDatabase.DIGEST,
AttachmentDatabase.FAST_PREFLIGHT_ID,
AttachmentDatabase.CONTENT_DISPOSITION,
AttachmentDatabase.NAME,
AttachmentDatabase.TRANSFER_STATE};
@ -249,6 +252,7 @@ public class MmsSmsDatabase extends Database {
mmsColumnsPresent.add(AttachmentDatabase.CONTENT_TYPE);
mmsColumnsPresent.add(AttachmentDatabase.CONTENT_LOCATION);
mmsColumnsPresent.add(AttachmentDatabase.DIGEST);
mmsColumnsPresent.add(AttachmentDatabase.FAST_PREFLIGHT_ID);
mmsColumnsPresent.add(AttachmentDatabase.CONTENT_DISPOSITION);
mmsColumnsPresent.add(AttachmentDatabase.NAME);
mmsColumnsPresent.add(AttachmentDatabase.TRANSFER_STATE);

View File

@ -32,6 +32,7 @@ import org.thoughtcrime.securesms.ApplicationContext;
import org.thoughtcrime.securesms.database.documents.IdentityKeyMismatch;
import org.thoughtcrime.securesms.database.documents.IdentityKeyMismatchList;
import org.thoughtcrime.securesms.database.model.DisplayRecord;
import org.thoughtcrime.securesms.database.model.MessageRecord;
import org.thoughtcrime.securesms.database.model.SmsMessageRecord;
import org.thoughtcrime.securesms.jobs.TrimThreadJob;
import org.thoughtcrime.securesms.recipients.Recipient;
@ -46,6 +47,8 @@ import org.whispersystems.libsignal.util.guava.Optional;
import org.whispersystems.signalservice.api.util.InvalidNumberException;
import java.io.IOException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
@ -594,7 +597,8 @@ public class SmsDatabase extends MessagingDatabase {
}
protected long insertMessageOutbox(long threadId, OutgoingTextMessage message,
long type, boolean forceSms, long date)
long type, boolean forceSms, long date,
InsertListener insertListener)
{
if (message.isKeyExchange()) type |= Types.KEY_EXCHANGE_BIT;
else if (message.isSecureMessage()) type |= (Types.SECURE_MESSAGE_BIT | Types.PUSH_MESSAGE_BIT);
@ -623,6 +627,10 @@ public class SmsDatabase extends MessagingDatabase {
SQLiteDatabase db = databaseHelper.getWritableDatabase();
long messageId = db.insert(TABLE_NAME, ADDRESS, contentValues);
if (insertListener != null) {
insertListener.onComplete();
}
DatabaseFactory.getThreadDatabase(context).update(threadId, true);
DatabaseFactory.getThreadDatabase(context).setLastSeen(threadId);
notifyConversationListeners(threadId);
@ -768,6 +776,37 @@ public class SmsDatabase extends MessagingDatabase {
return new Reader(cursor);
}
public OutgoingMessageReader readerFor(OutgoingTextMessage message, long threadId) {
return new OutgoingMessageReader(message, threadId);
}
public class OutgoingMessageReader {
private final OutgoingTextMessage message;
private final long id;
private final long threadId;
public OutgoingMessageReader(OutgoingTextMessage message, long threadId) {
try {
this.message = message;
this.threadId = threadId;
this.id = SecureRandom.getInstance("SHA1PRNG").nextLong();
} catch (NoSuchAlgorithmException e) {
throw new AssertionError(e);
}
}
public MessageRecord getCurrent() {
return new SmsMessageRecord(context, id, new DisplayRecord.Body(message.getMessageBody(), true),
message.getRecipients(), message.getRecipients().getPrimaryRecipient(),
1, System.currentTimeMillis(), System.currentTimeMillis(),
0, message.isSecureMessage() ? MmsSmsColumns.Types.getOutgoingEncryptedMessageType() : MmsSmsColumns.Types.getOutgoingSmsMessageType(),
threadId, 0, new LinkedList<IdentityKeyMismatch>(),
message.getSubscriptionId(), message.getExpiresIn(),
System.currentTimeMillis());
}
}
public class Reader {
private final Cursor cursor;
@ -858,4 +897,8 @@ public class SmsDatabase extends MessagingDatabase {
}
}
public interface InsertListener {
public void onComplete();
}
}

View File

@ -108,7 +108,7 @@ public class GroupManager {
}
OutgoingGroupMediaMessage outgoingMessage = new OutgoingGroupMediaMessage(groupRecipient, groupContext, avatarAttachment, System.currentTimeMillis(), 0);
long threadId = MessageSender.send(context, masterSecret, outgoingMessage, -1, false);
long threadId = MessageSender.send(context, masterSecret, outgoingMessage, -1, false, null);
return new GroupActionResult(groupRecipient, threadId);
}

View File

@ -205,7 +205,7 @@ public class GroupMessageProcessor {
Recipients recipients = RecipientFactory.getRecipientsFromString(context, GroupUtil.getEncodedId(group.getGroupId()), false);
OutgoingGroupMediaMessage outgoingMessage = new OutgoingGroupMediaMessage(recipients, storage, null, envelope.getTimestamp(), 0);
long threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipients);
long messageId = mmsDatabase.insertMessageOutbox(masterSecret, outgoingMessage, threadId, false);
long messageId = mmsDatabase.insertMessageOutbox(masterSecret, outgoingMessage, threadId, false, null);
mmsDatabase.markAsSent(messageId, true);

View File

@ -321,7 +321,7 @@ public class PushDecryptJob extends ContextJob {
SecurityEvent.broadcastSecurityUpdateEvent(context);
long messageId = database.insertMessageOutbox(masterSecret, threadId, outgoingEndSessionMessage,
false, message.getTimestamp());
false, message.getTimestamp(), null);
database.markAsSent(messageId, true);
}
@ -521,7 +521,7 @@ public class PushDecryptJob extends ContextJob {
message.getMessage().getExpiresInSeconds() * 1000);
long threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipients);
long messageId = database.insertMessageOutbox(masterSecret, expirationUpdateMessage, threadId, false);
long messageId = database.insertMessageOutbox(masterSecret, expirationUpdateMessage, threadId, false, null);
database.markAsSent(messageId, true);
@ -554,7 +554,7 @@ public class PushDecryptJob extends ContextJob {
}
long threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipients);
long messageId = database.insertMessageOutbox(masterSecret, mediaMessage, threadId, false);
long messageId = database.insertMessageOutbox(masterSecret, mediaMessage, threadId, false, null);
database.markAsSent(messageId, true);
@ -635,7 +635,7 @@ public class PushDecryptJob extends ContextJob {
}
long threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipients);
long messageId = database.insertMessageOutbox(masterSecret, threadId, outgoingTextMessage, false, message.getTimestamp());
long messageId = database.insertMessageOutbox(masterSecret, threadId, outgoingTextMessage, false, message.getTimestamp(), null);
database.markAsSent(messageId, true);

View File

@ -35,6 +35,7 @@ import android.util.Log;
import android.view.View;
import android.widget.Toast;
import com.bumptech.glide.Glide;
import com.google.android.gms.common.GooglePlayServicesNotAvailableException;
import com.google.android.gms.common.GooglePlayServicesRepairableException;
import com.google.android.gms.location.places.ui.PlacePicker;
@ -109,20 +110,27 @@ public class AttachmentManager {
}
public void clear() {
public void clear(boolean animate) {
if (attachmentViewStub.resolved()) {
ViewUtil.fadeOut(attachmentViewStub.get(), 200).addListener(new Listener<Boolean>() {
@Override
public void onSuccess(Boolean result) {
thumbnail.clear();
attachmentViewStub.get().setVisibility(View.GONE);
attachmentListener.onAttachmentChanged();
}
@Override
public void onFailure(ExecutionException e) {
}
});
if (animate) {
ViewUtil.fadeOut(attachmentViewStub.get(), 200).addListener(new Listener<Boolean>() {
@Override
public void onSuccess(Boolean result) {
thumbnail.clear();
attachmentViewStub.get().setVisibility(View.GONE);
attachmentListener.onAttachmentChanged();
}
@Override
public void onFailure(ExecutionException e) {
}
});
} else {
thumbnail.clear();
attachmentViewStub.get().setVisibility(View.GONE);
attachmentListener.onAttachmentChanged();
}
markGarbage(getSlideUri());
slide = Optional.absent();
@ -413,7 +421,7 @@ public class AttachmentManager {
@Override
public void onClick(View v) {
cleanup();
clear();
clear(true);
}
}

View File

@ -41,7 +41,7 @@ public class AudioSlide extends Slide {
}
public AudioSlide(Context context, Uri uri, long dataSize, String contentType) {
super(context, new UriAttachment(uri, null, contentType, AttachmentDatabase.TRANSFER_PROGRESS_STARTED, dataSize, null));
super(context, new UriAttachment(uri, null, contentType, AttachmentDatabase.TRANSFER_PROGRESS_STARTED, dataSize, null, null));
}
public AudioSlide(Context context, Attachment attachment) {

View File

@ -30,6 +30,9 @@ import org.thoughtcrime.securesms.util.MediaUtil;
import org.thoughtcrime.securesms.util.Util;
import org.whispersystems.libsignal.util.guava.Optional;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
public abstract class Slide {
protected final Attachment attachment;
@ -65,6 +68,11 @@ public abstract class Slide {
return Optional.fromNullable(attachment.getFileName());
}
@Nullable
public String getFastPreflightId() {
return attachment.getFastPreflightId();
}
public long getFileSize() {
return attachment.getSize();
}
@ -127,12 +135,18 @@ public abstract class Slide {
boolean hasThumbnail,
@Nullable String fileName)
{
Optional<String> resolvedType = Optional.fromNullable(MediaUtil.getMimeType(context, uri));
return new UriAttachment(uri, hasThumbnail ? uri : null, resolvedType.or(defaultMime), AttachmentDatabase.TRANSFER_PROGRESS_STARTED, size, fileName);
try {
Optional<String> resolvedType = Optional.fromNullable(MediaUtil.getMimeType(context, uri));
String fastPreflightId = String.valueOf(SecureRandom.getInstance("SHA1PRNG").nextLong());
return new UriAttachment(uri, hasThumbnail ? uri : null, resolvedType.or(defaultMime), AttachmentDatabase.TRANSFER_PROGRESS_STARTED, size, fileName, fastPreflightId);
} catch (NoSuchAlgorithmException e) {
throw new AssertionError(e);
}
}
@Override
public boolean equals(Object other) {
if (other == null) return false;
if (!(other instanceof Slide)) return false;
Slide that = (Slide)other;

View File

@ -81,13 +81,13 @@ public class AndroidAutoReplyReceiver extends MasterSecretBroadcastReceiver {
long expiresIn = preferences.isPresent() ? preferences.get().getExpireMessages() * 1000 : 0;
if (recipients.isGroupRecipient()) {
Log.i("AndroidAutoReplyReceiver", "GroupRecipient, Sending media message");
Log.w("AndroidAutoReplyReceiver", "GroupRecipient, Sending media message");
OutgoingMediaMessage reply = new OutgoingMediaMessage(recipients, responseText.toString(), new LinkedList<Attachment>(), System.currentTimeMillis(), subscriptionId, expiresIn, 0);
replyThreadId = MessageSender.send(context, masterSecret, reply, threadId, false);
replyThreadId = MessageSender.send(context, masterSecret, reply, threadId, false, null);
} else {
Log.i("AndroidAutoReplyReceiver", "Sending regular message ");
Log.w("AndroidAutoReplyReceiver", "Sending regular message ");
OutgoingTextMessage reply = new OutgoingTextMessage(recipients, responseText.toString(), expiresIn, subscriptionId);
replyThreadId = MessageSender.send(context, masterSecret, reply, threadId, false);
replyThreadId = MessageSender.send(context, masterSecret, reply, threadId, false, null);
}
List<MarkedMessageInfo> messageIds = DatabaseFactory.getThreadDatabase(context).setRead(replyThreadId, true);

View File

@ -74,10 +74,10 @@ public class RemoteReplyReceiver extends MasterSecretBroadcastReceiver {
Recipients recipients = RecipientFactory.getRecipientsForIds(context, recipientIds, false);
if (recipients.isGroupRecipient()) {
OutgoingMediaMessage reply = new OutgoingMediaMessage(recipients, responseText.toString(), new LinkedList<Attachment>(), System.currentTimeMillis(), subscriptionId, expiresIn, 0);
threadId = MessageSender.send(context, masterSecret, reply, -1, false);
threadId = MessageSender.send(context, masterSecret, reply, -1, false, null);
} else {
OutgoingTextMessage reply = new OutgoingTextMessage(recipients, responseText.toString(), expiresIn, subscriptionId);
threadId = MessageSender.send(context, masterSecret, reply, -1, false);
threadId = MessageSender.send(context, masterSecret, reply, -1, false, null);
}
List<MarkedMessageInfo> messageIds = DatabaseFactory.getThreadDatabase(context).setRead(threadId, true);

View File

@ -60,10 +60,10 @@ public class QuickResponseService extends MasterSecretIntentService {
if (!TextUtils.isEmpty(content)) {
if (recipients.isSingleRecipient()) {
MessageSender.send(this, masterSecret, new OutgoingTextMessage(recipients, content, expiresIn, subscriptionId), -1, false);
MessageSender.send(this, masterSecret, new OutgoingTextMessage(recipients, content, expiresIn, subscriptionId), -1, false, null);
} else {
MessageSender.send(this, masterSecret, new OutgoingMediaMessage(recipients, new SlideDeck(), content, System.currentTimeMillis(),
subscriptionId, expiresIn, ThreadDatabase.DistributionTypes.DEFAULT), -1, false);
subscriptionId, expiresIn, ThreadDatabase.DistributionTypes.DEFAULT), -1, false, null);
}
}
} catch (URISyntaxException e) {

View File

@ -27,6 +27,7 @@ import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.EncryptingSmsDatabase;
import org.thoughtcrime.securesms.database.MmsDatabase;
import org.thoughtcrime.securesms.database.NotInDirectoryException;
import org.thoughtcrime.securesms.database.SmsDatabase;
import org.thoughtcrime.securesms.database.TextSecureDirectory;
import org.thoughtcrime.securesms.database.ThreadDatabase;
import org.thoughtcrime.securesms.database.model.MessageRecord;
@ -61,7 +62,8 @@ public class MessageSender {
final MasterSecret masterSecret,
final OutgoingTextMessage message,
final long threadId,
final boolean forceSms)
final boolean forceSms,
final SmsDatabase.InsertListener insertListener)
{
EncryptingSmsDatabase database = DatabaseFactory.getEncryptingSmsDatabase(context);
Recipients recipients = message.getRecipients();
@ -76,7 +78,7 @@ public class MessageSender {
}
long messageId = database.insertMessageOutbox(new MasterSecretUnion(masterSecret), allocatedThreadId,
message, forceSms, System.currentTimeMillis());
message, forceSms, System.currentTimeMillis(), insertListener);
sendTextMessage(context, recipients, forceSms, keyExchange, messageId, message.getExpiresIn());
@ -87,7 +89,8 @@ public class MessageSender {
final MasterSecret masterSecret,
final OutgoingMediaMessage message,
final long threadId,
final boolean forceSms)
final boolean forceSms,
final SmsDatabase.InsertListener insertListener)
{
try {
ThreadDatabase threadDatabase = DatabaseFactory.getThreadDatabase(context);
@ -102,7 +105,7 @@ public class MessageSender {
}
Recipients recipients = message.getRecipients();
long messageId = database.insertMessageOutbox(new MasterSecretUnion(masterSecret), message, allocatedThreadId, forceSms);
long messageId = database.insertMessageOutbox(new MasterSecretUnion(masterSecret), message, allocatedThreadId, forceSms, insertListener);
sendMediaMessage(context, masterSecret, recipients, forceSms, messageId, message.getExpiresIn());