diff --git a/src/com/android/email/activity/MessageView.java b/src/com/android/email/activity/MessageView.java index 52cac9919..8b866966b 100644 --- a/src/com/android/email/activity/MessageView.java +++ b/src/com/android/email/activity/MessageView.java @@ -1322,7 +1322,7 @@ public class MessageView extends Activity String text = MimeUtility.getTextFromPart(part); if (part.getMimeType().equalsIgnoreCase("text/html")) { text = EmailHtmlUtil.resolveInlineImage( - getContentResolver(), mAccount, text, mOldMessage, 0); + getContentResolver(), mAccount.mId, text, mOldMessage, 0); } else { // And also escape special character, such as "<>&", // to HTML escape sequence. diff --git a/src/com/android/email/mail/internet/EmailHtmlUtil.java b/src/com/android/email/mail/internet/EmailHtmlUtil.java index 8e1030ec0..255931790 100755 --- a/src/com/android/email/mail/internet/EmailHtmlUtil.java +++ b/src/com/android/email/mail/internet/EmailHtmlUtil.java @@ -48,7 +48,7 @@ public class EmailHtmlUtil { * @return html text in which src attribute of img tag may be replaced with content uri */ public static String resolveInlineImage( - ContentResolver resolver, EmailContent.Account account, String text, Part part, int depth) + ContentResolver resolver, long accountId, String text, Part part, int depth) throws MessagingException { // avoid too deep recursive call. if (depth >= 10 || text == null) { @@ -60,8 +60,10 @@ public class EmailHtmlUtil { contentId != null && part instanceof LocalAttachmentBodyPart) { LocalAttachmentBodyPart attachment = (LocalAttachmentBodyPart)part; - Uri contentUri = AttachmentProvider.resolveAttachmentIdToContentUri( - resolver, AttachmentProvider.getAttachmentUri(account, attachment.getAttachmentId())); + Uri attachmentUri = + AttachmentProvider.getAttachmentUri(accountId, attachment.getAttachmentId()); + Uri contentUri = + AttachmentProvider.resolveAttachmentIdToContentUri(resolver, attachmentUri); // Regexp which matches ' src="cid:contentId"'. String contentIdRe = "\\s+(?i)src=\"cid(?-i):\\Q" + contentId + "\\E\""; // Replace all occurrences of src attribute with ' src="content://contentUri"'. @@ -71,7 +73,7 @@ public class EmailHtmlUtil { if (part.getBody() instanceof Multipart) { Multipart mp = (Multipart)part.getBody(); for (int i = 0; i < mp.getCount(); i++) { - text = resolveInlineImage(resolver, account, text, mp.getBodyPart(i), depth + 1); + text = resolveInlineImage(resolver, accountId, text, mp.getBodyPart(i), depth + 1); } } diff --git a/src/com/android/email/mail/store/LocalStore.java b/src/com/android/email/mail/store/LocalStore.java index 43a8d6790..21c08f409 100644 --- a/src/com/android/email/mail/store/LocalStore.java +++ b/src/com/android/email/mail/store/LocalStore.java @@ -1375,9 +1375,10 @@ public class LocalStore extends Store implements PersistentDataCallbacks { if (tempAttachmentFile != null) { File attachmentFile = new File(mAttachmentsDir, Long.toString(attachmentId)); tempAttachmentFile.renameTo(attachmentFile); - contentUri = AttachmentProvider.getAttachmentUri( - new File(mPath).getName(), - attachmentId); + // Doing this requires knowing the account id +// contentUri = AttachmentProvider.getAttachmentUri( +// new File(mPath).getName(), +// attachmentId); attachment.setBody(new LocalAttachmentBody(contentUri, mContext)); ContentValues cv = new ContentValues(); cv.put("content_uri", contentUri != null ? contentUri.toString() : null); diff --git a/src/com/android/email/provider/AttachmentProvider.java b/src/com/android/email/provider/AttachmentProvider.java index 51df37a83..f1ac26b36 100644 --- a/src/com/android/email/provider/AttachmentProvider.java +++ b/src/com/android/email/provider/AttachmentProvider.java @@ -17,13 +17,15 @@ package com.android.email.provider; import com.android.email.mail.internet.MimeUtility; +import com.android.email.provider.EmailContent.Attachment; +import com.android.email.provider.EmailContent.AttachmentColumns; import android.content.ContentProvider; import android.content.ContentResolver; +import android.content.ContentUris; import android.content.ContentValues; import android.database.Cursor; import android.database.MatrixCursor; -import android.database.sqlite.SQLiteDatabase; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.net.Uri; @@ -38,6 +40,12 @@ import java.util.List; /* * A simple ContentProvider that allows file access to Email's attachments. + * + * The URI scheme is as follows. For raw file access: + * content://com.android.email.attachmentprovider/acct#/attach#/RAW + * + * And for access to thumbnails: + * content://com.android.email.attachmentprovider/acct#/attach#/THUMBNAIL/width#/height# */ public class AttachmentProvider extends ContentProvider { @@ -54,9 +62,13 @@ public class AttachmentProvider extends ContentProvider { public static final String SIZE = "_size"; } - public static Uri getAttachmentUri(EmailContent.Account account, long id) { + private String[] PROJECTION_MIME_TYPE = new String[] { AttachmentColumns.MIME_TYPE }; + private String[] PROJECTION_QUERY = new String[] { AttachmentColumns.FILENAME, + AttachmentColumns.SIZE, AttachmentColumns.CONTENT_URI }; + + public static Uri getAttachmentUri(long accountId, long id) { return CONTENT_URI.buildUpon() - .appendPath(account.getUuid() + ".db") + .appendPath(Long.toString(accountId)) .appendPath(Long.toString(id)) .appendPath(FORMAT_RAW) .build(); @@ -65,7 +77,7 @@ public class AttachmentProvider extends ContentProvider { public static Uri getAttachmentThumbnailUri(EmailContent.Account account, long id, int width, int height) { return CONTENT_URI.buildUpon() - .appendPath(account.getUuid() + ".db") + .appendPath(Long.toString(account.mId)) .appendPath(Long.toString(id)) .appendPath(FORMAT_THUMBNAIL) .appendPath(Integer.toString(width)) @@ -73,14 +85,6 @@ public class AttachmentProvider extends ContentProvider { .build(); } - public static Uri getAttachmentUri(String db, long id) { - return CONTENT_URI.buildUpon() - .appendPath(db) - .appendPath(Long.toString(id)) - .appendPath(FORMAT_RAW) - .build(); - } - @Override public boolean onCreate() { /* @@ -106,42 +110,23 @@ public class AttachmentProvider extends ContentProvider { @Override public String getType(Uri uri) { List segments = uri.getPathSegments(); - String dbName = segments.get(0); + String accountId = segments.get(0); String id = segments.get(1); String format = segments.get(2); if (FORMAT_THUMBNAIL.equals(format)) { return "image/png"; - } - else { - String path = getContext().getDatabasePath(dbName).getAbsolutePath(); - SQLiteDatabase db = null; - Cursor cursor = null; + } else { + uri = ContentUris.withAppendedId(Attachment.CONTENT_URI, Long.parseLong(id)); + Cursor c = getContext().getContentResolver().query(uri, PROJECTION_MIME_TYPE, + null, null, null); try { - db = SQLiteDatabase.openDatabase(path, null, 0); - cursor = db.query( - "attachments", - new String[] { "mime_type" }, - "id = ?", - new String[] { id }, - null, - null, - null); - cursor.moveToFirst(); - String type = cursor.getString(0); - cursor.close(); - db.close(); - return type; - - } - finally { - if (cursor != null) { - cursor.close(); + if (c.moveToFirst()) { + return c.getString(0); } - if (db != null) { - db.close(); - } - + } finally { + c.close(); } + return null; } } @@ -159,23 +144,25 @@ public class AttachmentProvider extends ContentProvider { @Override public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException { List segments = uri.getPathSegments(); - String dbName = segments.get(0); + String accountId = segments.get(0); String id = segments.get(1); String format = segments.get(2); if (FORMAT_THUMBNAIL.equals(format)) { int width = Integer.parseInt(segments.get(3)); int height = Integer.parseInt(segments.get(4)); - String filename = "thmb_" + dbName + "_" + id; + String filename = "thmb_" + accountId + "_" + id; File dir = getContext().getCacheDir(); File file = new File(dir, filename); if (!file.exists()) { - Uri attachmentUri = getAttachmentUri(dbName, Long.parseLong(id)); + Uri attachmentUri = getAttachmentUri(Long.parseLong(accountId), Long.parseLong(id)); Cursor c = query(attachmentUri, new String[] { AttachmentProviderColumns.DATA }, null, null, null); if (c != null) { try { if (c.moveToFirst()) { attachmentUri = Uri.parse(c.getString(0)); + } else { + return null; } } finally { c.close(); @@ -200,7 +187,7 @@ public class AttachmentProvider extends ContentProvider { } else { return ParcelFileDescriptor.open( - new File(getContext().getDatabasePath(dbName + "_att"), id), + new File(getContext().getDatabasePath(accountId + ".db_att"), id), ParcelFileDescriptor.MODE_READ_ONLY); } } @@ -221,9 +208,6 @@ public class AttachmentProvider extends ContentProvider { * * Supports REST Uri only, for a single row - selection, selection args, and sortOrder are * ignored (non-null values should probably throw an exception....) - * - * TODO: Throws an SQLite exception on a missing DB file (e.g. unknown URI) instead of just - * returning null, as it should. */ @Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, @@ -237,39 +221,26 @@ public class AttachmentProvider extends ContentProvider { } List segments = uri.getPathSegments(); - String dbName = segments.get(0); + String accountId = segments.get(0); String id = segments.get(1); String format = segments.get(2); - String path = getContext().getDatabasePath(dbName).getAbsolutePath(); String name = null; int size = -1; String contentUri = null; - SQLiteDatabase db = null; - Cursor cursor = null; + + uri = ContentUris.withAppendedId(Attachment.CONTENT_URI, Long.parseLong(id)); + Cursor c = getContext().getContentResolver().query(uri, PROJECTION_QUERY, + null, null, null); try { - db = SQLiteDatabase.openDatabase(path, null, 0); - cursor = db.query( - "attachments", - new String[] { "name", "size", "content_uri" }, - "id = ?", - new String[] { id }, - null, - null, - null); - if (!cursor.moveToFirst()) { + if (c.moveToFirst()) { + name = c.getString(0); + size = c.getInt(1); + contentUri = c.getString(2); + } else { return null; } - name = cursor.getString(0); - size = cursor.getInt(1); - contentUri = cursor.getString(2); - } - finally { - if (cursor != null) { - cursor.close(); - } - if (db != null) { - db.close(); - } + } finally { + c.close(); } MatrixCursor ret = new MatrixCursor(projection); diff --git a/tests/src/com/android/email/mail/MessageTestUtils.java b/tests/src/com/android/email/mail/MessageTestUtils.java index 21c18fd0c..6594c46b1 100644 --- a/tests/src/com/android/email/mail/MessageTestUtils.java +++ b/tests/src/com/android/email/mail/MessageTestUtils.java @@ -66,7 +66,7 @@ public class MessageTestUtils { * @return AttachmentProvider content URI */ public static Uri contentUri(long attachmentId, EmailContent.Account account) { - return AttachmentProvider.getAttachmentUri(account, attachmentId); + return AttachmentProvider.getAttachmentUri(account.mId, attachmentId); } /** diff --git a/tests/src/com/android/email/mail/internet/EmailHtmlUtilTest.java b/tests/src/com/android/email/mail/internet/EmailHtmlUtilTest.java index 6dc5733a5..ffa6a3344 100755 --- a/tests/src/com/android/email/mail/internet/EmailHtmlUtilTest.java +++ b/tests/src/com/android/email/mail/internet/EmailHtmlUtilTest.java @@ -32,6 +32,12 @@ import android.test.suitebuilder.annotation.MediumTest; import java.io.IOException; +/** + * Tests of the Email HTML utils. + * + * You can run this entire test case with: + * runtest -c com.android.email.mail.internet.EmailHtmlUtilTest email + */ @MediumTest public class EmailHtmlUtilTest extends AndroidTestCase { private EmailContent.Account mAccount; @@ -74,13 +80,13 @@ public class EmailHtmlUtilTest extends AndroidTestCase { .build(); // Simple case. final String actual1 = EmailHtmlUtil.resolveInlineImage( - getContext().getContentResolver(), mAccount, text1, msg1, 0); + getContext().getContentResolver(), mAccount.mId, text1, msg1, 0); assertEquals("one content id reference is not resolved", expected1, actual1); // Exceed recursive limit. final String actual0 = EmailHtmlUtil.resolveInlineImage( - getContext().getContentResolver(), mAccount, text1, msg1, 10); + getContext().getContentResolver(), mAccount.mId, text1, msg1, 10); assertEquals("recursive call limit may exceeded", text1, actual0); @@ -100,7 +106,7 @@ public class EmailHtmlUtilTest extends AndroidTestCase { .build(); // cid1 is not replaced final String actual2 = EmailHtmlUtil.resolveInlineImage( - getContext().getContentResolver(), mAccount, text1 + text2, msg2, 0); + getContext().getContentResolver(), mAccount.mId, text1 + text2, msg2, 0); assertEquals("only one of two content id is resolved", text1 + expected2, actual2); @@ -114,7 +120,7 @@ public class EmailHtmlUtilTest extends AndroidTestCase { .build(); // cid1 and cid2 are replaced final String actual3 = EmailHtmlUtil.resolveInlineImage( - getContext().getContentResolver(), mAccount, text2 + text1, msg3, 0); + getContext().getContentResolver(), mAccount.mId, text2 + text1, msg3, 0); assertEquals("two content ids are resolved correctly", expected2 + expected1, actual3); @@ -133,13 +139,13 @@ public class EmailHtmlUtilTest extends AndroidTestCase { .build(); // cid1 and cid2 are replaced final String actual4 = EmailHtmlUtil.resolveInlineImage( - getContext().getContentResolver(), mAccount, text2 + text1, msg4, 0); + getContext().getContentResolver(), mAccount.mId, text2 + text1, msg4, 0); assertEquals("two content ids in deep multipart level are resolved", expected2 + expected1, actual4); // No crash on null text final String actual5 = EmailHtmlUtil.resolveInlineImage(getContext().getContentResolver(), - mAccount, null, msg4, 0); + mAccount.mId, null, msg4, 0); assertNull(actual5); } diff --git a/tests/src/com/android/email/provider/AttachmentProviderTests.java b/tests/src/com/android/email/provider/AttachmentProviderTests.java index 6566e70c8..1bbf2e46c 100644 --- a/tests/src/com/android/email/provider/AttachmentProviderTests.java +++ b/tests/src/com/android/email/provider/AttachmentProviderTests.java @@ -29,7 +29,6 @@ import android.content.Context; import android.content.res.AssetFileDescriptor; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; -import android.database.sqlite.SQLiteException; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.net.Uri; @@ -54,7 +53,7 @@ public class AttachmentProviderTests extends ProviderTestCase2