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:
Andrew Stadler 2009-07-16 16:03:40 -07:00
parent d4c18546fb
commit 4119218e2f
4 changed files with 148 additions and 30 deletions

View File

@ -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;

View File

@ -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);

View File

@ -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);
}
}

View File

@ -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();
}
}
}