Add support for get-attachments-by-message-id
* clean up provider URI's in this area * minor bugfix in EmailContent, and add auto-writeback of messageId into saved attachments * clean up existing attachment unit tests * add new tests
This commit is contained in:
parent
d4c18546fb
commit
4119218e2f
|
@ -605,7 +605,8 @@ public abstract class EmailContent {
|
|||
// This logic is in place so I can (a) short circuit the expensive stuff when
|
||||
// possible, and (b) override (and throw) if anyone tries to call save() or update()
|
||||
// directly for Message, which are unsupported.
|
||||
if (mText == null && mHtml == null) {
|
||||
if (mText == null && mHtml == null &&
|
||||
(mAttachments == null || mAttachments.isEmpty())) {
|
||||
if (doSave) {
|
||||
return super.save(context);
|
||||
} else {
|
||||
|
@ -626,6 +627,11 @@ public abstract class EmailContent {
|
|||
if (doSave) {
|
||||
Uri u = results[0].uri;
|
||||
mId = Long.parseLong(u.getPathSegments().get(1));
|
||||
if (mAttachments != null) {
|
||||
for (Attachment a : mAttachments) {
|
||||
a.mMessageKey = mId;
|
||||
}
|
||||
}
|
||||
return u;
|
||||
} else {
|
||||
return null;
|
||||
|
@ -1440,7 +1446,9 @@ public abstract class EmailContent {
|
|||
public static final class Attachment extends EmailContent implements AttachmentColumns {
|
||||
public static final String TABLE_NAME = "Attachment";
|
||||
public static final Uri CONTENT_URI = Uri.parse(EmailContent.CONTENT_URI + "/attachment");
|
||||
|
||||
// This must be used with an appended id: ContentUris.withAppendedId(MESSAGE_ID_URI, id)
|
||||
public static final Uri MESSAGE_ID_URI = Uri.parse(
|
||||
EmailContent.CONTENT_URI + "/attachment/message");
|
||||
|
||||
public String mFileName;
|
||||
public String mMimeType;
|
||||
|
|
|
@ -76,14 +76,14 @@ public class EmailProvider extends ContentProvider {
|
|||
|
||||
private static final int MESSAGE_BASE = 0x2000;
|
||||
private static final int MESSAGE = MESSAGE_BASE;
|
||||
private static final int MESSAGE_ATTACHMENTS = MESSAGE_BASE + 1;
|
||||
private static final int MESSAGE_ID = MESSAGE_BASE + 2;
|
||||
private static final int SYNCED_MESSAGE_ID = MESSAGE_BASE + 3;
|
||||
private static final int MESSAGE_ID = MESSAGE_BASE + 1;
|
||||
private static final int SYNCED_MESSAGE_ID = MESSAGE_BASE + 2;
|
||||
|
||||
private static final int ATTACHMENT_BASE = 0x3000;
|
||||
private static final int ATTACHMENT = ATTACHMENT_BASE;
|
||||
private static final int ATTACHMENT_CONTENT = ATTACHMENT_BASE + 1;
|
||||
private static final int ATTACHMENT_ID = ATTACHMENT_BASE + 2;
|
||||
private static final int ATTACHMENTS_MESSAGE_ID = ATTACHMENT_BASE + 3;
|
||||
|
||||
private static final int HOSTAUTH_BASE = 0x4000;
|
||||
private static final int HOSTAUTH = HOSTAUTH_BASE;
|
||||
|
@ -174,8 +174,6 @@ public class EmailProvider extends ContentProvider {
|
|||
// A specific message
|
||||
// insert into this URI causes an attachment to be added to the message
|
||||
matcher.addURI(EMAIL_AUTHORITY, "message/#", MESSAGE_ID);
|
||||
// The attachments of a specific message
|
||||
matcher.addURI(EMAIL_AUTHORITY, "message/#/attachment", MESSAGE_ATTACHMENTS);
|
||||
|
||||
// A specific attachment
|
||||
matcher.addURI(EMAIL_AUTHORITY, "attachment", ATTACHMENT);
|
||||
|
@ -184,6 +182,8 @@ public class EmailProvider extends ContentProvider {
|
|||
// The content for a specific attachment
|
||||
// NOT IMPLEMENTED
|
||||
matcher.addURI(EMAIL_AUTHORITY, "attachment/content/*", ATTACHMENT_CONTENT);
|
||||
// The attachments of a specific message (query only) (insert & delete TBD)
|
||||
matcher.addURI(EMAIL_AUTHORITY, "attachment/message/#", ATTACHMENTS_MESSAGE_ID);
|
||||
|
||||
// All mail bodies
|
||||
matcher.addURI(EMAIL_AUTHORITY, "body", BODY);
|
||||
|
@ -196,10 +196,10 @@ public class EmailProvider extends ContentProvider {
|
|||
// The plain text part of a specific mail body
|
||||
matcher.addURI(EMAIL_AUTHORITY, "body/#/text", BODY_TEXT);
|
||||
|
||||
// A specific attachment
|
||||
matcher.addURI(EMAIL_AUTHORITY, "hostauth", HOSTAUTH); // IMPLEMENTED
|
||||
// A specific attachment (the header information)
|
||||
matcher.addURI(EMAIL_AUTHORITY, "hostauth/#", HOSTAUTH_ID); // IMPLEMENTED
|
||||
// All hostauth records
|
||||
matcher.addURI(EMAIL_AUTHORITY, "hostauth", HOSTAUTH);
|
||||
// A specific hostauth
|
||||
matcher.addURI(EMAIL_AUTHORITY, "hostauth/#", HOSTAUTH_ID);
|
||||
|
||||
/**
|
||||
* THIS URI HAS SPECIAL SEMANTICS
|
||||
|
@ -646,7 +646,7 @@ public class EmailProvider extends ContentProvider {
|
|||
return "vnd.android.cursor.dir/email-account";
|
||||
case ACCOUNT_ID:
|
||||
return "vnd.android.cursor.item/email-account";
|
||||
case MESSAGE_ATTACHMENTS:
|
||||
case ATTACHMENTS_MESSAGE_ID:
|
||||
case ATTACHMENT:
|
||||
return "vnd.android.cursor.dir/email-attachment";
|
||||
case ATTACHMENT_ID:
|
||||
|
@ -708,7 +708,7 @@ public class EmailProvider extends ContentProvider {
|
|||
values.put(MailboxColumns.ACCOUNT_KEY, id);
|
||||
resultUri = insert(Mailbox.CONTENT_URI, values);
|
||||
break;
|
||||
case MESSAGE_ATTACHMENTS:
|
||||
case ATTACHMENTS_MESSAGE_ID:
|
||||
id = db.insert(TABLE_NAMES[table], "foo", values);
|
||||
resultUri = ContentUris.withAppendedId(Attachment.CONTENT_URI, id);
|
||||
break;
|
||||
|
@ -766,9 +766,9 @@ public class EmailProvider extends ContentProvider {
|
|||
c = db.query(TABLE_NAMES[table], projection,
|
||||
whereWithId(id, selection), selectionArgs, null, null, sortOrder);
|
||||
break;
|
||||
case MESSAGE_ATTACHMENTS:
|
||||
case ATTACHMENTS_MESSAGE_ID:
|
||||
// All attachments for the given message
|
||||
id = uri.getPathSegments().get(1);
|
||||
id = uri.getPathSegments().get(2);
|
||||
c = db.query(Attachment.TABLE_NAME, projection,
|
||||
whereWith(Attachment.MESSAGE_KEY + "=" + id, selection),
|
||||
selectionArgs, null, null, sortOrder);
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
package com.android.email.provider;
|
||||
|
||||
import com.android.email.provider.EmailContent.Account;
|
||||
import com.android.email.provider.EmailContent.Attachment;
|
||||
import com.android.email.provider.EmailContent.Mailbox;
|
||||
import com.android.email.provider.EmailContent.Message;
|
||||
|
||||
|
@ -138,6 +139,33 @@ public class ProviderTestUtils extends Assert {
|
|||
return message;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a test attachment. A few fields are specified by params, and all other fields
|
||||
* are generated using pseudo-unique values.
|
||||
*
|
||||
* @param messageId the message to attach to
|
||||
* @param fileName the "file" to indicate in the attachment
|
||||
* @param length the "length" of the attachment
|
||||
* @param saveIt if true, write the new attachment directly to the DB
|
||||
* @param context use this context
|
||||
*/
|
||||
public static Attachment setupAttachment(long messageId, String fileName, long length,
|
||||
boolean saveIt, Context context) {
|
||||
Attachment att = new Attachment();
|
||||
att.mSize = length;
|
||||
att.mFileName = fileName;
|
||||
att.mContentId = "contentId " + fileName;
|
||||
att.mContentUri = "contentUri " + fileName;
|
||||
att.mMessageKey = messageId;
|
||||
att.mMimeType = "mimeType " + fileName;
|
||||
att.mLocation = "location " + fileName;
|
||||
att.mEncoding = "encoding " + fileName;
|
||||
if (saveIt) {
|
||||
att.saveOrUpdate(context);
|
||||
}
|
||||
return att;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare two accounts for equality
|
||||
*
|
||||
|
@ -236,4 +264,24 @@ public class ProviderTestUtils extends Assert {
|
|||
assertEquals(caller + " mText", expect.mText, actual.mText);
|
||||
assertEquals(caller + " mHtml", expect.mHtml, actual.mHtml);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare to attachments for equality
|
||||
*
|
||||
* TODO: file / content URI mapping? Compare the actual files?
|
||||
*/
|
||||
public static void assertAttachmentEqual(String caller, Attachment expect, Attachment actual) {
|
||||
if (expect == actual) {
|
||||
return;
|
||||
}
|
||||
|
||||
assertEquals(caller + " mSize", expect.mSize, actual.mSize);
|
||||
assertEquals(caller + " mFileName", expect.mFileName, actual.mFileName);
|
||||
assertEquals(caller + " mContentId", expect.mContentId, actual.mContentId);
|
||||
assertEquals(caller + " mContentUri", expect.mContentUri, actual.mContentUri);
|
||||
assertEquals(caller + " mMessageKey", expect.mMessageKey, actual.mMessageKey);
|
||||
assertEquals(caller + " mMimeType", expect.mMimeType, actual.mMimeType);
|
||||
assertEquals(caller + " mLocation", expect.mLocation, actual.mLocation);
|
||||
assertEquals(caller + " mEncoding", expect.mEncoding, actual.mEncoding);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -94,18 +94,10 @@ public class ProviderTests extends ProviderTestCase2<EmailProvider> {
|
|||
ProviderTestUtils.assertMailboxEqual("testMailboxSave", box1, box2);
|
||||
}
|
||||
|
||||
private static Attachment setupAttachment(String fileName, long length) {
|
||||
Attachment att = new Attachment();
|
||||
att.mFileName = fileName;
|
||||
att.mLocation = "location" + length;
|
||||
att.mSize = length;
|
||||
return att;
|
||||
}
|
||||
|
||||
public static String[] expectedAttachmentNames =
|
||||
private static String[] expectedAttachmentNames =
|
||||
new String[] {"attachment1.doc", "attachment2.xls", "attachment3"};
|
||||
// The lengths need to be kept in ascending order
|
||||
public static long[] expectedAttachmentSizes = new long[] {31415L, 97701L, 151213L};
|
||||
private static long[] expectedAttachmentSizes = new long[] {31415L, 97701L, 151213L};
|
||||
|
||||
/**
|
||||
* Test simple message save/retrieve
|
||||
|
@ -159,11 +151,14 @@ public class ProviderTests extends ProviderTestCase2<EmailProvider> {
|
|||
c.close();
|
||||
}
|
||||
|
||||
// Message with attachments and body
|
||||
Message message3 = ProviderTestUtils.setupMessage("message3", account1Id, box1Id, true,
|
||||
false, mMockContext);
|
||||
ArrayList<Attachment> atts = new ArrayList<Attachment>();
|
||||
for (int i = 0; i < 3; i++) {
|
||||
atts.add(setupAttachment(expectedAttachmentNames[i], expectedAttachmentSizes[i]));
|
||||
atts.add(ProviderTestUtils.setupAttachment(
|
||||
-1, expectedAttachmentNames[i], expectedAttachmentSizes[i],
|
||||
false, mMockContext));
|
||||
}
|
||||
message3.mAttachments = atts;
|
||||
message3.saveOrUpdate(mMockContext);
|
||||
|
@ -187,10 +182,47 @@ public class ProviderTests extends ProviderTestCase2<EmailProvider> {
|
|||
assertEquals(3, numAtts);
|
||||
int i = 0;
|
||||
while (c.moveToNext()) {
|
||||
assertEquals(expectedAttachmentNames[i],
|
||||
c.getString(Attachment.CONTENT_FILENAME_COLUMN));
|
||||
assertEquals(expectedAttachmentSizes[i],
|
||||
c.getLong(Attachment.CONTENT_SIZE_COLUMN));
|
||||
Attachment actual = EmailContent.getContent(c, Attachment.class);
|
||||
ProviderTestUtils.assertAttachmentEqual("save-message3", atts.get(i), actual);
|
||||
i++;
|
||||
}
|
||||
} finally {
|
||||
c.close();
|
||||
}
|
||||
|
||||
// Message with attachments but no body
|
||||
Message message4 = ProviderTestUtils.setupMessage("message4", account1Id, box1Id, false,
|
||||
false, mMockContext);
|
||||
atts = new ArrayList<Attachment>();
|
||||
for (int i = 0; i < 3; i++) {
|
||||
atts.add(ProviderTestUtils.setupAttachment(
|
||||
-1, expectedAttachmentNames[i], expectedAttachmentSizes[i],
|
||||
false, mMockContext));
|
||||
}
|
||||
message4.mAttachments = atts;
|
||||
message4.saveOrUpdate(mMockContext);
|
||||
long message4Id = message4.mId;
|
||||
|
||||
// Now check the attachments; there should be three and they should match name and size
|
||||
c = null;
|
||||
try {
|
||||
// Note that there is NO guarantee of the order of returned records in the general case,
|
||||
// so we specifically ask for ordering by size. The expectedAttachmentSizes array must
|
||||
// be kept sorted by size (ascending) for this test to work properly
|
||||
c = mMockContext.getContentResolver().query(
|
||||
Attachment.CONTENT_URI,
|
||||
Attachment.CONTENT_PROJECTION,
|
||||
Attachment.MESSAGE_KEY + "=?",
|
||||
new String[] {
|
||||
String.valueOf(message4Id)
|
||||
},
|
||||
Attachment.SIZE);
|
||||
int numAtts = c.getCount();
|
||||
assertEquals(3, numAtts);
|
||||
int i = 0;
|
||||
while (c.moveToNext()) {
|
||||
Attachment actual = EmailContent.getContent(c, Attachment.class);
|
||||
ProviderTestUtils.assertAttachmentEqual("save-message4", atts.get(i), actual);
|
||||
i++;
|
||||
}
|
||||
} finally {
|
||||
|
@ -587,4 +619,34 @@ public class ProviderTests extends ProviderTestCase2<EmailProvider> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test retrieving attachments by message ID (using EmailContent.Attachment.MESSAGE_ID_URI)
|
||||
*/
|
||||
public void testGetAttachmentByMessageIdUri() {
|
||||
|
||||
// Note, we don't strictly need accounts, mailboxes or messages to run this test.
|
||||
Attachment a1 = ProviderTestUtils.setupAttachment(1, "a1", 100, true, mMockContext);
|
||||
Attachment a2 = ProviderTestUtils.setupAttachment(1, "a2", 200, true, mMockContext);
|
||||
Attachment a3 = ProviderTestUtils.setupAttachment(2, "a3", 300, true, mMockContext);
|
||||
Attachment a4 = ProviderTestUtils.setupAttachment(2, "a4", 400, true, mMockContext);
|
||||
|
||||
// Now ask for the attachments of message id=1
|
||||
// Note: Using the "sort by size" trick to bring them back in expected order
|
||||
Uri uri = ContentUris.withAppendedId(Attachment.MESSAGE_ID_URI, 1);
|
||||
Cursor c = mMockContext.getContentResolver().query(uri, Attachment.CONTENT_PROJECTION,
|
||||
null, null, Attachment.SIZE);
|
||||
assertEquals(2, c.getCount());
|
||||
|
||||
try {
|
||||
c.moveToFirst();
|
||||
Attachment a1Get = EmailContent.getContent(c, Attachment.class);
|
||||
ProviderTestUtils.assertAttachmentEqual("getAttachByUri-1", a1, a1Get);
|
||||
c.moveToNext();
|
||||
Attachment a2Get = EmailContent.getContent(c, Attachment.class);
|
||||
ProviderTestUtils.assertAttachmentEqual("getAttachByUri-2", a2, a2Get);
|
||||
} finally {
|
||||
c.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue