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.Recipients;
import org.thoughtcrime.securesms.sms.MessageSender;
import org.thoughtcrime.securesms.util.FutureTaskListener;
import org.thoughtcrime.securesms.util.ProgressDialogAsyncTask;
import org.thoughtcrime.securesms.util.SaveAttachmentTask;
import org.thoughtcrime.securesms.util.SaveAttachmentTask.Attachment;
@ -305,21 +304,16 @@ public class ConversationFragment extends Fragment
private void handleSaveAttachment(final MediaMmsMessageRecord message) {
SaveAttachmentTask.showWarningDialog(getActivity(), new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
message.fetchMediaSlide(new FutureTaskListener<Slide>() {
@Override
public void onSuccess(Slide slide) {
for (Slide slide : message.getSlideDeck().getSlides()) {
if (slide.hasImage() || slide.hasVideo() || slide.hasAudio()) {
SaveAttachmentTask saveTask = new SaveAttachmentTask(getActivity(), masterSecret);
saveTask.execute(new Attachment(slide.getUri(), slide.getContentType(), message.getDateReceived()));
return;
}
}
@Override
public void onFailure(Throwable error) {
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();
}
});
Log.w(TAG, "No slide with attachable media found, failing nicely.");
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) {
return messageRecord.isMms() &&
!messageRecord.isMmsNotification() &&
((MediaMmsMessageRecord)messageRecord).getPartCount() > 0;
((MediaMmsMessageRecord)messageRecord).getSlideDeck().getThumbnailSlide() != null;
}
private void setBodyText(MessageRecord messageRecord) {
@ -262,8 +262,9 @@ public class ConversationItem extends LinearLayout
setNotificationMmsAttributes((NotificationMmsMessageRecord) messageRecord);
} else if (hasMedia(messageRecord)) {
mediaThumbnail.setVisibility(View.VISIBLE);
//noinspection ConstantConditions
mediaThumbnail.setImageResource(masterSecret,
((MediaMmsMessageRecord)messageRecord).getSlideDeckFuture(),
((MediaMmsMessageRecord)messageRecord).getSlideDeck().getThumbnailSlide(),
!messageRecord.isFailed() && (!messageRecord.isOutgoing() || messageRecord.isPending()),
false);
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.RoundedCorners;
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.ViewUtil;
import org.whispersystems.libaxolotl.util.guava.Optional;
@ -46,8 +43,6 @@ public class ThumbnailView extends FrameLayout {
private OnClickListener parentClickListener;
private Optional<TransferControlView> transferControls = Optional.absent();
private ListenableFutureTask<SlideDeck> slideDeckFuture = null;
private SlideDeckListener slideDeckListener = null;
private ThumbnailClickListener thumbnailClickListener = null;
private ThumbnailClickListener downloadClickListener = null;
private Slide slide = null;
@ -117,25 +112,6 @@ public class ThumbnailView extends FrameLayout {
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,
boolean showControls, boolean showRemove)
{
@ -182,11 +158,9 @@ public class ThumbnailView extends FrameLayout {
public void clear() {
if (isContextValid()) Glide.clear(image);
if (slideDeckFuture != null) slideDeckFuture.removeListener(slideDeckListener);
if (transferControls.isPresent()) getTransferControls().clear();
slide = null;
slideDeckFuture = null;
slideDeckListener = null;
slide = null;
}
public void showProgressSpinner() {
@ -219,54 +193,6 @@ public class ThumbnailView extends FrameLayout {
.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 {
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 ROW_ID = "_id";
static final String ATTACHMENT_ID_ALIAS = "attachment_id";
static final String MMS_ID = "mid";
static final String CONTENT_TYPE = "ct";
private static final String NAME = "name";
private static final String CONTENT_DISPOSITION = "cd";
private static final String CONTENT_LOCATION = "cl";
static final String NAME = "name";
static final String CONTENT_DISPOSITION = "cd";
static final String CONTENT_LOCATION = "cl";
static final String DATA = "_data";
static final String TRANSFER_STATE = "pending_push";
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[] 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, " +
MMS_ID + " INTEGER, " + "seq" + " INTEGER DEFAULT 0, " +
CONTENT_TYPE + " TEXT, " + NAME + " TEXT, " + "chset" + " INTEGER, " +
@ -148,7 +155,7 @@ public class AttachmentDatabase extends Database {
Cursor cursor = null;
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);
else return null;
@ -165,7 +172,7 @@ public class AttachmentDatabase extends Database {
Cursor cursor = null;
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);
while (cursor != null && cursor.moveToNext()) {
@ -185,7 +192,7 @@ public class AttachmentDatabase extends Database {
Cursor cursor = null;
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()) {
attachments.add(getAttachment(cursor));
}
@ -417,8 +424,8 @@ public class AttachmentDatabase extends Database {
}
}
private DatabaseAttachment getAttachment(Cursor cursor) {
return new DatabaseAttachment(new AttachmentId(cursor.getLong(cursor.getColumnIndexOrThrow(ROW_ID)),
DatabaseAttachment getAttachment(Cursor cursor) {
return new DatabaseAttachment(new AttachmentId(cursor.getLong(cursor.getColumnIndexOrThrow(ATTACHMENT_ID_ALIAS)),
cursor.getLong(cursor.getColumnIndexOrThrow(UNIQUE_ID))),
cursor.getLong(cursor.getColumnIndexOrThrow(MMS_ID)),
!cursor.isNull(cursor.getColumnIndexOrThrow(DATA)),

View File

@ -1012,8 +1012,7 @@ public class MmsDatabase extends MessagingDatabase {
Recipients recipients = getRecipientsFor(address);
List<IdentityKeyMismatch> mismatches = getMismatchedIdentities(mismatchDocument);
List<NetworkFailure> networkFailures = getFailures(networkDocument);
ListenableFutureTask<SlideDeck> slideDeck = getSlideDeck(dateReceived, id);
SlideDeck slideDeck = getSlideDeck(cursor);
return new MediaMmsMessageRecord(context, id, recipients, recipients.getPrimaryRecipient(),
addressDeviceId, dateSent, dateReceived, receiptCount,
@ -1078,63 +1077,9 @@ public class MmsDatabase extends MessagingDatabase {
}
}
private ListenableFutureTask<SlideDeck> getSlideDeck(final long timestamp,
final long id)
{
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;
private SlideDeck getSlideDeck(@NonNull Cursor cursor) {
Attachment attachment = DatabaseFactory.getAttachmentDatabase(context).getAttachment(cursor);
return new SlideDeck(context, attachment);
}
public void close() {

View File

@ -16,11 +16,13 @@
*/
package org.thoughtcrime.securesms.database;
import android.annotation.TargetApi;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteQueryBuilder;
import android.os.Build;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.Log;
@ -34,33 +36,44 @@ import java.util.Set;
public class MmsSmsDatabase extends Database {
private static final String TAG = MmsSmsDatabase.class.getSimpleName();
public static final String TRANSPORT = "transport_type";
public static final String MMS_TRANSPORT = "mms";
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) {
super(context, databaseHelper);
}
public Cursor getConversation(long threadId, long limit) {
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 + " DESC";
String selection = MmsSmsColumns.THREAD_ID + " = " + threadId;
String order = MmsSmsColumns.NORMALIZED_DATE_RECEIVED + " DESC";
String selection = MmsSmsColumns.THREAD_ID + " = " + threadId;
Cursor cursor = queryTables(projection, selection, selection, order, null, limit > 0 ? String.valueOf(limit) : null);
Cursor cursor = queryTables(PROJECTION, selection, order, limit > 0 ? String.valueOf(limit) : null);
setNotifyConverationListeners(cursor, threadId);
return cursor;
@ -71,67 +84,27 @@ public class MmsSmsDatabase extends Database {
}
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 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);
return cursor;
}
public Cursor getConversationSnippet(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 + " DESC";
String selection = MmsSmsColumns.THREAD_ID + " = " + threadId;
String order = MmsSmsColumns.NORMALIZED_DATE_RECEIVED + " DESC";
String selection = MmsSmsColumns.THREAD_ID + " = " + threadId;
return queryTables(projection, selection, selection, order, null, "1");
return queryTables(PROJECTION, selection, order, "1");
}
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 selection = MmsSmsColumns.READ + " = 0";
return queryTables(projection, selection, selection, order, null, null);
return queryTables(PROJECTION, selection, order, null);
}
public int getConversationCount(long threadId) {
@ -146,27 +119,47 @@ public class MmsSmsDatabase extends Database {
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,
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,
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};
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,
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,
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};
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 smsQueryBuilder = new SQLiteQueryBuilder();
@ -174,10 +167,10 @@ public class MmsSmsDatabase extends Database {
mmsQueryBuilder.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);
Set<String> mmsColumnsPresent = new HashSet<String>();
Set<String> mmsColumnsPresent = new HashSet<>();
mmsColumnsPresent.add(MmsSmsColumns.ID);
mmsColumnsPresent.add(MmsSmsColumns.READ);
mmsColumnsPresent.add(MmsSmsColumns.THREAD_ID);
@ -198,7 +191,16 @@ public class MmsSmsDatabase extends Database {
mmsColumnsPresent.add(MmsDatabase.STATUS);
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.BODY);
smsColumnsPresent.add(MmsSmsColumns.ADDRESS);
@ -213,16 +215,16 @@ public class MmsSmsDatabase extends Database {
smsColumnsPresent.add(SmsDatabase.DATE_RECEIVED);
smsColumnsPresent.add(SmsDatabase.STATUS);
String mmsSubQuery = mmsQueryBuilder.buildUnionSubQuery(TRANSPORT, mmsProjection, mmsColumnsPresent, 2, MMS_TRANSPORT, mmsSelection, null, null, null);
String smsSubQuery = smsQueryBuilder.buildUnionSubQuery(TRANSPORT, smsProjection, smsColumnsPresent, 2, SMS_TRANSPORT, smsSelection, null, null, null);
String mmsSubQuery = mmsQueryBuilder.buildUnionSubQuery(TRANSPORT, mmsProjection, mmsColumnsPresent, 3, MMS_TRANSPORT, selection, null, null, null);
String smsSubQuery = smsQueryBuilder.buildUnionSubQuery(TRANSPORT, smsProjection, smsColumnsPresent, 3, SMS_TRANSPORT, selection, null, null, null);
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();
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);
SQLiteDatabase db = databaseHelper.getReadableDatabase();
@ -277,14 +279,15 @@ public class MmsSmsDatabase extends Database {
return getCurrent();
}
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public MessageRecord getCurrent() {
String type = cursor.getString(cursor.getColumnIndexOrThrow(TRANSPORT));
if (MmsSmsDatabase.MMS_TRANSPORT.equals(type)) {
return getMmsReader().getCurrent();
} else {
return getSmsReader().getCurrent();
}
Log.w("MmsSmsDatabase", "Type: " + type);
if (MmsSmsDatabase.MMS_TRANSPORT.equals(type)) return getMmsReader().getCurrent();
else if (MmsSmsDatabase.SMS_TRANSPORT.equals(type)) return getSmsReader().getCurrent();
else throw new AssertionError("Bad type: " + type);
}
public void close() {

View File

@ -17,23 +17,18 @@
package org.thoughtcrime.securesms.database.model;
import android.content.Context;
import android.support.annotation.NonNull;
import android.text.SpannableString;
import android.util.Log;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.database.MmsDatabase;
import org.thoughtcrime.securesms.database.documents.NetworkFailure;
import org.thoughtcrime.securesms.database.documents.IdentityKeyMismatch;
import org.thoughtcrime.securesms.mms.MediaNotFoundException;
import org.thoughtcrime.securesms.mms.Slide;
import org.thoughtcrime.securesms.database.documents.NetworkFailure;
import org.thoughtcrime.securesms.mms.SlideDeck;
import org.thoughtcrime.securesms.recipients.Recipient;
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.concurrent.ExecutionException;
/**
* 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 int partCount;
private final ListenableFutureTask<SlideDeck> slideDeckFutureTask;
private final @NonNull SlideDeck slideDeck;
public MediaMmsMessageRecord(Context context, long id, Recipients recipients,
Recipient individualRecipient, int recipientDeviceId,
long dateSent, long dateReceived, int deliveredCount,
long threadId, Body body,
ListenableFutureTask<SlideDeck> slideDeck,
@NonNull SlideDeck slideDeck,
int partCount, long mailbox,
List<IdentityKeyMismatch> mismatches,
List<NetworkFailure> failures)
@ -63,51 +58,17 @@ public class MediaMmsMessageRecord extends MessageRecord {
dateSent, dateReceived, threadId, DELIVERY_STATUS_NONE, deliveredCount, mailbox,
mismatches, failures);
this.context = context.getApplicationContext();
this.partCount = partCount;
this.slideDeckFutureTask = slideDeck;
this.context = context.getApplicationContext();
this.partCount = partCount;
this.slideDeck = slideDeck;
}
public ListenableFutureTask<SlideDeck> getSlideDeckFuture() {
return slideDeckFutureTask;
}
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 @NonNull SlideDeck getSlideDeck() {
return slideDeck;
}
public boolean containsMediaSlide() {
SlideDeck deck = getSlideDeckSync();
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);
}
});
return slideDeck.containsMediaSlide();
}
public int getPartCount() {

View File

@ -17,29 +17,14 @@
package org.thoughtcrime.securesms.mms;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.support.annotation.Nullable;
import android.util.Pair;
import org.thoughtcrime.securesms.R;
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.SmilUtil;
import org.thoughtcrime.securesms.util.Util;
import java.io.ByteArrayOutputStream;
import java.io.UnsupportedEncodingException;
import java.util.LinkedList;
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 {
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() {
}

View File

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

View File

@ -21,12 +21,12 @@ public class NotificationItem {
private final long threadId;
private final CharSequence text;
private final long timestamp;
private final ListenableFutureTask<SlideDeck> slideDeck;
private final @Nullable SlideDeck slideDeck;
public NotificationItem(Recipient individualRecipient, Recipients recipients,
Recipients threadRecipients, long threadId,
CharSequence text, long timestamp,
@Nullable ListenableFutureTask<SlideDeck> slideDeck)
@Nullable SlideDeck slideDeck)
{
this.individualRecipient = individualRecipient;
this.recipients = recipients;
@ -57,7 +57,7 @@ public class NotificationItem {
return threadId;
}
public @Nullable ListenableFutureTask<SlideDeck> getSlideDeck() {
public @Nullable SlideDeck getSlideDeck() {
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.RemoteInput;
import android.text.SpannableStringBuilder;
import android.util.Log;
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.recipients.Recipient;
import org.thoughtcrime.securesms.util.BitmapUtil;
import org.thoughtcrime.securesms.util.ListenableFutureTask;
import java.util.LinkedList;
import java.util.List;
@ -38,8 +36,8 @@ public class SingleRecipientNotificationBuilder extends AbstractNotificationBuil
private final List<CharSequence> messageBodies = new LinkedList<>();
private ListenableFutureTask<SlideDeck> slideDeck;
private final MasterSecret masterSecret;
private SlideDeck slideDeck;
private final MasterSecret masterSecret;
public SingleRecipientNotificationBuilder(@NonNull Context context,
@Nullable MasterSecret masterSecret,
@ -81,7 +79,7 @@ public class SingleRecipientNotificationBuilder extends AbstractNotificationBuil
setNumber(messageCount);
}
public void setPrimaryMessageBody(CharSequence message, @Nullable ListenableFutureTask<SlideDeck> slideDeck) {
public void setPrimaryMessageBody(CharSequence message, @Nullable SlideDeck slideDeck) {
if (privacy.isDisplayMessage()) {
setContentText(message);
this.slideDeck = slideDeck;
@ -166,30 +164,25 @@ public class SingleRecipientNotificationBuilder extends AbstractNotificationBuil
}
}
private boolean hasBigPictureSlide(@Nullable ListenableFutureTask<SlideDeck> slideDeck) {
try {
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);
private boolean hasBigPictureSlide(@Nullable SlideDeck slideDeck) {
if (masterSecret == null || slideDeck == null || Build.VERSION.SDK_INT < 16) {
return false;
}
Slide thumbnailSlide = slideDeck.getThumbnailSlide();
return thumbnailSlide != null &&
thumbnailSlide.hasImage() &&
!thumbnailSlide.isInProgress() &&
thumbnailSlide.getThumbnailUri() != null;
}
private Bitmap getBigPicture(@NonNull MasterSecret masterSecret,
@NonNull ListenableFutureTask<SlideDeck> slideDeck)
@NonNull SlideDeck slideDeck)
{
try {
Uri uri = slideDeck.get().getThumbnailSlide().getThumbnailUri();
@SuppressWarnings("ConstantConditions")
Uri uri = slideDeck.getThumbnailSlide().getThumbnailUri();
return Glide.with(context)
.load(new DecryptableStreamUriLoader.DecryptableUri(masterSecret, uri))