am fbde900c
: Merge branch \'readonly-p4-donut\' into donut
Merge commit 'fbde900c37ae76ec3c6181b3328d4ddf7c46cc7e' * commit 'fbde900c37ae76ec3c6181b3328d4ddf7c46cc7e': AI 149442: Integrate CL#140625 (Fix attachment uri and content uri confusion) from imode to donut. AI 149328: Add extended header support to MimeMessage, MimeBodyPart, and LocalStore.
This commit is contained in:
commit
4c27102aea
@ -714,6 +714,29 @@ public class MessageView extends Activity
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve attachment id to content URI.
|
||||
*
|
||||
* @param attachmentUri
|
||||
* @return resolved content URI
|
||||
*/
|
||||
private Uri resolveAttachmentIdToContentUri(long attachmentId) {
|
||||
Uri attachmentUri = AttachmentProvider.getAttachmentUri(mAccount, attachmentId);
|
||||
Cursor c = getContentResolver().query(attachmentUri,
|
||||
new String[] { AttachmentProvider.AttachmentProviderColumns.DATA },
|
||||
null, null, null);
|
||||
if (c != null) {
|
||||
try {
|
||||
if (c.moveToFirst()) {
|
||||
return Uri.parse(c.getString(0));
|
||||
}
|
||||
} finally {
|
||||
c.close();
|
||||
}
|
||||
}
|
||||
return attachmentUri;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve content-id reference in src attribute of img tag to AttachmentProvider's
|
||||
* content uri. This method calls itself recursively at most the number of
|
||||
@ -737,15 +760,11 @@ public class MessageView extends Activity
|
||||
contentId != null &&
|
||||
part instanceof LocalAttachmentBodyPart) {
|
||||
LocalAttachmentBodyPart attachment = (LocalAttachmentBodyPart)part;
|
||||
Uri contentUri = AttachmentProvider.getAttachmentUri(
|
||||
mAccount,
|
||||
attachment.getAttachmentId());
|
||||
if (contentUri != null) {
|
||||
// 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"'.
|
||||
text = text.replaceAll(contentIdRe, " src=\"" + contentUri + "\"");
|
||||
}
|
||||
Uri contentUri = resolveAttachmentIdToContentUri(attachment.getAttachmentId());
|
||||
// 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"'.
|
||||
text = text.replaceAll(contentIdRe, " src=\"" + contentUri + "\"");
|
||||
}
|
||||
|
||||
if (part.getBody() instanceof Multipart) {
|
||||
@ -1047,9 +1066,7 @@ public class MessageView extends Activity
|
||||
try {
|
||||
File file = createUniqueFile(Environment.getExternalStorageDirectory(),
|
||||
attachment.name);
|
||||
Uri uri = AttachmentProvider.getAttachmentUri(
|
||||
mAccount,
|
||||
attachment.part.getAttachmentId());
|
||||
Uri uri = resolveAttachmentIdToContentUri(attachment.part.getAttachmentId());
|
||||
InputStream in = getContentResolver().openInputStream(uri);
|
||||
OutputStream out = new FileOutputStream(file);
|
||||
IOUtils.copy(in, out);
|
||||
@ -1065,9 +1082,7 @@ public class MessageView extends Activity
|
||||
}
|
||||
else {
|
||||
try {
|
||||
Uri uri = AttachmentProvider.getAttachmentUri(
|
||||
mAccount,
|
||||
attachment.part.getAttachmentId());
|
||||
Uri uri = resolveAttachmentIdToContentUri(attachment.part.getAttachmentId());
|
||||
Intent intent = new Intent(Intent.ACTION_VIEW);
|
||||
intent.setData(uri);
|
||||
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
||||
|
@ -36,6 +36,10 @@ public interface Part {
|
||||
|
||||
public String[] getHeader(String name) throws MessagingException;
|
||||
|
||||
public void setExtendedHeader(String name, String value) throws MessagingException;
|
||||
|
||||
public String getExtendedHeader(String name) throws MessagingException;
|
||||
|
||||
public int getSize() throws MessagingException;
|
||||
|
||||
public boolean isMimeType(String mimeType) throws MessagingException;
|
||||
|
@ -32,11 +32,14 @@ import com.android.email.mail.MessagingException;
|
||||
*/
|
||||
public class MimeBodyPart extends BodyPart {
|
||||
protected MimeHeader mHeader = new MimeHeader();
|
||||
protected MimeHeader mExtendedHeader;
|
||||
protected Body mBody;
|
||||
protected int mSize;
|
||||
|
||||
// regex that matches content id surrounded by "<>" optionally.
|
||||
private static final Pattern REMOVE_OPTIONAL_BRACKETS = Pattern.compile("^<?([^>]+)>?$");
|
||||
// regex that matches end of line.
|
||||
private static final Pattern END_OF_LINE = Pattern.compile("\r?\n");
|
||||
|
||||
public MimeBodyPart() throws MessagingException {
|
||||
this(null);
|
||||
@ -135,6 +138,41 @@ public class MimeBodyPart extends BodyPart {
|
||||
return mSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set extended header
|
||||
*
|
||||
* @param name Extended header name
|
||||
* @param value header value - flattened by removing CR-NL if any
|
||||
* remove header if value is null
|
||||
* @throws MessagingException
|
||||
*/
|
||||
public void setExtendedHeader(String name, String value) throws MessagingException {
|
||||
if (value == null) {
|
||||
if (mExtendedHeader != null) {
|
||||
mExtendedHeader.removeHeader(name);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (mExtendedHeader == null) {
|
||||
mExtendedHeader = new MimeHeader();
|
||||
}
|
||||
mExtendedHeader.setHeader(name, END_OF_LINE.matcher(value).replaceAll(""));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get extended header
|
||||
*
|
||||
* @param name Extended header name
|
||||
* @return header value - null if header does not exist
|
||||
* @throws MessagingException
|
||||
*/
|
||||
public String getExtendedHeader(String name) throws MessagingException {
|
||||
if (mExtendedHeader == null) {
|
||||
return null;
|
||||
}
|
||||
return mExtendedHeader.getFirstHeader(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the MimeMessage out in MIME format.
|
||||
*/
|
||||
|
@ -21,6 +21,7 @@ import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import com.android.email.Utility;
|
||||
import com.android.email.mail.MessagingException;
|
||||
@ -98,6 +99,25 @@ public class MimeHeader {
|
||||
mFields.removeAll(removeFields);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write header into String
|
||||
*
|
||||
* @return CR-NL separated header string except the headers in writeOmitFields
|
||||
* null if header is empty
|
||||
*/
|
||||
public String writeToString() {
|
||||
if (mFields.size() == 0) {
|
||||
return null;
|
||||
}
|
||||
StringBuilder builder = new StringBuilder();
|
||||
for (Field field : mFields) {
|
||||
if (!Utility.arrayContains(writeOmitFields, field.name)) {
|
||||
builder.append(field.name + ": " + field.value + "\r\n");
|
||||
}
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
public void writeTo(OutputStream out) throws IOException, MessagingException {
|
||||
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(out), 1024);
|
||||
for (Field field : mFields) {
|
||||
|
@ -30,7 +30,10 @@ import org.apache.james.mime4j.MimeStreamParser;
|
||||
import org.apache.james.mime4j.field.DateTimeField;
|
||||
import org.apache.james.mime4j.field.Field;
|
||||
|
||||
import android.text.TextUtils;
|
||||
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
@ -47,6 +50,7 @@ import java.util.regex.Pattern;
|
||||
*/
|
||||
public class MimeMessage extends Message {
|
||||
protected MimeHeader mHeader = new MimeHeader();
|
||||
protected MimeHeader mExtendedHeader;
|
||||
|
||||
// NOTE: The fields here are transcribed out of headers, and values stored here will supercede
|
||||
// the values found in the headers. Use caution to prevent any out-of-phase errors. In
|
||||
@ -70,6 +74,8 @@ public class MimeMessage extends Message {
|
||||
|
||||
// regex that matches content id surrounded by "<>" optionally.
|
||||
private static final Pattern REMOVE_OPTIONAL_BRACKETS = Pattern.compile("^<?([^>]+)>?$");
|
||||
// regex that matches end of line.
|
||||
private static final Pattern END_OF_LINE = Pattern.compile("\r?\n");
|
||||
|
||||
public MimeMessage() {
|
||||
/*
|
||||
@ -361,9 +367,85 @@ public class MimeMessage extends Message {
|
||||
mHeader.removeHeader(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set extended header
|
||||
*
|
||||
* @param name Extended header name
|
||||
* @param value header value - flattened by removing CR-NL if any
|
||||
* remove header if value is null
|
||||
* @throws MessagingException
|
||||
*/
|
||||
public void setExtendedHeader(String name, String value) throws MessagingException {
|
||||
if (value == null) {
|
||||
if (mExtendedHeader != null) {
|
||||
mExtendedHeader.removeHeader(name);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (mExtendedHeader == null) {
|
||||
mExtendedHeader = new MimeHeader();
|
||||
}
|
||||
mExtendedHeader.setHeader(name, END_OF_LINE.matcher(value).replaceAll(""));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get extended header
|
||||
*
|
||||
* @param name Extended header name
|
||||
* @return header value - null if header does not exist
|
||||
* @throws MessagingException
|
||||
*/
|
||||
public String getExtendedHeader(String name) throws MessagingException {
|
||||
if (mExtendedHeader == null) {
|
||||
return null;
|
||||
}
|
||||
return mExtendedHeader.getFirstHeader(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set entire extended headers from String
|
||||
*
|
||||
* @param headers Extended header and its value - "CR-NL-separated pairs
|
||||
* if null or empty, remove entire extended headers
|
||||
* @throws MessagingException
|
||||
*/
|
||||
public void setExtendedHeaders(String headers) throws MessagingException {
|
||||
if (TextUtils.isEmpty(headers)) {
|
||||
mExtendedHeader = null;
|
||||
} else {
|
||||
mExtendedHeader = new MimeHeader();
|
||||
for (String header : END_OF_LINE.split(headers)) {
|
||||
String[] tokens = header.split(":", 2);
|
||||
if (tokens.length != 2) {
|
||||
throw new MessagingException("Illegal extended headers: " + headers);
|
||||
}
|
||||
mExtendedHeader.setHeader(tokens[0].trim(), tokens[1].trim());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get entire extended headers as String
|
||||
*
|
||||
* @return "CR-NL-separated extended headers - null if extended header does not exist
|
||||
*/
|
||||
public String getExtendedHeaders() {
|
||||
if (mExtendedHeader != null) {
|
||||
return mExtendedHeader.writeToString();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write message header and body to output stream
|
||||
*
|
||||
* @param out Output steam to write message header and body.
|
||||
*/
|
||||
public void writeTo(OutputStream out) throws IOException, MessagingException {
|
||||
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(out), 1024);
|
||||
mHeader.writeTo(out);
|
||||
// mExtendedHeader will not be write out to external output stream,
|
||||
// because it is intended to internal use.
|
||||
writer.write("\r\n");
|
||||
writer.flush();
|
||||
if (mBody != null) {
|
||||
|
@ -82,9 +82,10 @@ public class LocalStore extends Store implements PersistentDataCallbacks {
|
||||
* 22 - Added store_flag_1 and store_flag_2 columns to messages table.
|
||||
* 23 - Added flag_downloaded_full, flag_downloaded_partial, flag_deleted
|
||||
* columns to message table.
|
||||
* 24 - Added x_headers to messages table.
|
||||
*/
|
||||
|
||||
private static final int DB_VERSION = 23;
|
||||
private static final int DB_VERSION = 24;
|
||||
|
||||
private static final Flag[] PERMANENT_FLAGS = { Flag.DELETED, Flag.X_DESTROYED, Flag.SEEN };
|
||||
|
||||
@ -148,7 +149,7 @@ public class LocalStore extends Store implements PersistentDataCallbacks {
|
||||
"html_content TEXT, text_content TEXT, attachment_count INTEGER, " +
|
||||
"internal_date INTEGER, message_id TEXT, store_flag_1 INTEGER, " +
|
||||
"store_flag_2 INTEGER, flag_downloaded_full INTEGER," +
|
||||
"flag_downloaded_partial INTEGER, flag_deleted INTEGER)");
|
||||
"flag_downloaded_partial INTEGER, flag_deleted INTEGER, x_headers TEXT)");
|
||||
|
||||
mDb.execSQL("DROP TABLE IF EXISTS attachments");
|
||||
mDb.execSQL("CREATE TABLE attachments (id INTEGER PRIMARY KEY, message_id INTEGER,"
|
||||
@ -218,6 +219,13 @@ public class LocalStore extends Store implements PersistentDataCallbacks {
|
||||
mDb.endTransaction();
|
||||
}
|
||||
}
|
||||
if (oldVersion < 24) {
|
||||
/**
|
||||
* Upgrade 23 to 24: add x_headers to messages table
|
||||
*/
|
||||
mDb.execSQL("ALTER TABLE messages ADD COLUMN x_headers TEXT;");
|
||||
mDb.setVersion(24);
|
||||
}
|
||||
}
|
||||
|
||||
if (mDb.getVersion() != DB_VERSION) {
|
||||
@ -845,7 +853,7 @@ public class LocalStore extends Store implements PersistentDataCallbacks {
|
||||
"subject, sender_list, date, uid, flags, id, to_list, cc_list, " +
|
||||
"bcc_list, reply_to_list, attachment_count, internal_date, message_id, " +
|
||||
"store_flag_1, store_flag_2, flag_downloaded_full, flag_downloaded_partial, " +
|
||||
"flag_deleted";
|
||||
"flag_deleted, x_headers";
|
||||
|
||||
/**
|
||||
* Populate a message from a cursor with the following columns:
|
||||
@ -868,6 +876,7 @@ public class LocalStore extends Store implements PersistentDataCallbacks {
|
||||
* 15 flag "downloaded full"
|
||||
* 16 flag "downloaded partial"
|
||||
* 17 flag "deleted"
|
||||
* 18 extended headers ("\r\n"-separated string)
|
||||
*/
|
||||
private void populateMessageFromGetMessageCursor(LocalMessage message, Cursor cursor)
|
||||
throws MessagingException{
|
||||
@ -901,6 +910,7 @@ public class LocalStore extends Store implements PersistentDataCallbacks {
|
||||
message.setFlagInternal(Flag.X_DOWNLOADED_FULL, (0 != cursor.getInt(15)));
|
||||
message.setFlagInternal(Flag.X_DOWNLOADED_PARTIAL, (0 != cursor.getInt(16)));
|
||||
message.setFlagInternal(Flag.DELETED, (0 != cursor.getInt(17)));
|
||||
message.setExtendedHeaders(cursor.getString(18));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -1155,6 +1165,7 @@ public class LocalStore extends Store implements PersistentDataCallbacks {
|
||||
cv.put("flag_downloaded_partial",
|
||||
makeFlagNumeric(message, Flag.X_DOWNLOADED_PARTIAL));
|
||||
cv.put("flag_deleted", makeFlagNumeric(message, Flag.DELETED));
|
||||
cv.put("x_headers", ((MimeMessage) message).getExtendedHeaders());
|
||||
long messageId = mDb.insert("messages", "uid", cv);
|
||||
for (Part attachment : attachments) {
|
||||
saveAttachment(messageId, attachment, copy);
|
||||
@ -1209,7 +1220,7 @@ public class LocalStore extends Store implements PersistentDataCallbacks {
|
||||
+ "html_content = ?, text_content = ?, reply_to_list = ?, "
|
||||
+ "attachment_count = ?, message_id = ?, store_flag_1 = ?, "
|
||||
+ "store_flag_2 = ?, flag_downloaded_full = ?, "
|
||||
+ "flag_downloaded_partial = ?, flag_deleted = ? "
|
||||
+ "flag_downloaded_partial = ?, flag_deleted = ?, x_headers = ? "
|
||||
+ "WHERE id = ?",
|
||||
new Object[] {
|
||||
message.getUid(),
|
||||
@ -1236,6 +1247,7 @@ public class LocalStore extends Store implements PersistentDataCallbacks {
|
||||
makeFlagNumeric(message, Flag.X_DOWNLOADED_FULL),
|
||||
makeFlagNumeric(message, Flag.X_DOWNLOADED_PARTIAL),
|
||||
makeFlagNumeric(message, Flag.DELETED),
|
||||
message.getExtendedHeaders(),
|
||||
|
||||
message.mId
|
||||
});
|
||||
@ -1327,6 +1339,7 @@ public class LocalStore extends Store implements PersistentDataCallbacks {
|
||||
cv.put("content_uri", contentUri != null ? contentUri.toString() : null);
|
||||
cv.put("size", size);
|
||||
cv.put("content_id", contentId);
|
||||
cv.put("message_id", messageId);
|
||||
mDb.update(
|
||||
"attachments",
|
||||
cv,
|
||||
|
@ -155,12 +155,23 @@ public class AttachmentProvider extends ContentProvider {
|
||||
File file = new File(dir, filename);
|
||||
if (!file.exists()) {
|
||||
Uri attachmentUri = getAttachmentUri(dbName, Long.parseLong(id));
|
||||
String type = getType(attachmentUri);
|
||||
Cursor c = query(attachmentUri,
|
||||
new String[] { AttachmentProviderColumns.DATA }, null, null, null);
|
||||
if (c != null) {
|
||||
try {
|
||||
if (c.moveToFirst()) {
|
||||
attachmentUri = Uri.parse(c.getString(0));
|
||||
}
|
||||
} finally {
|
||||
c.close();
|
||||
}
|
||||
}
|
||||
String type = getContext().getContentResolver().getType(attachmentUri);
|
||||
try {
|
||||
FileInputStream in = new FileInputStream(
|
||||
new File(getContext().getDatabasePath(dbName + "_att"), id));
|
||||
InputStream in =
|
||||
getContext().getContentResolver().openInputStream(attachmentUri);
|
||||
Bitmap thumbnail = createThumbnail(type, in);
|
||||
thumbnail = thumbnail.createScaledBitmap(thumbnail, width, height, true);
|
||||
thumbnail = Bitmap.createScaledBitmap(thumbnail, width, height, true);
|
||||
FileOutputStream out = new FileOutputStream(file);
|
||||
thumbnail.compress(Bitmap.CompressFormat.PNG, 100, out);
|
||||
out.close();
|
||||
@ -207,13 +218,14 @@ public class AttachmentProvider extends ContentProvider {
|
||||
String path = getContext().getDatabasePath(dbName).getAbsolutePath();
|
||||
String name = null;
|
||||
int size = -1;
|
||||
String contentUri = null;
|
||||
SQLiteDatabase db = null;
|
||||
Cursor cursor = null;
|
||||
try {
|
||||
db = SQLiteDatabase.openDatabase(path, null, 0);
|
||||
cursor = db.query(
|
||||
"attachments",
|
||||
new String[] { "name", "size" },
|
||||
new String[] { "name", "size", "content_uri" },
|
||||
"id = ?",
|
||||
new String[] { id },
|
||||
null,
|
||||
@ -224,6 +236,7 @@ public class AttachmentProvider extends ContentProvider {
|
||||
}
|
||||
name = cursor.getString(0);
|
||||
size = cursor.getInt(1);
|
||||
contentUri = cursor.getString(2);
|
||||
}
|
||||
finally {
|
||||
if (cursor != null) {
|
||||
@ -242,7 +255,7 @@ public class AttachmentProvider extends ContentProvider {
|
||||
values[i] = id;
|
||||
}
|
||||
else if (AttachmentProviderColumns.DATA.equals(column)) {
|
||||
values[i] = uri.toString();
|
||||
values[i] = contentUri;
|
||||
}
|
||||
else if (AttachmentProviderColumns.DISPLAY_NAME.equals(column)) {
|
||||
values[i] = name;
|
||||
|
@ -30,8 +30,10 @@ import com.android.email.mail.MessageTestUtils.TextBuilder;
|
||||
import com.android.email.mail.internet.BinaryTempFileBody;
|
||||
import com.android.email.mail.store.LocalStore;
|
||||
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.net.Uri;
|
||||
import android.test.ActivityInstrumentationTestCase2;
|
||||
import android.test.suitebuilder.annotation.MediumTest;
|
||||
@ -236,8 +238,20 @@ public class MessageViewTests
|
||||
final String actual5 = a.resolveInlineImage(null, msg4, 0);
|
||||
assertNull(actual5);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Test for resolveAttachmentIdToContentUri.
|
||||
*/
|
||||
public void testResolveAttachmentIdToContentUri() throws MessagingException, IOException {
|
||||
final ContentResolver contentResolver = mContext.getContentResolver();
|
||||
final MessageView a = getActivity();
|
||||
// create attachments tables.
|
||||
LocalStore.newInstance(mAccount.getLocalStoreUri(), mContext, null);
|
||||
final String dbPath = mContext.getDatabasePath(mAccount.getUuid() + ".db").toString();
|
||||
final SQLiteDatabase db = SQLiteDatabase.openDatabase(dbPath, null, 0);
|
||||
// TODO write unit test
|
||||
}
|
||||
|
||||
/**
|
||||
* Mock Messaging controller, so we can drive its callbacks. This probably should be
|
||||
* generalized since we're likely to use for other tests eventually.
|
||||
|
@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright (C) 2009 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.email.mail.internet;
|
||||
|
||||
import android.test.suitebuilder.annotation.SmallTest;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
/**
|
||||
* This is a series of unit tests for the MimeHeader class. These tests must be locally
|
||||
* complete - no server(s) required.
|
||||
*/
|
||||
@SmallTest
|
||||
public class MimeHeaderUnitTests extends TestCase {
|
||||
|
||||
// TODO more test
|
||||
|
||||
/**
|
||||
* Test for writeToString()
|
||||
*/
|
||||
public void testWriteToString() throws Exception {
|
||||
MimeHeader header = new MimeHeader();
|
||||
|
||||
// empty header
|
||||
String actual1 = header.writeToString();
|
||||
assertEquals("empty header", actual1, null);
|
||||
|
||||
// single header
|
||||
header.setHeader("Header1", "value1");
|
||||
String actual2 = header.writeToString();
|
||||
assertEquals("single header", actual2, "Header1: value1\r\n");
|
||||
|
||||
// multiple headers
|
||||
header.setHeader("Header2", "value2");
|
||||
String actual3 = header.writeToString();
|
||||
assertEquals("multiple headers", actual3,
|
||||
"Header1: value1\r\n"
|
||||
+ "Header2: value2\r\n");
|
||||
|
||||
// omit header
|
||||
header.setHeader(MimeHeader.HEADER_ANDROID_ATTACHMENT_STORE_DATA, "value3");
|
||||
String actual4 = header.writeToString();
|
||||
assertEquals("multiple headers", actual4,
|
||||
"Header1: value1\r\n"
|
||||
+ "Header2: value2\r\n");
|
||||
}
|
||||
}
|
@ -19,12 +19,11 @@ package com.android.email.mail.internet;
|
||||
import com.android.email.mail.Address;
|
||||
import com.android.email.mail.Flag;
|
||||
import com.android.email.mail.MessagingException;
|
||||
import com.android.email.mail.internet.MimeHeader;
|
||||
import com.android.email.mail.internet.MimeMessage;
|
||||
import com.android.email.mail.Message.RecipientType;
|
||||
|
||||
import android.test.suitebuilder.annotation.SmallTest;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
@ -334,4 +333,90 @@ public class MimeMessageTest extends TestCase {
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Test for setExtendedHeader() and getExtendedHeader()
|
||||
*/
|
||||
public void testExtendedHeader() throws MessagingException {
|
||||
MimeMessage message = new MimeMessage();
|
||||
|
||||
assertNull("non existent header", message.getExtendedHeader("X-Non-Existent"));
|
||||
|
||||
message.setExtendedHeader("X-Header1", "value1");
|
||||
message.setExtendedHeader("X-Header2", "value2\n value3\r\n value4\r\n");
|
||||
assertEquals("simple value", "value1",
|
||||
message.getExtendedHeader("X-Header1"));
|
||||
assertEquals("multi line value", "value2 value3 value4",
|
||||
message.getExtendedHeader("X-Header2"));
|
||||
assertNull("non existent header 2", message.getExtendedHeader("X-Non-Existent"));
|
||||
|
||||
message.setExtendedHeader("X-Header1", "value4");
|
||||
assertEquals("over written value", "value4", message.getExtendedHeader("X-Header1"));
|
||||
|
||||
message.setExtendedHeader("X-Header1", null);
|
||||
assertNull("remove header", message.getExtendedHeader("X-Header1"));
|
||||
}
|
||||
|
||||
/*
|
||||
* Test for setExtendedHeaders() and getExtendedheaders()
|
||||
*/
|
||||
public void testExtendedHeaders() throws MessagingException {
|
||||
MimeMessage message = new MimeMessage();
|
||||
|
||||
assertNull("new message", message.getExtendedHeaders());
|
||||
message.setExtendedHeaders(null);
|
||||
assertNull("null headers", message.getExtendedHeaders());
|
||||
message.setExtendedHeaders("");
|
||||
assertNull("empty headers", message.getExtendedHeaders());
|
||||
|
||||
message.setExtendedHeaders("X-Header1: value1\r\n");
|
||||
assertEquals("header 1 value", "value1", message.getExtendedHeader("X-Header1"));
|
||||
assertEquals("header 1", "X-Header1: value1\r\n", message.getExtendedHeaders());
|
||||
|
||||
message.setExtendedHeaders(null);
|
||||
message.setExtendedHeader("X-Header2", "value2");
|
||||
message.setExtendedHeader("X-Header3", "value3\n value4\r\n value5\r\n");
|
||||
assertEquals("headers 2,3",
|
||||
"X-Header2: value2\r\n" +
|
||||
"X-Header3: value3 value4 value5\r\n",
|
||||
message.getExtendedHeaders());
|
||||
|
||||
message.setExtendedHeaders(
|
||||
"X-Header3: value3 value4 value5\r\n" +
|
||||
"X-Header2: value2\r\n");
|
||||
assertEquals("header 2", "value2", message.getExtendedHeader("X-Header2"));
|
||||
assertEquals("header 3", "value3 value4 value5", message.getExtendedHeader("X-Header3"));
|
||||
assertEquals("headers 3,2",
|
||||
"X-Header3: value3 value4 value5\r\n" +
|
||||
"X-Header2: value2\r\n",
|
||||
message.getExtendedHeaders());
|
||||
}
|
||||
|
||||
/*
|
||||
* Test for writeTo(), only for header part.
|
||||
*/
|
||||
public void testWriteToHeader() throws Exception {
|
||||
MimeMessage message = new MimeMessage();
|
||||
|
||||
message.setHeader("Header1", "value1");
|
||||
message.setHeader(MimeHeader.HEADER_ANDROID_ATTACHMENT_STORE_DATA, "value2");
|
||||
message.setExtendedHeader("X-Header3", "value3");
|
||||
message.setHeader("Header4", "value4");
|
||||
message.setExtendedHeader("X-Header5", "value5");
|
||||
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
message.writeTo(out);
|
||||
out.close();
|
||||
String expectedString = "Message-ID: " + message.getMessageId() + "\r\n" +
|
||||
"Header1: value1\r\n" +
|
||||
"Header4: value4\r\n" +
|
||||
"\r\n";
|
||||
byte[] expected = expectedString.getBytes();
|
||||
byte[] actual = out.toByteArray();
|
||||
assertEquals("output length", expected.length, actual.length);
|
||||
for (int i = 0; i < actual.length; ++i) {
|
||||
assertEquals("output byte["+i+"]", expected[i], actual[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO more test for writeTo()
|
||||
}
|
||||
|
@ -35,6 +35,7 @@ import com.android.email.mail.internet.BinaryTempFileBody;
|
||||
import com.android.email.mail.internet.MimeMessage;
|
||||
import com.android.email.mail.internet.MimeUtility;
|
||||
import com.android.email.mail.internet.TextBody;
|
||||
import com.android.email.mail.store.LocalStore.LocalMessage;
|
||||
|
||||
import android.content.ContentValues;
|
||||
import android.database.Cursor;
|
||||
@ -64,7 +65,7 @@ public class LocalStoreUnitTests extends AndroidTestCase {
|
||||
private static final String MESSAGE_ID = "Test-Message-ID";
|
||||
private static final String MESSAGE_ID_2 = "Test-Message-ID-Second";
|
||||
|
||||
private static final int DATABASE_VERSION = 23;
|
||||
private static final int DATABASE_VERSION = 24;
|
||||
|
||||
private static final String FOLDER_NAME = "TEST";
|
||||
private static final String MISSING_FOLDER_NAME = "TEST-NO-FOLDER";
|
||||
@ -99,6 +100,11 @@ public class LocalStoreUnitTests extends AndroidTestCase {
|
||||
*/
|
||||
@Override
|
||||
protected void tearDown() throws Exception {
|
||||
super.tearDown();
|
||||
if (mFolder != null) {
|
||||
mFolder.close(false);
|
||||
}
|
||||
|
||||
// First, try the official way
|
||||
if (mStore != null) {
|
||||
mStore.delete();
|
||||
@ -873,6 +879,28 @@ public class LocalStoreUnitTests extends AndroidTestCase {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for setExtendedHeader() and getExtendedHeader()
|
||||
*/
|
||||
public void testExtendedHeader() throws MessagingException {
|
||||
MimeMessage message = new MimeMessage();
|
||||
message.setUid("message1");
|
||||
mFolder.appendMessages(new Message[] { message });
|
||||
|
||||
message.setUid("message2");
|
||||
message.setExtendedHeader("X-Header1", "value1");
|
||||
message.setExtendedHeader("X-Header2", "value2\r\n value3\n value4\r\n");
|
||||
mFolder.appendMessages(new Message[] { message });
|
||||
|
||||
LocalMessage message1 = (LocalMessage) mFolder.getMessage("message1");
|
||||
assertNull("none existent header", message1.getExtendedHeader("X-None-Existent"));
|
||||
|
||||
LocalMessage message2 = (LocalMessage) mFolder.getMessage("message2");
|
||||
assertEquals("header 1", "value1", message2.getExtendedHeader("X-Header1"));
|
||||
assertEquals("header 2", "value2 value3 value4", message2.getExtendedHeader("X-Header2"));
|
||||
assertNull("header 3", message2.getExtendedHeader("X-Header3"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests for database version.
|
||||
*/
|
||||
@ -978,7 +1006,7 @@ public class LocalStoreUnitTests extends AndroidTestCase {
|
||||
// check if data are expected
|
||||
final ContentValues actualMessage = cursorToContentValues(c,
|
||||
new String[] { "primary", "integer", "integer", "text" });
|
||||
assertEquals("messages table cursor does not have expected values",
|
||||
assertEquals("messages table cursor does not have expected values",
|
||||
expectedMessage, actualMessage);
|
||||
c.close();
|
||||
|
||||
@ -1187,6 +1215,57 @@ public class LocalStoreUnitTests extends AndroidTestCase {
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests for database upgrade from version 23 to current version.
|
||||
*/
|
||||
public void testDbUpgrade23ToLatest() throws MessagingException, URISyntaxException {
|
||||
final URI uri = new URI(mLocalStoreUri);
|
||||
final String dbPath = uri.getPath();
|
||||
SQLiteDatabase db = SQLiteDatabase.openOrCreateDatabase(dbPath, null);
|
||||
|
||||
// create sample version 23 db tables
|
||||
createSampleDb(db, 23);
|
||||
|
||||
// sample message data and expected data
|
||||
final ContentValues initialMessage = new ContentValues();
|
||||
initialMessage.put("folder_id", (long) 2); // folder_id type integer == Long
|
||||
initialMessage.put("internal_date", (long) 3); // internal_date type integer == Long
|
||||
final ContentValues expectedMessage = new ContentValues(initialMessage);
|
||||
expectedMessage.put("id", db.insert("messages", null, initialMessage));
|
||||
|
||||
db.close();
|
||||
|
||||
// upgrade database 23 to latest
|
||||
LocalStore.newInstance(mLocalStoreUri, getContext(), null);
|
||||
|
||||
// added message_id column should be initialized as null
|
||||
expectedMessage.put("message_id", (String) null); // message_id type text == String
|
||||
|
||||
// database should be upgraded
|
||||
db = SQLiteDatabase.openOrCreateDatabase(dbPath, null);
|
||||
assertEquals("database should be upgraded", DATABASE_VERSION, db.getVersion());
|
||||
Cursor c;
|
||||
|
||||
// check for all "latest version" tables
|
||||
checkAllTablesFound(db);
|
||||
|
||||
// check message table
|
||||
c = db.query("messages",
|
||||
new String[] { "id", "folder_id", "internal_date", "message_id" },
|
||||
null, null, null, null, null);
|
||||
// check if data is available
|
||||
assertTrue("messages table should have one data", c.moveToNext());
|
||||
|
||||
// check if data are expected
|
||||
final ContentValues actualMessage = cursorToContentValues(c,
|
||||
new String[] { "primary", "integer", "integer", "text" });
|
||||
assertEquals("messages table cursor does not have expected values",
|
||||
expectedMessage, actualMessage);
|
||||
c.close();
|
||||
|
||||
db.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the database to confirm that all tables, with all expected columns are found.
|
||||
*/
|
||||
private void checkAllTablesFound(SQLiteDatabase db) {
|
||||
@ -1204,7 +1283,7 @@ public class LocalStoreUnitTests extends AndroidTestCase {
|
||||
"to_list", "cc_list", "bcc_list", "reply_to_list",
|
||||
"html_content", "text_content", "attachment_count",
|
||||
"internal_date", "store_flag_1", "store_flag_2", "flag_downloaded_full",
|
||||
"flag_downloaded_partial", "flag_deleted" }
|
||||
"flag_downloaded_partial", "flag_deleted", "x_headers" }
|
||||
));
|
||||
assertTrue("messages", foundNames.containsAll(expectedNames));
|
||||
|
||||
@ -1243,6 +1322,7 @@ public class LocalStoreUnitTests extends AndroidTestCase {
|
||||
((version >= 23) ?
|
||||
", flag_downloaded_full INTEGER, flag_downloaded_partial INTEGER" : "") +
|
||||
((version >= 23) ? ", flag_deleted INTEGER" : "") +
|
||||
((version >= 24) ? ", x_headers TEXT" : "") +
|
||||
")");
|
||||
db.execSQL("DROP TABLE IF EXISTS attachments");
|
||||
db.execSQL("CREATE TABLE attachments (id INTEGER PRIMARY KEY, message_id INTEGER," +
|
||||
|
Loading…
Reference in New Issue
Block a user