Join attachments instead of running an asynchronous query.

No more SlideDeck futures, just SlideDecks.

// FREEBIE
This commit is contained in:
Moxie Marlinspike 2015-10-21 15:32:19 -07:00
parent 25e099a309
commit d2f44f6584
11 changed files with 155 additions and 335 deletions

View File

@ -41,7 +41,6 @@ import org.thoughtcrime.securesms.mms.Slide;
import org.thoughtcrime.securesms.recipients.RecipientFactory; import org.thoughtcrime.securesms.recipients.RecipientFactory;
import org.thoughtcrime.securesms.recipients.Recipients; import org.thoughtcrime.securesms.recipients.Recipients;
import org.thoughtcrime.securesms.sms.MessageSender; import org.thoughtcrime.securesms.sms.MessageSender;
import org.thoughtcrime.securesms.util.FutureTaskListener;
import org.thoughtcrime.securesms.util.ProgressDialogAsyncTask; import org.thoughtcrime.securesms.util.ProgressDialogAsyncTask;
import org.thoughtcrime.securesms.util.SaveAttachmentTask; import org.thoughtcrime.securesms.util.SaveAttachmentTask;
import org.thoughtcrime.securesms.util.SaveAttachmentTask.Attachment; import org.thoughtcrime.securesms.util.SaveAttachmentTask.Attachment;
@ -305,21 +304,16 @@ public class ConversationFragment extends Fragment
private void handleSaveAttachment(final MediaMmsMessageRecord message) { private void handleSaveAttachment(final MediaMmsMessageRecord message) {
SaveAttachmentTask.showWarningDialog(getActivity(), new DialogInterface.OnClickListener() { SaveAttachmentTask.showWarningDialog(getActivity(), new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) { public void onClick(DialogInterface dialog, int which) {
for (Slide slide : message.getSlideDeck().getSlides()) {
message.fetchMediaSlide(new FutureTaskListener<Slide>() { if (slide.hasImage() || slide.hasVideo() || slide.hasAudio()) {
@Override
public void onSuccess(Slide slide) {
SaveAttachmentTask saveTask = new SaveAttachmentTask(getActivity(), masterSecret); SaveAttachmentTask saveTask = new SaveAttachmentTask(getActivity(), masterSecret);
saveTask.execute(new Attachment(slide.getUri(), slide.getContentType(), message.getDateReceived())); saveTask.execute(new Attachment(slide.getUri(), slide.getContentType(), message.getDateReceived()));
return;
} }
}
@Override Log.w(TAG, "No slide with attachable media found, failing nicely.");
public void onFailure(Throwable error) { Toast.makeText(getActivity(), R.string.ConversationFragment_error_while_saving_attachment_to_sd_card, Toast.LENGTH_LONG).show();
Log.w(TAG, "No slide with attachable media found, failing nicely.");
Log.w(TAG, error);
Toast.makeText(getActivity(), R.string.ConversationFragment_error_while_saving_attachment_to_sd_card, Toast.LENGTH_LONG).show();
}
});
} }
}); });
} }

View File

@ -240,7 +240,7 @@ public class ConversationItem extends LinearLayout
private boolean hasMedia(MessageRecord messageRecord) { private boolean hasMedia(MessageRecord messageRecord) {
return messageRecord.isMms() && return messageRecord.isMms() &&
!messageRecord.isMmsNotification() && !messageRecord.isMmsNotification() &&
((MediaMmsMessageRecord)messageRecord).getPartCount() > 0; ((MediaMmsMessageRecord)messageRecord).getSlideDeck().getThumbnailSlide() != null;
} }
private void setBodyText(MessageRecord messageRecord) { private void setBodyText(MessageRecord messageRecord) {
@ -262,8 +262,9 @@ public class ConversationItem extends LinearLayout
setNotificationMmsAttributes((NotificationMmsMessageRecord) messageRecord); setNotificationMmsAttributes((NotificationMmsMessageRecord) messageRecord);
} else if (hasMedia(messageRecord)) { } else if (hasMedia(messageRecord)) {
mediaThumbnail.setVisibility(View.VISIBLE); mediaThumbnail.setVisibility(View.VISIBLE);
//noinspection ConstantConditions
mediaThumbnail.setImageResource(masterSecret, mediaThumbnail.setImageResource(masterSecret,
((MediaMmsMessageRecord)messageRecord).getSlideDeckFuture(), ((MediaMmsMessageRecord)messageRecord).getSlideDeck().getThumbnailSlide(),
!messageRecord.isFailed() && (!messageRecord.isOutgoing() || messageRecord.isPending()), !messageRecord.isFailed() && (!messageRecord.isOutgoing() || messageRecord.isPending()),
false); false);
bodyText.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)); bodyText.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));

View File

@ -29,9 +29,6 @@ import org.thoughtcrime.securesms.database.AttachmentDatabase;
import org.thoughtcrime.securesms.mms.DecryptableStreamUriLoader.DecryptableUri; import org.thoughtcrime.securesms.mms.DecryptableStreamUriLoader.DecryptableUri;
import org.thoughtcrime.securesms.mms.RoundedCorners; import org.thoughtcrime.securesms.mms.RoundedCorners;
import org.thoughtcrime.securesms.mms.Slide; import org.thoughtcrime.securesms.mms.Slide;
import org.thoughtcrime.securesms.mms.SlideDeck;
import org.thoughtcrime.securesms.util.FutureTaskListener;
import org.thoughtcrime.securesms.util.ListenableFutureTask;
import org.thoughtcrime.securesms.util.Util; import org.thoughtcrime.securesms.util.Util;
import org.thoughtcrime.securesms.util.ViewUtil; import org.thoughtcrime.securesms.util.ViewUtil;
import org.whispersystems.libaxolotl.util.guava.Optional; import org.whispersystems.libaxolotl.util.guava.Optional;
@ -46,8 +43,6 @@ public class ThumbnailView extends FrameLayout {
private OnClickListener parentClickListener; private OnClickListener parentClickListener;
private Optional<TransferControlView> transferControls = Optional.absent(); private Optional<TransferControlView> transferControls = Optional.absent();
private ListenableFutureTask<SlideDeck> slideDeckFuture = null;
private SlideDeckListener slideDeckListener = null;
private ThumbnailClickListener thumbnailClickListener = null; private ThumbnailClickListener thumbnailClickListener = null;
private ThumbnailClickListener downloadClickListener = null; private ThumbnailClickListener downloadClickListener = null;
private Slide slide = null; private Slide slide = null;
@ -117,25 +112,6 @@ public class ThumbnailView extends FrameLayout {
this.backgroundColorHint = color; this.backgroundColorHint = color;
} }
public void setImageResource(@NonNull MasterSecret masterSecret,
@NonNull ListenableFutureTask<SlideDeck> slideDeckFuture,
boolean showControls, boolean showRemove)
{
if (this.slideDeckFuture != null && this.slideDeckListener != null) {
this.slideDeckFuture.removeListener(this.slideDeckListener);
}
if (!slideDeckFuture.equals(this.slideDeckFuture)) {
if (transferControls.isPresent()) getTransferControls().clear();
image.setImageDrawable(null);
this.slide = null;
}
this.slideDeckListener = new SlideDeckListener(masterSecret, showControls, showRemove);
this.slideDeckFuture = slideDeckFuture;
this.slideDeckFuture.addListener(this.slideDeckListener);
}
public void setImageResource(@NonNull MasterSecret masterSecret, @NonNull Slide slide, public void setImageResource(@NonNull MasterSecret masterSecret, @NonNull Slide slide,
boolean showControls, boolean showRemove) boolean showControls, boolean showRemove)
{ {
@ -182,11 +158,9 @@ public class ThumbnailView extends FrameLayout {
public void clear() { public void clear() {
if (isContextValid()) Glide.clear(image); if (isContextValid()) Glide.clear(image);
if (slideDeckFuture != null) slideDeckFuture.removeListener(slideDeckListener);
if (transferControls.isPresent()) getTransferControls().clear(); if (transferControls.isPresent()) getTransferControls().clear();
slide = null;
slideDeckFuture = null; slide = null;
slideDeckListener = null;
} }
public void showProgressSpinner() { public void showProgressSpinner() {
@ -219,54 +193,6 @@ public class ThumbnailView extends FrameLayout {
.fitCenter(); .fitCenter();
} }
private class SlideDeckListener implements FutureTaskListener<SlideDeck> {
private final MasterSecret masterSecret;
private final boolean showControls;
private final boolean showRemove;
public SlideDeckListener(@NonNull MasterSecret masterSecret, boolean showControls, boolean showRemove) {
this.masterSecret = masterSecret;
this.showControls = showControls;
this.showRemove = showRemove;
}
@Override
public void onSuccess(final SlideDeck slideDeck) {
if (slideDeck == null) return;
final Slide slide = slideDeck.getThumbnailSlide();
if (slide != null) {
Util.runOnMain(new Runnable() {
@Override
public void run() {
setImageResource(masterSecret, slide, showControls, showRemove);
}
});
} else {
Util.runOnMain(new Runnable() {
@Override
public void run() {
Log.w(TAG, "Resolved slide was null!");
setVisibility(View.GONE);
}
});
}
}
@Override
public void onFailure(Throwable error) {
Log.w(TAG, error);
Util.runOnMain(new Runnable() {
@Override
public void run() {
Log.w(TAG, "onFailure!");
setVisibility(View.GONE);
}
});
}
}
public interface ThumbnailClickListener { public interface ThumbnailClickListener {
void onClick(View v, Slide slide); void onClick(View v, Slide slide);
} }

View File

@ -61,11 +61,12 @@ public class AttachmentDatabase extends Database {
static final String TABLE_NAME = "part"; static final String TABLE_NAME = "part";
static final String ROW_ID = "_id"; static final String ROW_ID = "_id";
static final String ATTACHMENT_ID_ALIAS = "attachment_id";
static final String MMS_ID = "mid"; static final String MMS_ID = "mid";
static final String CONTENT_TYPE = "ct"; static final String CONTENT_TYPE = "ct";
private static final String NAME = "name"; static final String NAME = "name";
private static final String CONTENT_DISPOSITION = "cd"; static final String CONTENT_DISPOSITION = "cd";
private static final String CONTENT_LOCATION = "cl"; static final String CONTENT_LOCATION = "cl";
static final String DATA = "_data"; static final String DATA = "_data";
static final String TRANSFER_STATE = "pending_push"; static final String TRANSFER_STATE = "pending_push";
static final String SIZE = "data_size"; static final String SIZE = "data_size";
@ -80,6 +81,12 @@ public class AttachmentDatabase extends Database {
private static final String PART_ID_WHERE = ROW_ID + " = ? AND " + UNIQUE_ID + " = ?"; private static final String PART_ID_WHERE = ROW_ID + " = ? AND " + UNIQUE_ID + " = ?";
private static final String[] PROJECTION = new String[] {ROW_ID + " AS " + ATTACHMENT_ID_ALIAS,
MMS_ID, CONTENT_TYPE, NAME, CONTENT_DISPOSITION,
CONTENT_LOCATION, DATA, TRANSFER_STATE,
SIZE, THUMBNAIL, THUMBNAIL_ASPECT_RATIO,
UNIQUE_ID};
public static final String CREATE_TABLE = "CREATE TABLE " + TABLE_NAME + " (" + ROW_ID + " INTEGER PRIMARY KEY, " + public static final String CREATE_TABLE = "CREATE TABLE " + TABLE_NAME + " (" + ROW_ID + " INTEGER PRIMARY KEY, " +
MMS_ID + " INTEGER, " + "seq" + " INTEGER DEFAULT 0, " + MMS_ID + " INTEGER, " + "seq" + " INTEGER DEFAULT 0, " +
CONTENT_TYPE + " TEXT, " + NAME + " TEXT, " + "chset" + " INTEGER, " + CONTENT_TYPE + " TEXT, " + NAME + " TEXT, " + "chset" + " INTEGER, " +
@ -148,7 +155,7 @@ public class AttachmentDatabase extends Database {
Cursor cursor = null; Cursor cursor = null;
try { try {
cursor = database.query(TABLE_NAME, null, PART_ID_WHERE, attachmentId.toStrings(), null, null, null); cursor = database.query(TABLE_NAME, PROJECTION, PART_ID_WHERE, attachmentId.toStrings(), null, null, null);
if (cursor != null && cursor.moveToFirst()) return getAttachment(cursor); if (cursor != null && cursor.moveToFirst()) return getAttachment(cursor);
else return null; else return null;
@ -165,7 +172,7 @@ public class AttachmentDatabase extends Database {
Cursor cursor = null; Cursor cursor = null;
try { try {
cursor = database.query(TABLE_NAME, null, MMS_ID + " = ?", new String[] {mmsId+""}, cursor = database.query(TABLE_NAME, PROJECTION, MMS_ID + " = ?", new String[] {mmsId+""},
null, null, null); null, null, null);
while (cursor != null && cursor.moveToNext()) { while (cursor != null && cursor.moveToNext()) {
@ -185,7 +192,7 @@ public class AttachmentDatabase extends Database {
Cursor cursor = null; Cursor cursor = null;
try { try {
cursor = database.query(TABLE_NAME, null, TRANSFER_STATE + " = ?", new String[] {String.valueOf(TRANSFER_PROGRESS_STARTED)}, null, null, null); cursor = database.query(TABLE_NAME, PROJECTION, TRANSFER_STATE + " = ?", new String[] {String.valueOf(TRANSFER_PROGRESS_STARTED)}, null, null, null);
while (cursor != null && cursor.moveToNext()) { while (cursor != null && cursor.moveToNext()) {
attachments.add(getAttachment(cursor)); attachments.add(getAttachment(cursor));
} }
@ -417,8 +424,8 @@ public class AttachmentDatabase extends Database {
} }
} }
private DatabaseAttachment getAttachment(Cursor cursor) { DatabaseAttachment getAttachment(Cursor cursor) {
return new DatabaseAttachment(new AttachmentId(cursor.getLong(cursor.getColumnIndexOrThrow(ROW_ID)), return new DatabaseAttachment(new AttachmentId(cursor.getLong(cursor.getColumnIndexOrThrow(ATTACHMENT_ID_ALIAS)),
cursor.getLong(cursor.getColumnIndexOrThrow(UNIQUE_ID))), cursor.getLong(cursor.getColumnIndexOrThrow(UNIQUE_ID))),
cursor.getLong(cursor.getColumnIndexOrThrow(MMS_ID)), cursor.getLong(cursor.getColumnIndexOrThrow(MMS_ID)),
!cursor.isNull(cursor.getColumnIndexOrThrow(DATA)), !cursor.isNull(cursor.getColumnIndexOrThrow(DATA)),

View File

@ -1012,8 +1012,7 @@ public class MmsDatabase extends MessagingDatabase {
Recipients recipients = getRecipientsFor(address); Recipients recipients = getRecipientsFor(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);
ListenableFutureTask<SlideDeck> slideDeck = getSlideDeck(dateReceived, id);
return new MediaMmsMessageRecord(context, id, recipients, recipients.getPrimaryRecipient(), return new MediaMmsMessageRecord(context, id, recipients, recipients.getPrimaryRecipient(),
addressDeviceId, dateSent, dateReceived, receiptCount, addressDeviceId, dateSent, dateReceived, receiptCount,
@ -1078,63 +1077,9 @@ public class MmsDatabase extends MessagingDatabase {
} }
} }
private ListenableFutureTask<SlideDeck> getSlideDeck(final long timestamp, private SlideDeck getSlideDeck(@NonNull Cursor cursor) {
final long id) Attachment attachment = DatabaseFactory.getAttachmentDatabase(context).getAttachment(cursor);
{ return new SlideDeck(context, attachment);
ListenableFutureTask<SlideDeck> future = getCachedSlideDeck(timestamp, id);
if (future != null) {
return future;
}
Callable<SlideDeck> task = new Callable<SlideDeck>() {
@Override
public SlideDeck call() throws Exception {
AttachmentDatabase attachmentDatabase = DatabaseFactory.getAttachmentDatabase(context);
List<Attachment> attachments = new LinkedList<Attachment>(attachmentDatabase.getAttachmentsForMessage(id));
SlideDeck slideDeck = new SlideDeck(context, attachments);
boolean progress = false;
for (Attachment attachment : attachments) {
if (attachment.isInProgress()) progress = true;
}
if (!progress) {
slideCache.put(timestamp + "::" + id, new SoftReference<>(slideDeck));
}
return slideDeck;
}
};
future = new ListenableFutureTask<>(task, timestamp + "::" + id);
slideResolver.execute(future);
return future;
}
private ListenableFutureTask<SlideDeck> getCachedSlideDeck(final long timestamp, final long id) {
SoftReference<SlideDeck> reference = slideCache.get(timestamp + "::" + id);
if (reference != null) {
final SlideDeck slideDeck = reference.get();
if (slideDeck != null) {
Callable<SlideDeck> task = new Callable<SlideDeck>() {
@Override
public SlideDeck call() throws Exception {
return slideDeck;
}
};
ListenableFutureTask<SlideDeck> future = new ListenableFutureTask<>(task);
future.run();
return future;
}
}
return null;
} }
public void close() { public void close() {

View File

@ -16,11 +16,13 @@
*/ */
package org.thoughtcrime.securesms.database; package org.thoughtcrime.securesms.database;
import android.annotation.TargetApi;
import android.content.Context; import android.content.Context;
import android.database.Cursor; import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper; import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteQueryBuilder; import android.database.sqlite.SQLiteQueryBuilder;
import android.os.Build;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import android.util.Log; import android.util.Log;
@ -34,33 +36,44 @@ import java.util.Set;
public class MmsSmsDatabase extends Database { public class MmsSmsDatabase extends Database {
private static final String TAG = MmsSmsDatabase.class.getSimpleName();
public static final String TRANSPORT = "transport_type"; public static final String TRANSPORT = "transport_type";
public static final String MMS_TRANSPORT = "mms"; public static final String MMS_TRANSPORT = "mms";
public static final String SMS_TRANSPORT = "sms"; public static final String SMS_TRANSPORT = "sms";
private static final String[] PROJECTION = {MmsSmsColumns.ID, SmsDatabase.BODY, SmsDatabase.TYPE,
MmsSmsColumns.THREAD_ID,
SmsDatabase.ADDRESS, SmsDatabase.ADDRESS_DEVICE_ID, SmsDatabase.SUBJECT,
MmsSmsColumns.NORMALIZED_DATE_SENT,
MmsSmsColumns.NORMALIZED_DATE_RECEIVED,
MmsDatabase.MESSAGE_TYPE, MmsDatabase.MESSAGE_BOX,
SmsDatabase.STATUS, MmsDatabase.PART_COUNT,
MmsDatabase.CONTENT_LOCATION, MmsDatabase.TRANSACTION_ID,
MmsDatabase.MESSAGE_SIZE, MmsDatabase.EXPIRY,
MmsDatabase.STATUS, MmsSmsColumns.RECEIPT_COUNT,
MmsSmsColumns.MISMATCHED_IDENTITIES,
MmsDatabase.NETWORK_FAILURE, TRANSPORT,
AttachmentDatabase.ATTACHMENT_ID_ALIAS,
AttachmentDatabase.UNIQUE_ID,
AttachmentDatabase.MMS_ID,
AttachmentDatabase.SIZE,
AttachmentDatabase.DATA,
AttachmentDatabase.CONTENT_TYPE,
AttachmentDatabase.CONTENT_LOCATION,
AttachmentDatabase.CONTENT_DISPOSITION,
AttachmentDatabase.NAME,
AttachmentDatabase.TRANSFER_STATE};
public MmsSmsDatabase(Context context, SQLiteOpenHelper databaseHelper) { public MmsSmsDatabase(Context context, SQLiteOpenHelper databaseHelper) {
super(context, databaseHelper); super(context, databaseHelper);
} }
public Cursor getConversation(long threadId, long limit) { public Cursor getConversation(long threadId, long limit) {
String[] projection = {MmsSmsColumns.ID, SmsDatabase.BODY, SmsDatabase.TYPE, String order = MmsSmsColumns.NORMALIZED_DATE_RECEIVED + " DESC";
MmsSmsColumns.THREAD_ID, String selection = MmsSmsColumns.THREAD_ID + " = " + threadId;
SmsDatabase.ADDRESS, SmsDatabase.ADDRESS_DEVICE_ID, SmsDatabase.SUBJECT,
MmsSmsColumns.NORMALIZED_DATE_SENT,
MmsSmsColumns.NORMALIZED_DATE_RECEIVED,
MmsDatabase.MESSAGE_TYPE, MmsDatabase.MESSAGE_BOX,
SmsDatabase.STATUS, MmsDatabase.PART_COUNT,
MmsDatabase.CONTENT_LOCATION, MmsDatabase.TRANSACTION_ID,
MmsDatabase.MESSAGE_SIZE, MmsDatabase.EXPIRY,
MmsDatabase.STATUS, MmsSmsColumns.RECEIPT_COUNT,
MmsSmsColumns.MISMATCHED_IDENTITIES,
MmsDatabase.NETWORK_FAILURE, TRANSPORT};
String order = MmsSmsColumns.NORMALIZED_DATE_RECEIVED + " DESC"; Cursor cursor = queryTables(PROJECTION, selection, order, limit > 0 ? String.valueOf(limit) : null);
String selection = MmsSmsColumns.THREAD_ID + " = " + threadId;
Cursor cursor = queryTables(projection, selection, selection, order, null, limit > 0 ? String.valueOf(limit) : null);
setNotifyConverationListeners(cursor, threadId); setNotifyConverationListeners(cursor, threadId);
return cursor; return cursor;
@ -71,67 +84,27 @@ public class MmsSmsDatabase extends Database {
} }
public Cursor getIdentityConflictMessagesForThread(long threadId) { public Cursor getIdentityConflictMessagesForThread(long threadId) {
String[] projection = {MmsSmsColumns.ID, SmsDatabase.BODY, SmsDatabase.TYPE,
MmsSmsColumns.THREAD_ID,
SmsDatabase.ADDRESS, SmsDatabase.ADDRESS_DEVICE_ID, SmsDatabase.SUBJECT,
MmsSmsColumns.NORMALIZED_DATE_SENT,
MmsSmsColumns.NORMALIZED_DATE_RECEIVED,
MmsDatabase.MESSAGE_TYPE, MmsDatabase.MESSAGE_BOX,
SmsDatabase.STATUS, MmsDatabase.PART_COUNT,
MmsDatabase.CONTENT_LOCATION, MmsDatabase.TRANSACTION_ID,
MmsDatabase.MESSAGE_SIZE, MmsDatabase.EXPIRY,
MmsDatabase.STATUS, MmsSmsColumns.RECEIPT_COUNT,
MmsSmsColumns.MISMATCHED_IDENTITIES,
MmsDatabase.NETWORK_FAILURE, TRANSPORT};
String order = MmsSmsColumns.NORMALIZED_DATE_RECEIVED + " ASC"; String order = MmsSmsColumns.NORMALIZED_DATE_RECEIVED + " ASC";
String selection = MmsSmsColumns.THREAD_ID + " = " + threadId + " AND " + MmsSmsColumns.MISMATCHED_IDENTITIES + " IS NOT NULL"; String selection = MmsSmsColumns.THREAD_ID + " = " + threadId + " AND " + MmsSmsColumns.MISMATCHED_IDENTITIES + " IS NOT NULL";
Cursor cursor = queryTables(projection, selection, selection, order, null, null); Cursor cursor = queryTables(PROJECTION, selection, order, null);
setNotifyConverationListeners(cursor, threadId); setNotifyConverationListeners(cursor, threadId);
return cursor; return cursor;
} }
public Cursor getConversationSnippet(long threadId) { public Cursor getConversationSnippet(long threadId) {
String[] projection = {MmsSmsColumns.ID, SmsDatabase.BODY, SmsDatabase.TYPE, String order = MmsSmsColumns.NORMALIZED_DATE_RECEIVED + " DESC";
MmsSmsColumns.THREAD_ID, String selection = MmsSmsColumns.THREAD_ID + " = " + threadId;
SmsDatabase.ADDRESS, SmsDatabase.ADDRESS_DEVICE_ID, SmsDatabase.SUBJECT,
MmsSmsColumns.NORMALIZED_DATE_SENT,
MmsSmsColumns.NORMALIZED_DATE_RECEIVED,
MmsDatabase.MESSAGE_TYPE, MmsDatabase.MESSAGE_BOX,
SmsDatabase.STATUS, MmsDatabase.PART_COUNT,
MmsDatabase.CONTENT_LOCATION, MmsDatabase.TRANSACTION_ID,
MmsDatabase.MESSAGE_SIZE, MmsDatabase.EXPIRY,
MmsDatabase.STATUS, MmsSmsColumns.RECEIPT_COUNT,
MmsSmsColumns.MISMATCHED_IDENTITIES,
MmsDatabase.NETWORK_FAILURE, TRANSPORT};
String order = MmsSmsColumns.NORMALIZED_DATE_RECEIVED + " DESC"; return queryTables(PROJECTION, selection, order, "1");
String selection = MmsSmsColumns.THREAD_ID + " = " + threadId;
return queryTables(projection, selection, selection, order, null, "1");
} }
public Cursor getUnread() { public Cursor getUnread() {
String[] projection = {MmsSmsColumns.ID, SmsDatabase.BODY, SmsDatabase.READ, SmsDatabase.TYPE,
SmsDatabase.ADDRESS, SmsDatabase.ADDRESS_DEVICE_ID, SmsDatabase.SUBJECT, MmsSmsColumns.THREAD_ID,
SmsDatabase.STATUS,
MmsSmsColumns.NORMALIZED_DATE_SENT,
MmsSmsColumns.NORMALIZED_DATE_RECEIVED,
MmsDatabase.MESSAGE_TYPE, MmsDatabase.MESSAGE_BOX,
MmsDatabase.PART_COUNT,
MmsDatabase.CONTENT_LOCATION, MmsDatabase.TRANSACTION_ID,
MmsDatabase.MESSAGE_SIZE, MmsDatabase.EXPIRY,
MmsDatabase.STATUS, MmsSmsColumns.RECEIPT_COUNT,
MmsSmsColumns.MISMATCHED_IDENTITIES,
MmsDatabase.NETWORK_FAILURE, TRANSPORT};
String order = MmsSmsColumns.NORMALIZED_DATE_RECEIVED + " ASC"; String order = MmsSmsColumns.NORMALIZED_DATE_RECEIVED + " ASC";
String selection = MmsSmsColumns.READ + " = 0"; String selection = MmsSmsColumns.READ + " = 0";
return queryTables(projection, selection, selection, order, null, null); return queryTables(PROJECTION, selection, order, null);
} }
public int getConversationCount(long threadId) { public int getConversationCount(long threadId) {
@ -146,27 +119,47 @@ public class MmsSmsDatabase extends Database {
DatabaseFactory.getMmsDatabase(context).incrementDeliveryReceiptCount(address, timestamp); DatabaseFactory.getMmsDatabase(context).incrementDeliveryReceiptCount(address, timestamp);
} }
private Cursor queryTables(String[] projection, String smsSelection, String mmsSelection, String order, String groupBy, String limit) { private Cursor queryTables(String[] projection, String selection, String order, String limit) {
String[] mmsProjection = {MmsDatabase.DATE_SENT + " AS " + MmsSmsColumns.NORMALIZED_DATE_SENT, String[] mmsProjection = {MmsDatabase.DATE_SENT + " AS " + MmsSmsColumns.NORMALIZED_DATE_SENT,
MmsDatabase.DATE_RECEIVED + " AS " + MmsSmsColumns.NORMALIZED_DATE_RECEIVED, MmsDatabase.DATE_RECEIVED + " AS " + MmsSmsColumns.NORMALIZED_DATE_RECEIVED,
MmsSmsColumns.ID, SmsDatabase.BODY, MmsSmsColumns.READ, MmsSmsColumns.THREAD_ID, MmsDatabase.TABLE_NAME + "." + MmsDatabase.ID + " AS " + MmsSmsColumns.ID,
AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.ROW_ID + " AS " + AttachmentDatabase.ATTACHMENT_ID_ALIAS,
SmsDatabase.BODY, MmsSmsColumns.READ, MmsSmsColumns.THREAD_ID,
SmsDatabase.TYPE, SmsDatabase.ADDRESS, SmsDatabase.ADDRESS_DEVICE_ID, SmsDatabase.SUBJECT, MmsDatabase.MESSAGE_TYPE, SmsDatabase.TYPE, SmsDatabase.ADDRESS, SmsDatabase.ADDRESS_DEVICE_ID, SmsDatabase.SUBJECT, MmsDatabase.MESSAGE_TYPE,
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.RECEIPT_COUNT, MmsSmsColumns.MISMATCHED_IDENTITIES,
MmsDatabase.NETWORK_FAILURE, TRANSPORT}; MmsDatabase.NETWORK_FAILURE, TRANSPORT,
AttachmentDatabase.UNIQUE_ID,
AttachmentDatabase.MMS_ID,
AttachmentDatabase.SIZE,
AttachmentDatabase.DATA,
AttachmentDatabase.CONTENT_TYPE,
AttachmentDatabase.CONTENT_LOCATION,
AttachmentDatabase.CONTENT_DISPOSITION,
AttachmentDatabase.NAME,
AttachmentDatabase.TRANSFER_STATE};
String[] smsProjection = {SmsDatabase.DATE_SENT + " AS " + MmsSmsColumns.NORMALIZED_DATE_SENT, String[] smsProjection = {SmsDatabase.DATE_SENT + " AS " + MmsSmsColumns.NORMALIZED_DATE_SENT,
SmsDatabase.DATE_RECEIVED + " AS " + MmsSmsColumns.NORMALIZED_DATE_RECEIVED, SmsDatabase.DATE_RECEIVED + " AS " + MmsSmsColumns.NORMALIZED_DATE_RECEIVED,
MmsSmsColumns.ID, SmsDatabase.BODY, MmsSmsColumns.READ, MmsSmsColumns.THREAD_ID, MmsSmsColumns.ID, "NULL AS " + AttachmentDatabase.ATTACHMENT_ID_ALIAS,
SmsDatabase.BODY, MmsSmsColumns.READ, MmsSmsColumns.THREAD_ID,
SmsDatabase.TYPE, SmsDatabase.ADDRESS, SmsDatabase.ADDRESS_DEVICE_ID, SmsDatabase.SUBJECT, MmsDatabase.MESSAGE_TYPE, SmsDatabase.TYPE, SmsDatabase.ADDRESS, SmsDatabase.ADDRESS_DEVICE_ID, SmsDatabase.SUBJECT, MmsDatabase.MESSAGE_TYPE,
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.RECEIPT_COUNT, MmsSmsColumns.MISMATCHED_IDENTITIES,
MmsDatabase.NETWORK_FAILURE, TRANSPORT}; MmsDatabase.NETWORK_FAILURE, TRANSPORT,
AttachmentDatabase.UNIQUE_ID,
AttachmentDatabase.MMS_ID,
AttachmentDatabase.SIZE,
AttachmentDatabase.DATA,
AttachmentDatabase.CONTENT_TYPE,
AttachmentDatabase.CONTENT_LOCATION,
AttachmentDatabase.CONTENT_DISPOSITION,
AttachmentDatabase.NAME,
AttachmentDatabase.TRANSFER_STATE};
SQLiteQueryBuilder mmsQueryBuilder = new SQLiteQueryBuilder(); SQLiteQueryBuilder mmsQueryBuilder = new SQLiteQueryBuilder();
SQLiteQueryBuilder smsQueryBuilder = new SQLiteQueryBuilder(); SQLiteQueryBuilder smsQueryBuilder = new SQLiteQueryBuilder();
@ -174,10 +167,10 @@ public class MmsSmsDatabase extends Database {
mmsQueryBuilder.setDistinct(true); mmsQueryBuilder.setDistinct(true);
smsQueryBuilder.setDistinct(true); smsQueryBuilder.setDistinct(true);
mmsQueryBuilder.setTables(MmsDatabase.TABLE_NAME); mmsQueryBuilder.setTables(MmsDatabase.TABLE_NAME + " LEFT OUTER JOIN " + AttachmentDatabase.TABLE_NAME + " ON (" + MmsDatabase.TABLE_NAME + "." + MmsDatabase.ID + " = " + AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.MMS_ID + ")");
smsQueryBuilder.setTables(SmsDatabase.TABLE_NAME); smsQueryBuilder.setTables(SmsDatabase.TABLE_NAME);
Set<String> mmsColumnsPresent = new HashSet<String>(); Set<String> mmsColumnsPresent = new HashSet<>();
mmsColumnsPresent.add(MmsSmsColumns.ID); mmsColumnsPresent.add(MmsSmsColumns.ID);
mmsColumnsPresent.add(MmsSmsColumns.READ); mmsColumnsPresent.add(MmsSmsColumns.READ);
mmsColumnsPresent.add(MmsSmsColumns.THREAD_ID); mmsColumnsPresent.add(MmsSmsColumns.THREAD_ID);
@ -198,7 +191,16 @@ public class MmsSmsDatabase extends Database {
mmsColumnsPresent.add(MmsDatabase.STATUS); mmsColumnsPresent.add(MmsDatabase.STATUS);
mmsColumnsPresent.add(MmsDatabase.NETWORK_FAILURE); mmsColumnsPresent.add(MmsDatabase.NETWORK_FAILURE);
Set<String> smsColumnsPresent = new HashSet<String>(); mmsColumnsPresent.add(AttachmentDatabase.ROW_ID);
mmsColumnsPresent.add(AttachmentDatabase.UNIQUE_ID);
mmsColumnsPresent.add(AttachmentDatabase.SIZE);
mmsColumnsPresent.add(AttachmentDatabase.CONTENT_TYPE);
mmsColumnsPresent.add(AttachmentDatabase.CONTENT_LOCATION);
mmsColumnsPresent.add(AttachmentDatabase.CONTENT_DISPOSITION);
mmsColumnsPresent.add(AttachmentDatabase.NAME);
mmsColumnsPresent.add(AttachmentDatabase.TRANSFER_STATE);
Set<String> smsColumnsPresent = new HashSet<>();
smsColumnsPresent.add(MmsSmsColumns.ID); smsColumnsPresent.add(MmsSmsColumns.ID);
smsColumnsPresent.add(MmsSmsColumns.BODY); smsColumnsPresent.add(MmsSmsColumns.BODY);
smsColumnsPresent.add(MmsSmsColumns.ADDRESS); smsColumnsPresent.add(MmsSmsColumns.ADDRESS);
@ -213,16 +215,16 @@ public class MmsSmsDatabase extends Database {
smsColumnsPresent.add(SmsDatabase.DATE_RECEIVED); smsColumnsPresent.add(SmsDatabase.DATE_RECEIVED);
smsColumnsPresent.add(SmsDatabase.STATUS); smsColumnsPresent.add(SmsDatabase.STATUS);
String mmsSubQuery = mmsQueryBuilder.buildUnionSubQuery(TRANSPORT, mmsProjection, mmsColumnsPresent, 2, MMS_TRANSPORT, mmsSelection, null, null, null); String mmsSubQuery = mmsQueryBuilder.buildUnionSubQuery(TRANSPORT, mmsProjection, mmsColumnsPresent, 3, MMS_TRANSPORT, selection, null, null, null);
String smsSubQuery = smsQueryBuilder.buildUnionSubQuery(TRANSPORT, smsProjection, smsColumnsPresent, 2, SMS_TRANSPORT, smsSelection, null, null, null); String smsSubQuery = smsQueryBuilder.buildUnionSubQuery(TRANSPORT, smsProjection, smsColumnsPresent, 3, SMS_TRANSPORT, selection, null, null, null);
SQLiteQueryBuilder unionQueryBuilder = new SQLiteQueryBuilder(); SQLiteQueryBuilder unionQueryBuilder = new SQLiteQueryBuilder();
String unionQuery = unionQueryBuilder.buildUnionQuery(new String[] {smsSubQuery, mmsSubQuery}, order, null); String unionQuery = unionQueryBuilder.buildUnionQuery(new String[] {smsSubQuery, mmsSubQuery}, order, limit);
SQLiteQueryBuilder outerQueryBuilder = new SQLiteQueryBuilder(); SQLiteQueryBuilder outerQueryBuilder = new SQLiteQueryBuilder();
outerQueryBuilder.setTables("(" + unionQuery + ")"); outerQueryBuilder.setTables("(" + unionQuery + ")");
String query = outerQueryBuilder.buildQuery(projection, null, null, groupBy, null, null, limit); String query = outerQueryBuilder.buildQuery(projection, null, null, null, null, null, null);
Log.w("MmsSmsDatabase", "Executing query: " + query); Log.w("MmsSmsDatabase", "Executing query: " + query);
SQLiteDatabase db = databaseHelper.getReadableDatabase(); SQLiteDatabase db = databaseHelper.getReadableDatabase();
@ -277,14 +279,15 @@ public class MmsSmsDatabase extends Database {
return getCurrent(); return getCurrent();
} }
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public MessageRecord getCurrent() { public MessageRecord getCurrent() {
String type = cursor.getString(cursor.getColumnIndexOrThrow(TRANSPORT)); String type = cursor.getString(cursor.getColumnIndexOrThrow(TRANSPORT));
if (MmsSmsDatabase.MMS_TRANSPORT.equals(type)) { Log.w("MmsSmsDatabase", "Type: " + type);
return getMmsReader().getCurrent();
} else { if (MmsSmsDatabase.MMS_TRANSPORT.equals(type)) return getMmsReader().getCurrent();
return getSmsReader().getCurrent(); else if (MmsSmsDatabase.SMS_TRANSPORT.equals(type)) return getSmsReader().getCurrent();
} else throw new AssertionError("Bad type: " + type);
} }
public void close() { public void close() {

View File

@ -17,23 +17,18 @@
package org.thoughtcrime.securesms.database.model; package org.thoughtcrime.securesms.database.model;
import android.content.Context; import android.content.Context;
import android.support.annotation.NonNull;
import android.text.SpannableString; import android.text.SpannableString;
import android.util.Log;
import org.thoughtcrime.securesms.R; import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.database.MmsDatabase; import org.thoughtcrime.securesms.database.MmsDatabase;
import org.thoughtcrime.securesms.database.documents.NetworkFailure;
import org.thoughtcrime.securesms.database.documents.IdentityKeyMismatch; import org.thoughtcrime.securesms.database.documents.IdentityKeyMismatch;
import org.thoughtcrime.securesms.mms.MediaNotFoundException; import org.thoughtcrime.securesms.database.documents.NetworkFailure;
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.recipients.Recipients; import org.thoughtcrime.securesms.recipients.Recipients;
import org.thoughtcrime.securesms.util.FutureTaskListener;
import org.thoughtcrime.securesms.util.ListenableFutureTask;
import java.util.List; import java.util.List;
import java.util.concurrent.ExecutionException;
/** /**
* Represents the message record model for MMS messages that contain * Represents the message record model for MMS messages that contain
@ -48,13 +43,13 @@ public class MediaMmsMessageRecord extends MessageRecord {
private final Context context; private final Context context;
private final int partCount; private final int partCount;
private final ListenableFutureTask<SlideDeck> slideDeckFutureTask; private final @NonNull SlideDeck slideDeck;
public MediaMmsMessageRecord(Context context, long id, Recipients recipients, public MediaMmsMessageRecord(Context context, long id, Recipients recipients,
Recipient individualRecipient, int recipientDeviceId, Recipient individualRecipient, int recipientDeviceId,
long dateSent, long dateReceived, int deliveredCount, long dateSent, long dateReceived, int deliveredCount,
long threadId, Body body, long threadId, Body body,
ListenableFutureTask<SlideDeck> slideDeck, @NonNull SlideDeck slideDeck,
int partCount, long mailbox, int partCount, long mailbox,
List<IdentityKeyMismatch> mismatches, List<IdentityKeyMismatch> mismatches,
List<NetworkFailure> failures) List<NetworkFailure> failures)
@ -63,51 +58,17 @@ public class MediaMmsMessageRecord extends MessageRecord {
dateSent, dateReceived, threadId, DELIVERY_STATUS_NONE, deliveredCount, mailbox, dateSent, dateReceived, threadId, DELIVERY_STATUS_NONE, deliveredCount, mailbox,
mismatches, failures); mismatches, failures);
this.context = context.getApplicationContext(); this.context = context.getApplicationContext();
this.partCount = partCount; this.partCount = partCount;
this.slideDeckFutureTask = slideDeck; this.slideDeck = slideDeck;
} }
public ListenableFutureTask<SlideDeck> getSlideDeckFuture() { public @NonNull SlideDeck getSlideDeck() {
return slideDeckFutureTask; return slideDeck;
}
private SlideDeck getSlideDeckSync() {
try {
return slideDeckFutureTask.get();
} catch (InterruptedException e) {
Log.w(TAG, e);
return null;
} catch (ExecutionException e) {
Log.w(TAG, e);
return null;
}
} }
public boolean containsMediaSlide() { public boolean containsMediaSlide() {
SlideDeck deck = getSlideDeckSync(); return slideDeck.containsMediaSlide();
return deck != null && deck.containsMediaSlide();
}
public void fetchMediaSlide(final FutureTaskListener<Slide> listener) {
slideDeckFutureTask.addListener(new FutureTaskListener<SlideDeck>() {
@Override
public void onSuccess(SlideDeck deck) {
for (Slide slide : deck.getSlides()) {
if (slide.hasImage() || slide.hasVideo() || slide.hasAudio()) {
listener.onSuccess(slide);
return;
}
}
listener.onFailure(new MediaNotFoundException("no media slide found"));
}
@Override
public void onFailure(Throwable error) {
listener.onFailure(error);
}
});
} }
public int getPartCount() { public int getPartCount() {

View File

@ -17,29 +17,14 @@
package org.thoughtcrime.securesms.mms; package org.thoughtcrime.securesms.mms;
import android.content.Context; import android.content.Context;
import android.graphics.drawable.Drawable;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import android.util.Pair;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.attachments.Attachment; import org.thoughtcrime.securesms.attachments.Attachment;
import org.thoughtcrime.securesms.crypto.MasterSecret;
import org.thoughtcrime.securesms.dom.smil.parser.SmilXmlSerializer;
import org.thoughtcrime.securesms.util.ListenableFutureTask;
import org.thoughtcrime.securesms.util.MediaUtil; import org.thoughtcrime.securesms.util.MediaUtil;
import org.thoughtcrime.securesms.util.SmilUtil;
import org.thoughtcrime.securesms.util.Util;
import java.io.ByteArrayOutputStream;
import java.io.UnsupportedEncodingException;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import ws.com.google.android.mms.ContentType;
import ws.com.google.android.mms.pdu.CharacterSets;
import ws.com.google.android.mms.pdu.PduBody;
import ws.com.google.android.mms.pdu.PduPart;
public class SlideDeck { public class SlideDeck {
private final List<Slide> slides = new LinkedList<>(); private final List<Slide> slides = new LinkedList<>();
@ -51,6 +36,11 @@ public class SlideDeck {
} }
} }
public SlideDeck(Context context, Attachment attachment) {
Slide slide = MediaUtil.getSlideForAttachment(context, attachment);
if (slide != null) slides.add(slide);
}
public SlideDeck() { public SlideDeck() {
} }

View File

@ -347,13 +347,13 @@ public class MessageNotifier {
else reader = DatabaseFactory.getMmsSmsDatabase(context).readerFor(cursor, masterSecret); else reader = DatabaseFactory.getMmsSmsDatabase(context).readerFor(cursor, masterSecret);
while ((record = reader.getNext()) != null) { while ((record = reader.getNext()) != null) {
Recipient recipient = record.getIndividualRecipient(); Recipient recipient = record.getIndividualRecipient();
Recipients recipients = record.getRecipients(); Recipients recipients = record.getRecipients();
long threadId = record.getThreadId(); long threadId = record.getThreadId();
CharSequence body = record.getDisplayBody(); CharSequence body = record.getDisplayBody();
Recipients threadRecipients = null; Recipients threadRecipients = null;
ListenableFutureTask<SlideDeck> slideDeck = null; SlideDeck slideDeck = null;
long timestamp; long timestamp;
if (record.isPush()) timestamp = record.getDateSent(); if (record.isPush()) timestamp = record.getDateSent();
else timestamp = record.getDateReceived(); else timestamp = record.getDateReceived();
@ -366,12 +366,12 @@ public class MessageNotifier {
body = SpanUtil.italic(context.getString(R.string.MessageNotifier_locked_message)); body = SpanUtil.italic(context.getString(R.string.MessageNotifier_locked_message));
} else if (record.isMms() && TextUtils.isEmpty(body)) { } else if (record.isMms() && TextUtils.isEmpty(body)) {
body = SpanUtil.italic(context.getString(R.string.MessageNotifier_media_message)); body = SpanUtil.italic(context.getString(R.string.MessageNotifier_media_message));
slideDeck = ((MediaMmsMessageRecord)record).getSlideDeckFuture(); slideDeck = ((MediaMmsMessageRecord)record).getSlideDeck();
} else if (record.isMms() && !record.isMmsNotification()) { } else if (record.isMms() && !record.isMmsNotification()) {
String message = context.getString(R.string.MessageNotifier_media_message_with_text, body); String message = context.getString(R.string.MessageNotifier_media_message_with_text, body);
int italicLength = message.length() - body.length(); int italicLength = message.length() - body.length();
body = SpanUtil.italic(message, italicLength); body = SpanUtil.italic(message, italicLength);
slideDeck = ((MediaMmsMessageRecord)record).getSlideDeckFuture(); slideDeck = ((MediaMmsMessageRecord)record).getSlideDeck();
} }
if (threadRecipients == null || !threadRecipients.isMuted()) { if (threadRecipients == null || !threadRecipients.isMuted()) {

View File

@ -21,12 +21,12 @@ public class NotificationItem {
private final long threadId; private final long threadId;
private final CharSequence text; private final CharSequence text;
private final long timestamp; private final long timestamp;
private final ListenableFutureTask<SlideDeck> slideDeck; private final @Nullable SlideDeck slideDeck;
public NotificationItem(Recipient individualRecipient, Recipients recipients, public NotificationItem(Recipient individualRecipient, Recipients recipients,
Recipients threadRecipients, long threadId, Recipients threadRecipients, long threadId,
CharSequence text, long timestamp, CharSequence text, long timestamp,
@Nullable ListenableFutureTask<SlideDeck> slideDeck) @Nullable SlideDeck slideDeck)
{ {
this.individualRecipient = individualRecipient; this.individualRecipient = individualRecipient;
this.recipients = recipients; this.recipients = recipients;
@ -57,7 +57,7 @@ public class NotificationItem {
return threadId; return threadId;
} }
public @Nullable ListenableFutureTask<SlideDeck> getSlideDeck() { public @Nullable SlideDeck getSlideDeck() {
return slideDeck; return slideDeck;
} }

View File

@ -14,7 +14,6 @@ import android.support.v4.app.NotificationCompat;
import android.support.v4.app.NotificationCompat.Action; import android.support.v4.app.NotificationCompat.Action;
import android.support.v4.app.RemoteInput; import android.support.v4.app.RemoteInput;
import android.text.SpannableStringBuilder; import android.text.SpannableStringBuilder;
import android.util.Log;
import com.bumptech.glide.Glide; import com.bumptech.glide.Glide;
@ -26,7 +25,6 @@ import org.thoughtcrime.securesms.mms.SlideDeck;
import org.thoughtcrime.securesms.preferences.NotificationPrivacyPreference; import org.thoughtcrime.securesms.preferences.NotificationPrivacyPreference;
import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.util.BitmapUtil; import org.thoughtcrime.securesms.util.BitmapUtil;
import org.thoughtcrime.securesms.util.ListenableFutureTask;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
@ -38,8 +36,8 @@ public class SingleRecipientNotificationBuilder extends AbstractNotificationBuil
private final List<CharSequence> messageBodies = new LinkedList<>(); private final List<CharSequence> messageBodies = new LinkedList<>();
private ListenableFutureTask<SlideDeck> slideDeck; private SlideDeck slideDeck;
private final MasterSecret masterSecret; private final MasterSecret masterSecret;
public SingleRecipientNotificationBuilder(@NonNull Context context, public SingleRecipientNotificationBuilder(@NonNull Context context,
@Nullable MasterSecret masterSecret, @Nullable MasterSecret masterSecret,
@ -81,7 +79,7 @@ public class SingleRecipientNotificationBuilder extends AbstractNotificationBuil
setNumber(messageCount); setNumber(messageCount);
} }
public void setPrimaryMessageBody(CharSequence message, @Nullable ListenableFutureTask<SlideDeck> slideDeck) { public void setPrimaryMessageBody(CharSequence message, @Nullable SlideDeck slideDeck) {
if (privacy.isDisplayMessage()) { if (privacy.isDisplayMessage()) {
setContentText(message); setContentText(message);
this.slideDeck = slideDeck; this.slideDeck = slideDeck;
@ -166,30 +164,25 @@ public class SingleRecipientNotificationBuilder extends AbstractNotificationBuil
} }
} }
private boolean hasBigPictureSlide(@Nullable ListenableFutureTask<SlideDeck> slideDeck) { private boolean hasBigPictureSlide(@Nullable SlideDeck slideDeck) {
try { if (masterSecret == null || slideDeck == null || Build.VERSION.SDK_INT < 16) {
if (masterSecret == null || slideDeck == null || Build.VERSION.SDK_INT < 16) {
return false;
}
Slide thumbnailSlide = slideDeck.get().getThumbnailSlide();
return thumbnailSlide != null &&
thumbnailSlide.hasImage() &&
!thumbnailSlide.isInProgress() &&
thumbnailSlide.getThumbnailUri() != null;
} catch (InterruptedException | ExecutionException e) {
Log.w(TAG, e);
return false; return false;
} }
Slide thumbnailSlide = slideDeck.getThumbnailSlide();
return thumbnailSlide != null &&
thumbnailSlide.hasImage() &&
!thumbnailSlide.isInProgress() &&
thumbnailSlide.getThumbnailUri() != null;
} }
private Bitmap getBigPicture(@NonNull MasterSecret masterSecret, private Bitmap getBigPicture(@NonNull MasterSecret masterSecret,
@NonNull ListenableFutureTask<SlideDeck> slideDeck) @NonNull SlideDeck slideDeck)
{ {
try { try {
Uri uri = slideDeck.get().getThumbnailSlide().getThumbnailUri(); @SuppressWarnings("ConstantConditions")
Uri uri = slideDeck.getThumbnailSlide().getThumbnailUri();
return Glide.with(context) return Glide.with(context)
.load(new DecryptableStreamUriLoader.DecryptableUri(masterSecret, uri)) .load(new DecryptableStreamUriLoader.DecryptableUri(masterSecret, uri))