MMS and Group Messaging Improvements

1) Display the individual sender name in a group conversation.

2) Add an "address" column to MmsDatabase and keep FROM there.

3) Remove all blocking operations from MmsDatabase.Reader path.

4) Strip SMIL and other undisplayable parts from part count.

5) Fix places where messages weren't being correctly decrypted.
This commit is contained in:
Moxie Marlinspike 2013-05-05 12:51:36 -07:00
parent 2305a648fb
commit 723fb4ffdd
12 changed files with 241 additions and 246 deletions

View File

@ -51,15 +51,17 @@ public class ConversationAdapter extends CursorAdapter implements AbsListView.Re
private final Handler failedIconClickHandler;
private final Context context;
private final MasterSecret masterSecret;
private final boolean groupThread;
private final LayoutInflater inflater;
public ConversationAdapter(Recipients recipients, long threadId, Context context,
MasterSecret masterSecret, Handler failedIconClickHandler)
public ConversationAdapter(Context context, MasterSecret masterSecret,
Handler failedIconClickHandler, boolean groupThread)
{
super(context, null);
this.context = context;
this.masterSecret = masterSecret;
this.failedIconClickHandler = failedIconClickHandler;
this.groupThread = groupThread;
this.messageRecordCache = initializeCache();
this.inflater = (LayoutInflater)context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
@ -72,7 +74,7 @@ public class ConversationAdapter extends CursorAdapter implements AbsListView.Re
String type = cursor.getString(cursor.getColumnIndexOrThrow(MmsSmsDatabase.TRANSPORT));
MessageRecord messageRecord = getMessageRecord(id, cursor, type);
item.set(masterSecret, messageRecord, failedIconClickHandler);
item.set(masterSecret, messageRecord, failedIconClickHandler, groupThread);
}
@Override

View File

@ -167,8 +167,9 @@ public class ConversationFragment extends SherlockListFragment
private void initializeListAdapter() {
if (this.recipients != null && this.threadId != -1) {
this.setListAdapter(new ConversationAdapter(recipients, threadId, getActivity(),
masterSecret, new FailedIconClickHandler()));
this.setListAdapter(new ConversationAdapter(getActivity(), masterSecret,
new FailedIconClickHandler(),
!this.recipients.isSingleRecipient()));
getListView().setRecyclerListener((ConversationAdapter)getListAdapter());
getLoaderManager().initLoader(0, null, this);
}

View File

@ -73,6 +73,7 @@ public class ConversationItem extends LinearLayout {
private Handler failedIconHandler;
private MessageRecord messageRecord;
private MasterSecret masterSecret;
private boolean groupThread;
private TextView bodyText;
private TextView dateText;
@ -125,11 +126,13 @@ public class ConversationItem extends LinearLayout {
this.mmsDownloadButton.setOnClickListener(mmsDownloadClickListener);
}
public void set(MasterSecret masterSecret, MessageRecord messageRecord, Handler failedIconHandler)
public void set(MasterSecret masterSecret, MessageRecord messageRecord,
Handler failedIconHandler, boolean groupThread)
{
this.messageRecord = messageRecord;
this.masterSecret = masterSecret;
this.failedIconHandler = failedIconHandler;
this.groupThread = groupThread;
setBodyText(messageRecord);
setStatusIcons(messageRecord);
@ -201,19 +204,12 @@ public class ConversationItem extends LinearLayout {
}
private void setGroupMessageStatus(MessageRecord messageRecord) {
// GroupData groupData = messageRecord.getGroupData();
//
// if (groupData != null) {
// String status = String.format("Sent (%d/%d)", groupData.groupSentCount, groupData.groupSize);
//
// if (groupData.groupSendFailedCount != 0)
// status = status + String.format(", Failed (%d/%d)", groupData.groupSendFailedCount, groupData.groupSize);
//
// this.groupStatusText.setText(status);
// this.groupStatusText.setVisibility(View.VISIBLE);
// } else {
if (groupThread && !messageRecord.isOutgoing()) {
this.groupStatusText.setText(messageRecord.getIndividualRecipient().toShortString());
this.groupStatusText.setVisibility(View.VISIBLE);
} else {
this.groupStatusText.setVisibility(View.GONE);
// }
}
}
private void setNotificationMmsAttributes(NotificationMmsMessageRecord messageRecord) {
@ -242,6 +238,8 @@ public class ConversationItem extends LinearLayout {
if (messageRecord.getPartCount() > 0) {
mmsThumbnail.setVisibility(View.VISIBLE);
mmsThumbnail.setImageDrawable(new ColorDrawable(Color.TRANSPARENT));
} else {
mmsThumbnail.setVisibility(View.GONE);
}
slideDeck = messageRecord.getSlideDeck();

View File

@ -19,6 +19,8 @@ package org.thoughtcrime.securesms.database;
import android.content.ContentValues;
import android.util.Log;
import org.thoughtcrime.securesms.util.Util;
import ws.com.google.android.mms.pdu.CharacterSets;
import ws.com.google.android.mms.pdu.EncodedStringValue;
@ -34,14 +36,14 @@ public class ContentValuesBuilder {
public void add(String key, String charsetKey, EncodedStringValue value) {
if (value != null) {
contentValues.put(key, toIsoString(value.getTextString()));
contentValues.put(key, Util.toIsoString(value.getTextString()));
contentValues.put(charsetKey, value.getCharacterSet());
}
}
public void add(String contentKey, byte[] value) {
if (value != null) {
contentValues.put(contentKey, toIsoString(value));
contentValues.put(contentKey, Util.toIsoString(value));
}
}
@ -58,14 +60,4 @@ public class ContentValuesBuilder {
public ContentValues getContentValues() {
return contentValues;
}
private String toIsoString(byte[] bytes) {
try {
return new String(bytes, CharacterSets.MIMENAME_ISO_8859_1);
} catch (UnsupportedEncodingException e) {
Log.e("MmsDatabase", "ISO_8859_1 must be supported!", e);
return "";
}
}
}

View File

@ -44,7 +44,8 @@ public class DatabaseFactory {
private static final int INTRODUCED_DRAFTS_VERSION = 5;
private static final int INTRODUCED_NEW_TYPES_VERSION = 6;
private static final int INTRODUCED_MMS_BODY_VERSION = 7;
private static final int DATABASE_VERSION = 7;
private static final int INTRODUCED_MMS_FROM_VERSION = 8;
private static final int DATABASE_VERSION = 8;
private static final String DATABASE_NAME = "messages.db";
private static final Object lock = new Object();
@ -213,10 +214,14 @@ public class DatabaseFactory {
listener.setProgress(smsCursor.getCount() + threadCursor.getPosition(), count);
try {
String snippet = masterCipher.decryptBody(threadCursor.getString(threadCursor.getColumnIndexOrThrow("snippet")));
String snippet = threadCursor.getString(threadCursor.getColumnIndexOrThrow("snippet"));
long snippetType = threadCursor.getLong(threadCursor.getColumnIndexOrThrow("snippet_type"));
long id = threadCursor.getLong(threadCursor.getColumnIndexOrThrow("_id"));
if (!Util.isEmpty(snippet)) {
snippet = masterCipher.decryptBody(snippet);
}
if (snippet.startsWith(KEY_EXCHANGE)) {
snippet = snippet.substring(KEY_EXCHANGE.length());
snippet = masterCipher.encryptBody(snippet);
@ -348,6 +353,8 @@ public class DatabaseFactory {
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.beginTransaction();
if (oldVersion < INTRODUCED_IDENTITIES_VERSION) {
db.execSQL("CREATE TABLE identities (_id INTEGER PRIMARY KEY, key TEXT UNIQUE, name TEXT UNIQUE, mac TEXT);");
}
@ -377,24 +384,18 @@ public class DatabaseFactory {
}
if (oldVersion < INTRODUCED_DATE_SENT_VERSION) {
db.beginTransaction();
db.execSQL("ALTER TABLE sms ADD COLUMN date_sent INTEGER;");
db.execSQL("UPDATE sms SET date_sent = date;");
db.execSQL("ALTER TABLE mms ADD COLUMN date_received INTEGER;");
db.execSQL("UPDATE mms SET date_received = date;");
db.setTransactionSuccessful();
db.endTransaction();
}
if (oldVersion < INTRODUCED_DRAFTS_VERSION) {
db.beginTransaction();
db.execSQL("CREATE TABLE drafts (_id INTEGER PRIMARY KEY, thread_id INTEGER, type TEXT, value TEXT);");
executeStatements(db, new String[] {
"CREATE INDEX IF NOT EXISTS draft_thread_index ON drafts (thread_id);",
});
db.setTransactionSuccessful();
db.endTransaction();
}
if (oldVersion < INTRODUCED_NEW_TYPES_VERSION) {
@ -405,7 +406,6 @@ public class DatabaseFactory {
String PROCESSED_KEY_EXCHANGE = "?TextSecureKeyExchangd";
String STALE_KEY_EXCHANGE = "?TextSecureKeyExchangs";
db.beginTransaction();
// SMS Updates
db.execSQL("UPDATE sms SET type = ? WHERE type = ?", new String[] {20L+"", 1L+""});
db.execSQL("UPDATE sms SET type = ? WHERE type = ?", new String[] {21L+"", 43L+""});
@ -425,26 +425,41 @@ public class DatabaseFactory {
updateSmsBodyAndType(db, cursor, SYMMETRIC_ENCRYPT, 0x80000000L);
if (cursor != null)
cursor.close();
cursor = db.query("sms", null,"body LIKE ?", new String[] {ASYMMETRIC_LOCAL_ENCRYPT + "%"},
null, null, null);
updateSmsBodyAndType(db, cursor, ASYMMETRIC_LOCAL_ENCRYPT, 0x40000000L);
if (cursor != null)
cursor.close();
cursor = db.query("sms", null,"body LIKE ?", new String[] {ASYMMETRIC_ENCRYPT + "%"},
null, null, null);
updateSmsBodyAndType(db, cursor, ASYMMETRIC_ENCRYPT, 0L);
if (cursor != null)
cursor.close();
cursor = db.query("sms", null,"body LIKE ?", new String[] {KEY_EXCHANGE + "%"},
null, null, null);
updateSmsBodyAndType(db, cursor, KEY_EXCHANGE, 0x8000L);
if (cursor != null)
cursor.close();
cursor = db.query("sms", null,"body LIKE ?", new String[] {PROCESSED_KEY_EXCHANGE + "%"},
null, null, null);
updateSmsBodyAndType(db, cursor, PROCESSED_KEY_EXCHANGE, 0x8000L | 0x2000L);
if (cursor != null)
cursor.close();
cursor = db.query("sms", null,"body LIKE ?", new String[] {STALE_KEY_EXCHANGE + "%"},
null, null, null);
@ -468,34 +483,68 @@ public class DatabaseFactory {
db.execSQL("ALTER TABLE thread ADD COLUMN snippet_type INTEGER;");
if (cursor != null)
cursor.close();
cursor = db.query("thread", null,"snippet LIKE ?",
new String[] {SYMMETRIC_ENCRYPT + "%"}, null, null, null);
updateThreadSnippetAndType(db, cursor, SYMMETRIC_ENCRYPT, 0x80000000L);
if (cursor != null)
cursor.close();
cursor = db.query("thread", null,"snippet LIKE ?",
new String[] {KEY_EXCHANGE + "%"}, null, null, null);
updateThreadSnippetAndType(db, cursor, KEY_EXCHANGE, 0x8000L);
if (cursor != null)
cursor.close();
cursor = db.query("thread", null,"snippet LIKE ?",
new String[] {STALE_KEY_EXCHANGE + "%"}, null, null, null);
updateThreadSnippetAndType(db, cursor, STALE_KEY_EXCHANGE, 0x8000L | 0x4000L);
if (cursor != null)
cursor.close();
cursor = db.query("thread", null,"snippet LIKE ?",
new String[] {PROCESSED_KEY_EXCHANGE + "%"}, null, null, null);
updateThreadSnippetAndType(db, cursor, KEY_EXCHANGE, 0x8000L | 0x2000L);
db.setTransactionSuccessful();
db.endTransaction();
if (cursor != null)
cursor.close();
}
if (oldVersion < INTRODUCED_MMS_BODY_VERSION) {
db.execSQL("ALTER TABLE mms ADD COLUMN body TEXT");
db.execSQL("ALTER TABLE mms ADD COLUMN part_count INTEGER");
}
if (oldVersion < INTRODUCED_MMS_FROM_VERSION) {
db.execSQL("ALTER TABLE mms ADD COLUMN address TEXT");
Cursor cursor = db.query("mms_addresses", null, "type = ?", new String[] {0x89+""},
null, null, null);
while (cursor != null && cursor.moveToNext()) {
long mmsId = cursor.getLong(cursor.getColumnIndexOrThrow("mms_id"));
String address = cursor.getString(cursor.getColumnIndexOrThrow("address"));
if (!Util.isEmpty(address)) {
db.execSQL("UPDATE mms SET address = ? WHERE _id = ?", new String[]{address, mmsId+""});
}
}
if (cursor != null)
cursor.close();
}
db.setTransactionSuccessful();
db.endTransaction();
}
private void updateSmsBodyAndType(SQLiteDatabase db, Cursor cursor, String prefix, long typeMask)

View File

@ -35,6 +35,7 @@ import org.thoughtcrime.securesms.database.model.MessageRecord;
import org.thoughtcrime.securesms.database.model.NotificationMmsMessageRecord;
import org.thoughtcrime.securesms.mms.PartParser;
import org.thoughtcrime.securesms.mms.SlideDeck;
import org.thoughtcrime.securesms.mms.TextSlide;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientFactory;
import org.thoughtcrime.securesms.recipients.RecipientFormattingException;
@ -75,19 +76,19 @@ public class MmsDatabase extends Database implements MmsSmsColumns {
private static final String MESSAGE_ID = "m_id";
private static final String SUBJECT = "sub";
private static final String SUBJECT_CHARSET = "sub_cs";
private static final String CONTENT_TYPE = "ct_t";
private static final String CONTENT_LOCATION = "ct_l";
private static final String EXPIRY = "exp";
static final String CONTENT_TYPE = "ct_t";
static final String CONTENT_LOCATION = "ct_l";
static final String EXPIRY = "exp";
private static final String MESSAGE_CLASS = "m_cls";
public static final String MESSAGE_TYPE = "m_type";
private static final String MMS_VERSION = "v";
private static final String MESSAGE_SIZE = "m_size";
static final String MESSAGE_SIZE = "m_size";
private static final String PRIORITY = "pri";
private static final String READ_REPORT = "rr";
private static final String REPORT_ALLOWED = "rpt_a";
private static final String RESPONSE_STATUS = "resp_st";
private static final String STATUS = "st";
private static final String TRANSACTION_ID = "tr_id";
static final String STATUS = "st";
static final String TRANSACTION_ID = "tr_id";
private static final String RETRIEVE_STATUS = "retr_st";
private static final String RETRIEVE_TEXT = "retr_txt";
private static final String RETRIEVE_TEXT_CS = "retr_txt_cs";
@ -102,7 +103,7 @@ public class MmsDatabase extends Database implements MmsSmsColumns {
THREAD_ID + " INTEGER, " + DATE_SENT + " INTEGER, " + DATE_RECEIVED + " INTEGER, " + MESSAGE_BOX + " INTEGER, " +
READ + " INTEGER DEFAULT 0, " + MESSAGE_ID + " TEXT, " + SUBJECT + " TEXT, " +
SUBJECT_CHARSET + " INTEGER, " + BODY + " TEXT, " + PART_COUNT + " INTEGER, " +
CONTENT_TYPE + " TEXT, " + CONTENT_LOCATION + " TEXT, " +
CONTENT_TYPE + " TEXT, " + CONTENT_LOCATION + " TEXT, " + ADDRESS + " TEXT, " +
EXPIRY + " INTEGER, " + MESSAGE_CLASS + " TEXT, " + MESSAGE_TYPE + " INTEGER, " +
MMS_VERSION + " INTEGER, " + MESSAGE_SIZE + " INTEGER, " + PRIORITY + " INTEGER, " +
READ_REPORT + " INTEGER, " + REPORT_ALLOWED + " INTEGER, " + RESPONSE_STATUS + " INTEGER, " +
@ -125,7 +126,7 @@ public class MmsDatabase extends Database implements MmsSmsColumns {
CONTENT_LOCATION, EXPIRY, MESSAGE_CLASS, MESSAGE_TYPE, MMS_VERSION,
MESSAGE_SIZE, PRIORITY, REPORT_ALLOWED, STATUS, TRANSACTION_ID, RETRIEVE_STATUS,
RETRIEVE_TEXT, RETRIEVE_TEXT_CS, READ_STATUS, CONTENT_CLASS, RESPONSE_TEXT,
DELIVERY_TIME, DELIVERY_REPORT, BODY, PART_COUNT
DELIVERY_TIME, DELIVERY_REPORT, BODY, PART_COUNT, ADDRESS
};
public static final ExecutorService slideResolver = Util.newSingleThreadedLifoExecutor();
@ -208,35 +209,6 @@ public class MmsDatabase extends Database implements MmsSmsColumns {
}
}
public Recipient getMessageRecipient(long messageId) {
try {
PduHeaders headers = new PduHeaders();
MmsAddressDatabase database = DatabaseFactory.getMmsAddressDatabase(context);
database.getAddressesForId(messageId, headers);
EncodedStringValue encodedFrom = headers.getEncodedStringValue(PduHeaders.FROM);
if (encodedFrom != null) {
String address = new String(encodedFrom.getTextString(), CharacterSets.MIMENAME_ISO_8859_1);
Recipients recipients = RecipientFactory.getRecipientsFromString(context, address, false);
if (recipients == null || recipients.isEmpty()) {
return new Recipient("Unknown", "Unknown", null,
ContactPhotoFactory.getDefaultContactPhoto(context));
}
return recipients.getPrimaryRecipient();
} else {
return new Recipient("Unknown", "Unknown", null,
ContactPhotoFactory.getDefaultContactPhoto(context));
}
} catch (UnsupportedEncodingException e) {
throw new AssertionError(e);
} catch (RecipientFormattingException e) {
return new Recipient("Unknown", "Unknown", null,
ContactPhotoFactory.getDefaultContactPhoto(context));
}
}
public void updateResponseStatus(long messageId, int status) {
SQLiteDatabase database = databaseHelper.getWritableDatabase();
ContentValues contentValues = new ContentValues();
@ -295,40 +267,29 @@ public class MmsDatabase extends Database implements MmsSmsColumns {
database.update(TABLE_NAME, contentValues, THREAD_ID + " = ?", new String[] {threadId+""});
}
public NotificationInd getNotificationMessage(long messageId) throws MmsException {
PduHeaders headers = getHeadersForId(messageId);
return new NotificationInd(headers);
}
private MultimediaMessagePdu getMediaMessage(long messageId)
public SendReq[] getOutgoingMessages(MasterSecret masterSecret, long messageId)
throws MmsException
{
PduHeaders headers = getHeadersForId(messageId);
PartDatabase partDatabase = getPartDatabase(null);
PduBody body = partDatabase.getParts(messageId, false);
MmsAddressDatabase addr = DatabaseFactory.getMmsAddressDatabase(context);
PartDatabase parts = getPartDatabase(masterSecret);
SQLiteDatabase database = databaseHelper.getReadableDatabase();
MasterCipher masterCipher = masterSecret == null ? null : new MasterCipher(masterSecret);
Cursor cursor = null;
return new MultimediaMessagePdu(headers, body);
}
public SendReq getSendRequest(MasterSecret masterSecret, long messageId) throws MmsException {
PduHeaders headers = getHeadersForId(messageId);
PartDatabase partDatabase = getPartDatabase(masterSecret);
PduBody body = partDatabase.getParts(messageId, true);
String selection;
String[] selectionArgs;
return new SendReq(headers, body, messageId, headers.getMessageBox());
}
public SendReq[] getOutgoingMessages(MasterSecret masterSecret) throws MmsException {
MmsAddressDatabase addr = DatabaseFactory.getMmsAddressDatabase(context);
PartDatabase parts = getPartDatabase(masterSecret);
SQLiteDatabase database = databaseHelper.getReadableDatabase();
Cursor cursor = null;
if (messageId > 0) {
selection = ID_WHERE;
selectionArgs = new String[]{messageId + ""};
} else {
selection = MESSAGE_BOX + " & " + Types.BASE_TYPE_MASK + " = ?";
selectionArgs = new String[]{Types.BASE_OUTBOX_TYPE + ""};
}
try {
cursor = database.query(TABLE_NAME, MMS_PROJECTION,
MESSAGE_BOX + " & " + Types.BASE_TYPE_MASK + " = ?",
new String[] {Types.BASE_OUTBOX_TYPE+""},
null, null, null);
cursor = database.query(TABLE_NAME, MMS_PROJECTION, selection, selectionArgs, null, null, null);
if (cursor == null || cursor.getCount() == 0)
return new SendReq[0];
@ -337,12 +298,25 @@ public class MmsDatabase extends Database implements MmsSmsColumns {
int i = 0;
while (cursor.moveToNext()) {
long messageId = cursor.getLong(cursor.getColumnIndexOrThrow(ID));
messageId = cursor.getLong(cursor.getColumnIndexOrThrow(ID));
long outboxType = cursor.getLong(cursor.getColumnIndexOrThrow(MESSAGE_BOX));
PduHeaders headers = getHeadersFromCursor(cursor);
String messageText = cursor.getString(cursor.getColumnIndexOrThrow(BODY));
PduHeaders headers = getHeadersFromCursor(cursor);
addr.getAddressesForId(messageId, headers);
PduBody body = parts.getParts(messageId, true);
requests[i++] = new SendReq(headers, body, messageId, outboxType);
try {
if (!Util.isEmpty(messageText) && Types.isSymmetricEncryption(outboxType)) {
body.addPart(new TextSlide(context, masterCipher.decryptBody(messageText)).getPart());
} else if (!Util.isEmpty(messageText)) {
body.addPart(new TextSlide(context, messageText).getPart());
}
} catch (InvalidMessageException e) {
Log.w("MmsDatabase", e);
}
requests[i++] = new SendReq(headers, body, messageId, outboxType);
}
return requests;
@ -467,6 +441,7 @@ public class MmsDatabase extends Database implements MmsSmsColumns {
contentValues.put(THREAD_ID, threadId);
contentValues.put(READ, 1);
contentValues.put(DATE_RECEIVED, contentValues.getAsLong(DATE_SENT));
contentValues.remove(ADDRESS);
long messageId = insertMediaMessage(masterSecret, sendRequest, contentValues);
Trimmer.trimThread(context, threadId);
@ -493,7 +468,7 @@ public class MmsDatabase extends Database implements MmsSmsColumns {
}
}
contentValues.put(PART_COUNT, body.getPartsNum());
contentValues.put(PART_COUNT, PartParser.getDisplayablePartCount(body));
long messageId = db.insert(TABLE_NAME, null, contentValues);
@ -601,31 +576,6 @@ public class MmsDatabase extends Database implements MmsSmsColumns {
}
}
private PduHeaders getHeadersForId(long messageId) throws MmsException {
SQLiteDatabase database = databaseHelper.getReadableDatabase();
Cursor cursor = null;
try {
cursor = database.query(TABLE_NAME, MMS_PROJECTION, ID_WHERE, new String[] {messageId+""},
null, null, null);
if (cursor == null || !cursor.moveToFirst())
throw new MmsException("No headers available at ID: " + messageId);
PduHeaders headers = getHeadersFromCursor(cursor);
long messageBox = cursor.getLong(cursor.getColumnIndexOrThrow(MESSAGE_BOX));
MmsAddressDatabase addr = DatabaseFactory.getMmsAddressDatabase(context);
addr.getAddressesForId(messageId, headers);
headers.setMessageBox(messageBox);
return headers;
} finally {
if (cursor != null)
cursor.close();
}
}
private PduHeaders getHeadersFromCursor(Cursor cursor) throws InvalidHeaderValueException {
PduHeaders headers = new PduHeaders();
PduHeadersBuilder phb = new PduHeadersBuilder(headers, cursor);
@ -683,6 +633,7 @@ public class MmsDatabase extends Database implements MmsSmsColumns {
cvb.add(DELIVERY_TIME, headers.getLongInteger(PduHeaders.DELIVERY_TIME));
cvb.add(EXPIRY, headers.getLongInteger(PduHeaders.EXPIRY));
cvb.add(MESSAGE_SIZE, headers.getLongInteger(PduHeaders.MESSAGE_SIZE));
cvb.add(ADDRESS, headers.getEncodedStringValue(PduHeaders.FROM).getTextString());
return cvb.getContentValues();
}
@ -759,23 +710,76 @@ public class MmsDatabase extends Database implements MmsSmsColumns {
}
}
private NotificationMmsMessageRecord getNotificationMmsMessageRecord(Cursor cursor) {
long id = cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.ID));
long dateSent = cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.NORMALIZED_DATE_SENT));
long dateReceived = cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.NORMALIZED_DATE_RECEIVED));
long threadId = cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.THREAD_ID));
long mailbox = cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.MESSAGE_BOX));
String address = cursor.getString(cursor.getColumnIndexOrThrow(MmsDatabase.ADDRESS));
Recipients recipients = getRecipientsFor(address);
String contentLocation = cursor.getString(cursor.getColumnIndexOrThrow(MmsDatabase.CONTENT_LOCATION));
String transactionId = cursor.getString(cursor.getColumnIndexOrThrow(MmsDatabase.TRANSACTION_ID));
long messageSize = cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.MESSAGE_SIZE));
long expiry = cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.EXPIRY));
int status = cursor.getInt(cursor.getColumnIndexOrThrow(MmsDatabase.STATUS));
byte[]contentLocationBytes = null;
byte[]transactionIdBytes = null;
if (!Util.isEmpty(contentLocation))
contentLocationBytes = Util.toIsoBytes(contentLocation);
if (!Util.isEmpty(transactionId))
transactionIdBytes = Util.toIsoBytes(transactionId);
return new NotificationMmsMessageRecord(context, id, recipients, recipients.getPrimaryRecipient(),
dateSent, dateReceived, threadId, contentLocationBytes,
messageSize, expiry, status, transactionIdBytes, mailbox);
}
private MediaMmsMessageRecord getMediaMmsMessageRecord(Cursor cursor) {
long id = cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.ID));
long dateSent = cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.NORMALIZED_DATE_SENT));
long dateReceived = cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.NORMALIZED_DATE_RECEIVED));
long box = cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.MESSAGE_BOX));
long threadId = cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.THREAD_ID));
String address = cursor.getString(cursor.getColumnIndexOrThrow(MmsDatabase.ADDRESS));
DisplayRecord.Body body = getBody(cursor);
int partCount = cursor.getInt(cursor.getColumnIndexOrThrow(MmsDatabase.PART_COUNT));
Recipient recipient = getMessageRecipient(id);
Recipients recipients = getRecipientsFor(address);
ListenableFutureTask<SlideDeck> slideDeck = getSlideDeck(masterSecret, id);
return new MediaMmsMessageRecord(context, id, new Recipients(recipient), recipient,
return new MediaMmsMessageRecord(context, id, recipients, recipients.getPrimaryRecipient(),
dateSent, dateReceived, threadId, body,
slideDeck, partCount, box);
}
private Recipients getRecipientsFor(String address) {
try {
if (Util.isEmpty(address)) {
return new Recipients(new Recipient("Unknown", "Unknown", null,
ContactPhotoFactory.getDefaultContactPhoto(context)));
}
Recipients recipients = RecipientFactory.getRecipientsFromString(context, address, false);
if (recipients == null || recipients.isEmpty()) {
return new Recipients(new Recipient("Unknown", "Unknown", null,
ContactPhotoFactory.getDefaultContactPhoto(context)));
}
return recipients;
} catch (RecipientFormattingException e) {
Log.w("MmsDatabase", e);
return new Recipients(new Recipient("Unknown", "Unknown", null,
ContactPhotoFactory.getDefaultContactPhoto(context)));
}
}
private DisplayRecord.Body getBody(Cursor cursor) {
try {
String body = cursor.getString(cursor.getColumnIndexOrThrow(MmsDatabase.BODY));
@ -800,17 +804,11 @@ public class MmsDatabase extends Database implements MmsSmsColumns {
Callable<SlideDeck> task = new Callable<SlideDeck>() {
@Override
public SlideDeck call() throws Exception {
try {
if (masterSecret == null)
return null;
MultimediaMessagePdu pdu = getMediaMessage(id);
return new SlideDeck(context, masterSecret, pdu.getBody());
} catch (MmsException me) {
Log.w("MmsDatabase", me);
if (masterSecret == null)
return null;
}
PduBody body = getPartDatabase(masterSecret).getParts(id, false);
return new SlideDeck(context, masterSecret, body);
}
};
@ -820,34 +818,6 @@ public class MmsDatabase extends Database implements MmsSmsColumns {
return future;
}
private NotificationMmsMessageRecord getNotificationMmsMessageRecord(Cursor cursor) {
long id = cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.ID));
long dateSent = cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.NORMALIZED_DATE_SENT));
long dateReceived = cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.NORMALIZED_DATE_RECEIVED));
long threadId = cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.THREAD_ID));
long mailbox = cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.MESSAGE_BOX));
Recipient recipient = getMessageRecipient(id);
NotificationInd notification;
try {
notification = getNotificationMessage(id);
} catch (MmsException me) {
Log.w("ConversationAdapter", me);
notification = new NotificationInd(new PduHeaders());
}
return new NotificationMmsMessageRecord(context, id, new Recipients(recipient), recipient,
dateSent, dateReceived, threadId,
notification.getContentLocation(),
notification.getMessageSize(),
notification.getExpiry(),
notification.getStatus(),
notification.getTransactionId(),
mailbox);
}
public void close() {
cursor.close();
}

View File

@ -8,6 +8,8 @@ public interface MmsSmsColumns {
public static final String THREAD_ID = "thread_id";
public static final String READ = "read";
public static final String BODY = "body";
public static final String ADDRESS = "address";
public static class Types {
protected static final long TOTAL_MASK = 0xFFFFFFFF;

View File

@ -39,54 +39,6 @@ public class MmsSmsDatabase extends Database {
super(context, databaseHelper);
}
// public Cursor getCollatedGroupConversation(long threadId) {
// String smsCaseSecurity = "CASE " + SmsDatabase.TYPE + " & " + SmsDatabase.Types.SECURE_MESSAGE_BIT + " " +
// "WHEN " + SmsDatabase.Types.SECURE_MESSAGE_BIT + " THEN 1 " +
// "ELSE 0 END";
//
// String mmsCaseSecurity = "CASE " + MmsDatabase.MESSAGE_BOX + " & " + SmsDatabase.Types.SECURE_MESSAGE_BIT + " " +
// "WHEN " + MmsDatabase.Types.SECURE_MESSAGE_BIT + " THEN 'secure' " +
// "ELSE 'insecure' END";
//
// String mmsGroupSentCount = "SUM(CASE " + MmsDatabase.MESSAGE_BOX + " & " + MmsDatabase.Types.BASE_TYPE_MASK + " " +
// "WHEN " + MmsDatabase.Types.BASE_SENT_TYPE + " THEN 1 " +
// "ELSE 0 END)";
//
//
// String smsGroupSentCount = "SUM(CASE " + SmsDatabase.TYPE + " & " + SmsDatabase.Types.BASE_TYPE_MASK + " " +
// "WHEN " + SmsDatabase.Types.BASE_SENT_TYPE + " THEN 1 " +
// "ELSE 0 END)";
//
// String mmsGroupSentFailedCount = "SUM(CASE " + MmsDatabase.MESSAGE_BOX + " & " + MmsDatabase.Types.BASE_TYPE_MASK + " " +
// "WHEN " + MmsDatabase.Types.BASE_SENT_FAILED_TYPE + " THEN 1 " +
// "ELSE 0 END)";
//
// String smsGroupSentFailedCount = "SUM(CASE " + SmsDatabase.TYPE + " & " + SmsDatabase.Types.BASE_TYPE_MASK + " " +
// "WHEN " + SmsDatabase.Types.BASE_SENT_FAILED_TYPE + " THEN 1 " +
// "ELSE 0 END)";
//
// String[] projection = {MmsSmsColumns.ID, SmsDatabase.BODY, SmsDatabase.TYPE,
// MmsSmsColumns.THREAD_ID,
// SmsDatabase.ADDRESS, SmsDatabase.SUBJECT, SmsDatabase.STATUS,
// MmsSmsColumns.NORMALIZED_DATE_SENT, MmsSmsColumns.NORMALIZED_DATE_RECEIVED,
// MmsDatabase.MESSAGE_TYPE, MmsDatabase.MESSAGE_BOX, TRANSPORT,
// "COUNT(" + MmsSmsColumns.ID + ") AS " + GROUP_SIZE,
// mmsGroupSentCount + " AS " + MMS_GROUP_SENT_COUNT,
// mmsGroupSentFailedCount + " AS " + MMS_GROUP_SEND_FAILED_COUNT,
// smsGroupSentCount + " AS " + SMS_GROUP_SENT_COUNT,
// smsGroupSentFailedCount + " AS " + SMS_GROUP_SEND_FAILED_COUNT,
// smsCaseSecurity + " AS sms_collate", mmsCaseSecurity + " AS mms_collate"};
//
// String order = MmsSmsColumns.NORMALIZED_DATE_RECEIVED + " ASC";
// String selection = MmsSmsColumns.THREAD_ID + " = " + threadId;
// String groupBy = MmsSmsColumns.NORMALIZED_DATE_SENT + " / 1000, sms_collate, mms_collate";
//
// Cursor cursor = queryTables(projection, selection, order, groupBy, null);
// setNotifyConverationListeners(cursor, threadId);
//
// return cursor;
// }
public Cursor getConversation(long threadId) {
String[] projection = {MmsSmsColumns.ID, SmsDatabase.BODY, SmsDatabase.TYPE,
MmsSmsColumns.THREAD_ID,
@ -94,7 +46,10 @@ public class MmsSmsDatabase extends Database {
MmsSmsColumns.NORMALIZED_DATE_SENT,
MmsSmsColumns.NORMALIZED_DATE_RECEIVED,
MmsDatabase.MESSAGE_TYPE, MmsDatabase.MESSAGE_BOX,
SmsDatabase.STATUS, MmsDatabase.PART_COUNT, TRANSPORT};
SmsDatabase.STATUS, MmsDatabase.PART_COUNT,
MmsDatabase.CONTENT_LOCATION, MmsDatabase.TRANSACTION_ID,
MmsDatabase.MESSAGE_SIZE, MmsDatabase.EXPIRY,
MmsDatabase.STATUS, TRANSPORT};
String order = MmsSmsColumns.NORMALIZED_DATE_RECEIVED + " ASC";
@ -113,7 +68,11 @@ public class MmsSmsDatabase extends Database {
MmsSmsColumns.NORMALIZED_DATE_SENT,
MmsSmsColumns.NORMALIZED_DATE_RECEIVED,
MmsDatabase.MESSAGE_TYPE, MmsDatabase.MESSAGE_BOX,
SmsDatabase.STATUS, MmsDatabase.PART_COUNT, TRANSPORT};
SmsDatabase.STATUS, MmsDatabase.PART_COUNT,
MmsDatabase.CONTENT_LOCATION, MmsDatabase.TRANSACTION_ID,
MmsDatabase.MESSAGE_SIZE, MmsDatabase.EXPIRY,
MmsDatabase.STATUS, TRANSPORT};
String order = MmsSmsColumns.NORMALIZED_DATE_RECEIVED + " DESC";
String selection = MmsSmsColumns.THREAD_ID + " = " + threadId;
@ -127,7 +86,11 @@ public class MmsSmsDatabase extends Database {
MmsSmsColumns.NORMALIZED_DATE_SENT,
MmsSmsColumns.NORMALIZED_DATE_RECEIVED,
MmsDatabase.MESSAGE_TYPE, MmsDatabase.MESSAGE_BOX,
MmsDatabase.PART_COUNT, TRANSPORT};
MmsDatabase.PART_COUNT,
MmsDatabase.CONTENT_LOCATION, MmsDatabase.TRANSACTION_ID,
MmsDatabase.MESSAGE_SIZE, MmsDatabase.EXPIRY,
MmsDatabase.STATUS, TRANSPORT};
String order = MmsSmsColumns.NORMALIZED_DATE_RECEIVED + " ASC";
String selection = MmsSmsColumns.READ + " = 0";
@ -146,13 +109,19 @@ public class MmsSmsDatabase extends Database {
MmsDatabase.DATE_RECEIVED + " * 1000 AS " + MmsSmsColumns.NORMALIZED_DATE_RECEIVED,
MmsSmsColumns.ID, SmsDatabase.BODY, MmsSmsColumns.READ, MmsSmsColumns.THREAD_ID,
SmsDatabase.TYPE, SmsDatabase.ADDRESS, SmsDatabase.SUBJECT, MmsDatabase.MESSAGE_TYPE,
MmsDatabase.MESSAGE_BOX, SmsDatabase.STATUS, MmsDatabase.PART_COUNT, TRANSPORT};
MmsDatabase.MESSAGE_BOX, SmsDatabase.STATUS, MmsDatabase.PART_COUNT,
MmsDatabase.CONTENT_LOCATION, MmsDatabase.TRANSACTION_ID,
MmsDatabase.MESSAGE_SIZE, MmsDatabase.EXPIRY, MmsDatabase.STATUS,
TRANSPORT};
String[] smsProjection = {SmsDatabase.DATE_SENT + " * 1 AS " + MmsSmsColumns.NORMALIZED_DATE_SENT,
SmsDatabase.DATE_RECEIVED + " * 1 AS " + MmsSmsColumns.NORMALIZED_DATE_RECEIVED,
MmsSmsColumns.ID, SmsDatabase.BODY, MmsSmsColumns.READ, MmsSmsColumns.THREAD_ID,
SmsDatabase.TYPE, SmsDatabase.ADDRESS, SmsDatabase.SUBJECT, MmsDatabase.MESSAGE_TYPE,
MmsDatabase.MESSAGE_BOX, SmsDatabase.STATUS, MmsDatabase.PART_COUNT, TRANSPORT};
MmsDatabase.MESSAGE_BOX, SmsDatabase.STATUS, MmsDatabase.PART_COUNT,
MmsDatabase.CONTENT_LOCATION, MmsDatabase.TRANSACTION_ID,
MmsDatabase.MESSAGE_SIZE, MmsDatabase.EXPIRY, MmsDatabase.STATUS,
TRANSPORT};
SQLiteQueryBuilder mmsQueryBuilder = new SQLiteQueryBuilder();
@ -166,25 +135,31 @@ public class MmsSmsDatabase extends Database {
Set<String> mmsColumnsPresent = new HashSet<String>();
mmsColumnsPresent.add(MmsSmsColumns.ID);
mmsColumnsPresent.add(MmsSmsColumns.READ);
mmsColumnsPresent.add(MmsSmsColumns.THREAD_ID);
mmsColumnsPresent.add(MmsSmsColumns.BODY);
mmsColumnsPresent.add(MmsSmsColumns.ADDRESS);
mmsColumnsPresent.add(MmsDatabase.MESSAGE_TYPE);
mmsColumnsPresent.add(MmsDatabase.MESSAGE_BOX);
mmsColumnsPresent.add(MmsDatabase.DATE_SENT);
mmsColumnsPresent.add(MmsDatabase.DATE_RECEIVED);
mmsColumnsPresent.add(MmsSmsColumns.READ);
mmsColumnsPresent.add(MmsSmsColumns.THREAD_ID);
mmsColumnsPresent.add(MmsSmsColumns.BODY);
mmsColumnsPresent.add(MmsDatabase.PART_COUNT);
mmsColumnsPresent.add(MmsDatabase.CONTENT_LOCATION);
mmsColumnsPresent.add(MmsDatabase.TRANSACTION_ID);
mmsColumnsPresent.add(MmsDatabase.MESSAGE_SIZE);
mmsColumnsPresent.add(MmsDatabase.EXPIRY);
mmsColumnsPresent.add(MmsDatabase.STATUS);
Set<String> smsColumnsPresent = new HashSet<String>();
smsColumnsPresent.add(MmsSmsColumns.ID);
smsColumnsPresent.add(MmsSmsColumns.BODY);
smsColumnsPresent.add(MmsSmsColumns.ADDRESS);
smsColumnsPresent.add(MmsSmsColumns.READ);
smsColumnsPresent.add(MmsSmsColumns.THREAD_ID);
smsColumnsPresent.add(SmsDatabase.TYPE);
smsColumnsPresent.add(SmsDatabase.ADDRESS);
smsColumnsPresent.add(SmsDatabase.SUBJECT);
smsColumnsPresent.add(SmsDatabase.DATE_SENT);
smsColumnsPresent.add(SmsDatabase.DATE_RECEIVED);
smsColumnsPresent.add(MmsSmsColumns.READ);
smsColumnsPresent.add(MmsSmsColumns.THREAD_ID);
smsColumnsPresent.add(SmsDatabase.STATUS);
String mmsSubQuery = mmsQueryBuilder.buildUnionSubQuery(TRANSPORT, mmsProjection, mmsColumnsPresent, 2, MMS_TRANSPORT, selection, null, null, null);

View File

@ -52,7 +52,6 @@ import java.util.Set;
public class SmsDatabase extends Database implements MmsSmsColumns {
public static final String TABLE_NAME = "sms";
public static final String ADDRESS = "address";
public static final String PERSON = "person";
static final String DATE_RECEIVED = "date";
static final String DATE_SENT = "date_sent";
@ -61,7 +60,6 @@ public class SmsDatabase extends Database implements MmsSmsColumns {
public static final String TYPE = "type";
public static final String REPLY_PATH_PRESENT = "reply_path_present";
public static final String SUBJECT = "subject";
//public static final String BODY = "body";
public static final String SERVICE_CENTER = "service_center";
public static final String CREATE_TABLE = "CREATE TABLE " + TABLE_NAME + " (" + ID + " integer PRIMARY KEY, " +

View File

@ -75,7 +75,7 @@ public class MediaMmsMessageRecord extends MessageRecord {
return emphasisAdded(context.getString(R.string.MmsMessageRecord_bad_encrypted_mms_message));
} else if (MmsDatabase.Types.isNoRemoteSessionType(type)) {
return emphasisAdded(context.getString(R.string.MmsMessageRecord_mms_message_encrypted_for_non_existing_session));
} else if (getBody().isPlaintext()) {
} else if (!getBody().isPlaintext()) {
return emphasisAdded(context.getString(R.string.MessageNotifier_encrypted_message));
}

View File

@ -44,4 +44,21 @@ public class PartParser {
return stripped;
}
public static int getDisplayablePartCount(PduBody body) {
int partCount = 0;
for (int i=0;i<body.getPartsNum();i++) {
String contentType = Util.toIsoString(body.getPart(i).getContentType());
if (ContentType.isImageType(contentType) ||
ContentType.isAudioType(contentType) ||
ContentType.isVideoType(contentType))
{
partCount++;
}
}
return partCount;
}
}

View File

@ -165,16 +165,7 @@ public class MmsSender extends MmscProcessor {
throws MmsException
{
MmsDatabase database = DatabaseFactory.getMmsDatabase(context);
List<SendReq> sendRequests;
if (messageId == -1) {
sendRequests = Arrays.asList(database.getOutgoingMessages(masterSecret));
} else {
sendRequests = new ArrayList<SendReq>(1);
sendRequests.add(database.getSendRequest(masterSecret, messageId));
}
return sendRequests;
return Arrays.asList(database.getOutgoingMessages(masterSecret, messageId));
}
protected void handleConnectivityChange() {