Merge "Add a flag to dump email messages."
diff --git a/res/layout/account_setup_basics.xml b/res/layout/account_setup_basics.xml
index 3b97f4a..ca509a2 100644
--- a/res/layout/account_setup_basics.xml
+++ b/res/layout/account_setup_basics.xml
@@ -18,11 +18,11 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true"
- android:scrollbarStyle="outsideInset" >
+ android:overscrollMode="ifContentScrolls">
<LinearLayout
android:layout_width="match_parent"
- android:layout_height="match_parent"
+ android:layout_height="wrap_content"
android:orientation="vertical" >
<LinearLayout
diff --git a/res/layout/account_setup_check_settings.xml b/res/layout/account_setup_check_settings.xml
index 34a21a5..248da2a 100644
--- a/res/layout/account_setup_check_settings.xml
+++ b/res/layout/account_setup_check_settings.xml
@@ -18,11 +18,11 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true"
- android:scrollbarStyle="outsideInset" >
+ android:overscrollMode="ifContentScrolls">
<LinearLayout
android:layout_width="match_parent"
- android:layout_height="match_parent"
+ android:layout_height="wrap_content"
android:orientation="vertical" >
<LinearLayout
diff --git a/res/layout/account_setup_exchange.xml b/res/layout/account_setup_exchange.xml
index ac06144..9e61a8d 100644
--- a/res/layout/account_setup_exchange.xml
+++ b/res/layout/account_setup_exchange.xml
@@ -19,11 +19,11 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true"
- android:scrollbarStyle="outsideInset" >
+ android:overscrollMode="ifContentScrolls">
<LinearLayout
android:layout_width="match_parent"
- android:layout_height="match_parent"
+ android:layout_height="wrap_content"
android:orientation="vertical" >
<LinearLayout
diff --git a/res/layout/account_setup_incoming.xml b/res/layout/account_setup_incoming.xml
index 2cd0edc..6bd280c 100644
--- a/res/layout/account_setup_incoming.xml
+++ b/res/layout/account_setup_incoming.xml
@@ -19,11 +19,11 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true"
- android:scrollbarStyle="outsideInset" >
+ android:overscrollMode="ifContentScrolls" >
<LinearLayout
android:layout_width="match_parent"
- android:layout_height="match_parent"
+ android:layout_height="wrap_content"
android:orientation="vertical" >
<LinearLayout
diff --git a/res/layout/account_setup_names.xml b/res/layout/account_setup_names.xml
index 977299c..15878c8 100644
--- a/res/layout/account_setup_names.xml
+++ b/res/layout/account_setup_names.xml
@@ -18,11 +18,11 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true"
- android:scrollbarStyle="outsideInset" >
+ android:overscrollMode="ifContentScrolls" >
<LinearLayout
android:layout_width="match_parent"
- android:layout_height="match_parent"
+ android:layout_height="wrap_content"
android:orientation="vertical" >
<LinearLayout
diff --git a/res/layout/account_setup_options.xml b/res/layout/account_setup_options.xml
index f2e4073..fbaaa2a 100644
--- a/res/layout/account_setup_options.xml
+++ b/res/layout/account_setup_options.xml
@@ -19,11 +19,11 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true"
- android:scrollbarStyle="outsideInset" >
+ android:overscrollMode="ifContentScrolls" >
<LinearLayout
android:layout_width="match_parent"
- android:layout_height="match_parent"
+ android:layout_height="wrap_content"
android:orientation="vertical" >
<LinearLayout
diff --git a/res/layout/account_setup_outgoing.xml b/res/layout/account_setup_outgoing.xml
index 057b224..7a9a7d5 100644
--- a/res/layout/account_setup_outgoing.xml
+++ b/res/layout/account_setup_outgoing.xml
@@ -19,11 +19,11 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true"
- android:scrollbarStyle="outsideInset" >
+ android:overscrollMode="ifContentScrolls" >
<LinearLayout
android:layout_width="match_parent"
- android:layout_height="match_parent"
+ android:layout_height="wrap_content"
android:orientation="vertical" >
<LinearLayout
diff --git a/res/values/strings.xml b/res/values/strings.xml
index b79b73b..39a83d2 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -676,4 +676,26 @@
automatically enabled for pre-existing Exchange accounts on upgrade -->
<string name="notification_exchange_calendar_added">Exchange calendar added</string>
+ <!-- Strings used for GAL access -->
+
+ <!-- Displayed in small separator in to/cc/bcc dropdowns, when searching GAL begins.
+ Example: "Searching bigcompany.com..." -->
+ <string name="gal_searching_fmt">Searching <xliff:g id="domain">%s</xliff:g>\u2026</string>
+ <!-- Displayed in small separator in to/cc/bcc dropdowns, when searching GAL completes,
+ and all of the server results are being displayed. Example:
+ "5 results from bigcompany.com..." -->
+ <plurals name="gal_completed_fmt">
+ <!-- Case of one result from server. -->
+ <item quantity="one"><xliff:g id="results" example="1">%d</xliff:g> result
+ from <xliff:g id="domain">%s</xliff:g></item>
+
+ <!-- Case of multiple results from server -->
+ <item quantity="other"><xliff:g id="results" example="20">%d</xliff:g> results
+ from <xliff:g id="domain">%s</xliff:g></item>
+ </plurals>
+ <!-- Displayed in small separator in to/cc/bcc dropdowns, when searching GAL completes,
+ and a limited amount (not all) of the server results are being displayed. This is
+ always a larger value because it represents the limit of displayed results. -->
+ <string name="gal_completed_limited_fmt">First <xliff:g id="results" example="20">%d</xliff:g>
+ results from <xliff:g id="domain">%s</xliff:g></string>
</resources>
diff --git a/src/com/android/email/activity/MessageView.java b/src/com/android/email/activity/MessageView.java
index 1e05622..e7d503e 100644
--- a/src/com/android/email/activity/MessageView.java
+++ b/src/com/android/email/activity/MessageView.java
@@ -327,6 +327,9 @@
*/
public static void actionView(Context context, long messageId, long mailboxId,
boolean disableReplyAndForward) {
+ if (messageId < 0) {
+ throw new IllegalArgumentException("MessageView invalid messageId " + messageId);
+ }
Intent i = new Intent(context, MessageView.class);
i.putExtra(EXTRA_MESSAGE_ID, messageId);
i.putExtra(EXTRA_MAILBOX_ID, mailboxId);
diff --git a/src/com/android/email/mail/transport/Rfc822Output.java b/src/com/android/email/mail/transport/Rfc822Output.java
index cdd821a..8526a01 100644
--- a/src/com/android/email/mail/transport/Rfc822Output.java
+++ b/src/com/android/email/mail/transport/Rfc822Output.java
@@ -156,11 +156,13 @@
Attachment.CONTENT_PROJECTION, null, null, null);
try {
- boolean mixedParts = attachmentsCursor.getCount() > 0;
- String mixedBoundary = null;
+ int attachmentCount = attachmentsCursor.getCount();
+ boolean multipart = attachmentCount > 0;
+ String multipartBoundary = null;
+ String multipartType = "mixed";
// Simplified case for no multipart - just emit text and be done.
- if (!mixedParts) {
+ if (!multipart) {
if (text != null) {
writeTextWithHeaders(writer, stream, text);
} else {
@@ -169,31 +171,41 @@
} else {
// continue with multipart headers, then into multipart body
writeHeader(writer, "MIME-Version", "1.0");
+ multipartBoundary = "--_com.android.email_" + System.nanoTime();
- mixedBoundary = "--_com.android.email_" + System.nanoTime();
+ // Move to the first attachment; this must succeed because multipart is true
+ attachmentsCursor.moveToFirst();
+ if (attachmentCount == 1) {
+ // If we've got one attachment and it's an ics "attachment", we want to send
+ // this as multipart/alternative instead of multipart/mixed
+ int flags = attachmentsCursor.getInt(Attachment.CONTENT_FLAGS_COLUMN);
+ if ((flags & Attachment.FLAG_ICS_ALTERNATIVE_PART) != 0) {
+ multipartType = "alternative";
+ }
+ }
+
writeHeader(writer, "Content-Type",
- "multipart/mixed; boundary=\"" + mixedBoundary + "\"");
-
+ "multipart/" + multipartType + "; boundary=\"" + multipartBoundary + "\"");
// Finish headers and prepare for body section(s)
writer.write("\r\n");
// first multipart element is the body
if (text != null) {
- writeBoundary(writer, mixedBoundary, false);
+ writeBoundary(writer, multipartBoundary, false);
writeTextWithHeaders(writer, stream, text);
}
- // Write out the attachments
- while (attachmentsCursor.moveToNext()) {
- writeBoundary(writer, mixedBoundary, false);
+ // Write out the attachments until we run out
+ do {
+ writeBoundary(writer, multipartBoundary, false);
Attachment attachment =
Attachment.getContent(attachmentsCursor, Attachment.class);
writeOneAttachment(context, writer, stream, attachment);
writer.write("\r\n");
- }
+ } while (attachmentsCursor.moveToNext());
// end of multipart section
- writeBoundary(writer, mixedBoundary, true);
+ writeBoundary(writer, multipartBoundary, true);
}
} finally {
attachmentsCursor.close();
@@ -213,7 +225,7 @@
writeHeader(writer, "Content-Transfer-Encoding", "base64");
// Most attachments (real files) will send Content-Disposition. The suppression option
// is used when sending calendar invites.
- if ((attachment.mFlags & Attachment.FLAG_SUPPRESS_DISPOSITION) == 0) {
+ if ((attachment.mFlags & Attachment.FLAG_ICS_ALTERNATIVE_PART) == 0) {
writeHeader(writer, "Content-Disposition",
"attachment;"
+ "\n filename=\"" + attachment.mFileName + "\";"
diff --git a/src/com/android/email/provider/EmailContent.java b/src/com/android/email/provider/EmailContent.java
index 1e5f3ba..fbb1426 100644
--- a/src/com/android/email/provider/EmailContent.java
+++ b/src/com/android/email/provider/EmailContent.java
@@ -1680,8 +1680,10 @@
};
// Bits used in mFlags
- // Instruct RFC822 output code to supress "content-disposition". Used for calendar invites.
- public static final int FLAG_SUPPRESS_DISPOSITION = 1<<0;
+ // Instruct Rfc822Output to 1) not use Content-Disposition and 2) use multipart/alternative
+ // with this attachment. This is only valid if there is one and only one attachment and
+ // that attachment has this flag set
+ public static final int FLAG_ICS_ALTERNATIVE_PART = 1<<0;
/**
* no public constructor since this is a utility class
diff --git a/src/com/android/exchange/SyncManager.java b/src/com/android/exchange/SyncManager.java
index d4501b8..77d98cd 100644
--- a/src/com/android/exchange/SyncManager.java
+++ b/src/com/android/exchange/SyncManager.java
@@ -702,8 +702,13 @@
// Reset the sync key locally in the Mailbox and set it not to sync
cv.put(Mailbox.SYNC_KEY, "0");
cv.put(Mailbox.SYNC_INTERVAL, Mailbox.CHECK_INTERVAL_NEVER);
- // Delete all events in this calendar
- mResolver.delete(Events.CONTENT_URI, WHERE_CALENDAR_ID,
+ // Delete all events in this calendar using the sync adapter
+ // parameter so that the deletion is only local
+ Uri eventsAsSyncAdapter =
+ Events.CONTENT_URI.buildUpon()
+ .appendQueryParameter(Calendar.CALLER_IS_SYNCADAPTER,
+ "true").build();
+ mResolver.delete(eventsAsSyncAdapter, WHERE_CALENDAR_ID,
new String[] {Long.toString(mCalendarId)});
// TODO Stop sync in progress??
} else {
diff --git a/src/com/android/exchange/provider/GalEmailAddressAdapter.java b/src/com/android/exchange/provider/GalEmailAddressAdapter.java
index 93ffc96..c740437 100644
--- a/src/com/android/exchange/provider/GalEmailAddressAdapter.java
+++ b/src/com/android/exchange/provider/GalEmailAddressAdapter.java
@@ -35,7 +35,7 @@
import android.widget.TextView;
/**
- * TODO: Use real format strings, get rid of all hardcoded strings
+ * Email Address adapter that performs asynchronous GAL lookups.
*/
public class GalEmailAddressAdapter extends EmailAddressAdapter {
// STOPSHIP - DO NOT RELEASE AS 'TRUE'
@@ -237,19 +237,25 @@
separator = mInflater.inflate(R.layout.recipient_dropdown_separator, parent, false);
TextView text1 = (TextView) separator.findViewById(R.id.text1);
View progress = separator.findViewById(R.id.progress);
- // TODO replace this logic with proper formatting
+ String bannerText;
if (mSeparatorDisplayCount == -1) {
- text1.setText("Searching " + mAccountEmailDomain);
+ // Display "Searching <account>..."
+ bannerText = mContext.getString(R.string.gal_searching_fmt, mAccountEmailDomain);
progress.setVisibility(View.VISIBLE);
} else {
if (mSeparatorDisplayCount == mSeparatorTotalCount) {
- text1.setText(mSeparatorDisplayCount + " results from " + mAccountEmailDomain);
+ // Display "x results from <account>"
+ bannerText = mContext.getResources().getQuantityString(
+ R.plurals.gal_completed_fmt, mSeparatorDisplayCount,
+ mSeparatorDisplayCount, mAccountEmailDomain);
} else {
- text1.setText("First " + mSeparatorDisplayCount + " results from " +
- mAccountEmailDomain);
+ // Display "First x results from <account>"
+ bannerText = mContext.getString(R.string.gal_completed_limited_fmt,
+ mSeparatorDisplayCount, mAccountEmailDomain);
}
progress.setVisibility(View.GONE);
}
+ text1.setText(bannerText);
return separator;
}
return super.getView(getRealPosition(position), convertView, parent);
diff --git a/src/com/android/exchange/utility/CalendarUtilities.java b/src/com/android/exchange/utility/CalendarUtilities.java
index 244cca5..c6beaca 100644
--- a/src/com/android/exchange/utility/CalendarUtilities.java
+++ b/src/com/android/exchange/utility/CalendarUtilities.java
@@ -1469,7 +1469,7 @@
att.mFileName = "invite.ics";
att.mSize = att.mContentBytes.length;
// We don't send content-disposition with this attachment
- att.mFlags = Attachment.FLAG_SUPPRESS_DISPOSITION;
+ att.mFlags = Attachment.FLAG_ICS_ALTERNATIVE_PART;
// Add the attachment to the message
msg.mAttachments = new ArrayList<Attachment>();
diff --git a/src/org/apache/james/mime4j/Log.java b/src/org/apache/james/mime4j/Log.java
index 7c4ce51..6e9c2da 100644
--- a/src/org/apache/james/mime4j/Log.java
+++ b/src/org/apache/james/mime4j/Log.java
@@ -16,6 +16,8 @@
package org.apache.james.mime4j;
+import com.android.email.Email;
+
/**
* Empty stub for the apache logging library.
*/
@@ -24,62 +26,89 @@
}
public boolean isDebugEnabled() {
- return false;
+ return Email.LOGD;
}
public boolean isErrorEnabled() {
- return false;
+ return true;
}
public boolean isFatalEnabled() {
- return false;
+ return true;
}
public boolean isInfoEnabled() {
- return false;
+ return Email.LOGD;
}
public boolean isTraceEnabled() {
- return false;
+ return Email.LOGD;
}
public boolean isWarnEnabled() {
- return false;
+ return true;
}
public void trace(Object message) {
+ if (!isTraceEnabled()) return;
+ android.util.Log.v(Email.LOG_TAG, toString(message, null));
}
public void trace(Object message, Throwable t) {
+ if (!isTraceEnabled()) return;
+ android.util.Log.v(Email.LOG_TAG, toString(message, t));
}
public void debug(Object message) {
+ if (!isDebugEnabled()) return;
+ android.util.Log.d(Email.LOG_TAG, toString(message, null));
}
public void debug(Object message, Throwable t) {
+ if (!isDebugEnabled()) return;
+ android.util.Log.d(Email.LOG_TAG, toString(message, t));
}
public void info(Object message) {
+ if (!isInfoEnabled()) return;
+ android.util.Log.i(Email.LOG_TAG, toString(message, null));
}
public void info(Object message, Throwable t) {
+ if (!isInfoEnabled()) return;
+ android.util.Log.i(Email.LOG_TAG, toString(message, t));
}
public void warn(Object message) {
+ android.util.Log.w(Email.LOG_TAG, toString(message, null));
}
public void warn(Object message, Throwable t) {
+ android.util.Log.w(Email.LOG_TAG, toString(message, t));
}
public void error(Object message) {
+ android.util.Log.e(Email.LOG_TAG, toString(message, null));
}
public void error(Object message, Throwable t) {
+ android.util.Log.e(Email.LOG_TAG, toString(message, t));
}
public void fatal(Object message) {
+ android.util.Log.e(Email.LOG_TAG, toString(message, null));
}
public void fatal(Object message, Throwable t) {
+ android.util.Log.e(Email.LOG_TAG, toString(message, t));
+ }
+
+ private static String toString(Object o, Throwable t) {
+ String m = (o == null) ? "(null)" : o.toString();
+ if (t == null) {
+ return m;
+ } else {
+ return m + " " + t.getMessage();
+ }
}
}
diff --git a/tests/src/com/android/email/mail/transport/Rfc822OutputTests.java b/tests/src/com/android/email/mail/transport/Rfc822OutputTests.java
index d445210..21b8dbb 100644
--- a/tests/src/com/android/email/mail/transport/Rfc822OutputTests.java
+++ b/tests/src/com/android/email/mail/transport/Rfc822OutputTests.java
@@ -16,9 +16,26 @@
package com.android.email.mail.transport;
+import com.android.email.mail.MessagingException;
+import com.android.email.provider.EmailProvider;
+import com.android.email.provider.EmailContent.Attachment;
import com.android.email.provider.EmailContent.Message;
-import android.test.AndroidTestCase;
+import org.apache.james.mime4j.field.Field;
+import org.apache.james.mime4j.message.Body;
+import org.apache.james.mime4j.message.Entity;
+import org.apache.james.mime4j.message.Header;
+import org.apache.james.mime4j.message.Multipart;
+
+import android.content.Context;
+import android.test.ProviderTestCase2;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
/**
* Tests of the Rfc822Output (used for sending mail)
@@ -26,7 +43,7 @@
* You can run this entire test case with:
* runtest -c com.android.email.mail.transport.Rfc822OutputTests email
*/
-public class Rfc822OutputTests extends AndroidTestCase {
+public class Rfc822OutputTests extends ProviderTestCase2<EmailProvider> {
private static final String SENDER = "sender@android.com";
private static final String REPLYTO = "replyto@android.com";
private static final String RECIPIENT_TO = "recipient-to@android.com";
@@ -38,6 +55,18 @@
private static final String REPLY_BODY_SHORT = "\n\n" + SENDER + " wrote:\n\n";
private static final String REPLY_BODY = REPLY_BODY_SHORT + ">" + BODY;
+ private Context mMockContext;
+
+ public Rfc822OutputTests () {
+ super(EmailProvider.class, EmailProvider.EMAIL_AUTHORITY);
+ }
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+ mMockContext = getMockContext();
+ }
+
// TODO Create more tests here. Specifically, we should test to make sure that forward works
// properly instead of just reply
@@ -63,16 +92,16 @@
msg.mFlags = Message.FLAG_TYPE_REPLY;
msg.mTextReply = BODY;
msg.mIntroText = REPLY_BODY_SHORT;
- msg.save(getContext());
+ msg.save(mMockContext);
- String body = Rfc822Output.buildBodyText(getContext(), msg, true);
+ String body = Rfc822Output.buildBodyText(mMockContext, msg, true);
assertEquals(REPLY_BODY, body);
// Save a different message with no reply body (so we reset the id)
msg.mId = -1;
msg.mTextReply = null;
- msg.save(getContext());
- body = Rfc822Output.buildBodyText(getContext(), msg, true);
+ msg.save(mMockContext);
+ body = Rfc822Output.buildBodyText(mMockContext, msg, true);
assertEquals(REPLY_BODY_SHORT, body);
}
@@ -89,16 +118,126 @@
msg.mFlags = Message.FLAG_TYPE_REPLY;
msg.mTextReply = BODY;
msg.mIntroText = REPLY_BODY_SHORT;
- msg.save(getContext());
+ msg.save(mMockContext);
- String body = Rfc822Output.buildBodyText(getContext(), msg, false);
+ String body = Rfc822Output.buildBodyText(mMockContext, msg, false);
assertEquals(TEXT + REPLY_BODY_SHORT, body);
// Save a different message with no reply body (so we reset the id)
msg.mId = -1;
msg.mTextReply = null;
- msg.save(getContext());
- body = Rfc822Output.buildBodyText(getContext(), msg, false);
+ msg.save(mMockContext);
+ body = Rfc822Output.buildBodyText(mMockContext, msg, false);
assertEquals(TEXT + REPLY_BODY_SHORT, body);
}
- }
+
+ public void testWriteToText() throws IOException, MessagingException {
+ // Create a simple text message
+ Message msg = new Message();
+ msg.mText = TEXT;
+ msg.mFrom = SENDER;
+ // Save this away
+ msg.save(mMockContext);
+
+ // Write out an Rfc822 message
+ ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
+ Rfc822Output.writeTo(mMockContext, msg.mId, byteStream, false, false);
+
+ // Get the message and create a mime4j message from it
+ // We'll take advantage of its parsing capabilities
+ ByteArrayInputStream messageInputStream =
+ new ByteArrayInputStream(byteStream.toByteArray());
+ org.apache.james.mime4j.message.Message mimeMessage =
+ new org.apache.james.mime4j.message.Message(messageInputStream);
+
+ // Make sure its structure is correct
+ assertFalse(mimeMessage.isMultipart());
+ assertEquals("text/plain", mimeMessage.getMimeType());
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testWriteToAlternativePart() throws IOException, MessagingException {
+ // Create a message with alternative part
+ Message msg = new Message();
+ msg.mText = TEXT;
+ msg.mFrom = SENDER;
+ msg.mAttachments = new ArrayList<Attachment>();
+ // Attach a meeting invitation, which needs to be sent as multipart/alternative
+ Attachment att = new Attachment();
+ att.mContentBytes = "__CONTENT__".getBytes("UTF-8");
+ att.mFlags = Attachment.FLAG_ICS_ALTERNATIVE_PART;
+ att.mMimeType = "text/calendar";
+ att.mFileName = "invite.ics";
+ msg.mAttachments.add(att);
+ // Save this away
+ msg.save(mMockContext);
+
+ // Write out an Rfc822 message
+ ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
+ Rfc822Output.writeTo(mMockContext, msg.mId, byteStream, false, false);
+
+ // Get the message and create a mime4j message from it
+ // We'll take advantage of its parsing capabilities
+ ByteArrayInputStream messageInputStream =
+ new ByteArrayInputStream(byteStream.toByteArray());
+ org.apache.james.mime4j.message.Message mimeMessage =
+ new org.apache.james.mime4j.message.Message(messageInputStream);
+
+ // Make sure its structure is correct
+ assertTrue(mimeMessage.isMultipart());
+ Header header = mimeMessage.getHeader();
+ Field contentType = header.getField("content-type");
+ assertTrue(contentType.getBody().contains("multipart/alternative"));
+ Multipart multipart = (Multipart)mimeMessage.getBody();
+ List<Body> partList = multipart.getBodyParts();
+ assertEquals(2, partList.size());
+ Entity part = (Entity)partList.get(0);
+ assertEquals("text/plain", part.getMimeType());
+ part = (Entity)partList.get(1);
+ assertEquals("text/calendar", part.getMimeType());
+ header = part.getHeader();
+ assertNull(header.getField("content-disposition"));
+ }
+
+ public void testWriteToMixedPart() throws IOException, MessagingException {
+ // Create a message with a mixed part
+ Message msg = new Message();
+ msg.mText = TEXT;
+ msg.mFrom = SENDER;
+ msg.mAttachments = new ArrayList<Attachment>();
+ // Attach a simple html "file"
+ Attachment att = new Attachment();
+ att.mContentBytes = "<html>Hi</html>".getBytes("UTF-8");
+ att.mMimeType = "text/html";
+ att.mFileName = "test.html";
+ msg.mAttachments.add(att);
+ // Save this away
+ msg.save(mMockContext);
+
+ // Write out an Rfc822 message
+ ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
+ Rfc822Output.writeTo(mMockContext, msg.mId, byteStream, false, false);
+
+ // Get the message and create a mime4j message from it
+ // We'll take advantage of its parsing capabilities
+ ByteArrayInputStream messageInputStream =
+ new ByteArrayInputStream(byteStream.toByteArray());
+ org.apache.james.mime4j.message.Message mimeMessage =
+ new org.apache.james.mime4j.message.Message(messageInputStream);
+
+ // Make sure its structure is correct
+ assertTrue(mimeMessage.isMultipart());
+ Header header = mimeMessage.getHeader();
+ Field contentType = header.getField("content-type");
+ assertTrue(contentType.getBody().contains("multipart/mixed"));
+ Multipart multipart = (Multipart)mimeMessage.getBody();
+ List<Body> partList = multipart.getBodyParts();
+ assertEquals(2, partList.size());
+ Entity part = (Entity)partList.get(0);
+ assertEquals("text/plain", part.getMimeType());
+ part = (Entity)partList.get(1);
+ assertEquals("text/html", part.getMimeType());
+ header = part.getHeader();
+ assertNotNull(header.getField("content-disposition"));
+ }
+}
diff --git a/tests/src/com/android/exchange/utility/CalendarUtilitiesTests.java b/tests/src/com/android/exchange/utility/CalendarUtilitiesTests.java
index 2468f1b..3f7beff 100644
--- a/tests/src/com/android/exchange/utility/CalendarUtilitiesTests.java
+++ b/tests/src/com/android/exchange/utility/CalendarUtilitiesTests.java
@@ -233,8 +233,8 @@
Attachment att = msg.mAttachments.get(0);
// And that the attachment has the correct elements
assertEquals("invite.ics", att.mFileName);
- assertEquals(Attachment.FLAG_SUPPRESS_DISPOSITION,
- att.mFlags & Attachment.FLAG_SUPPRESS_DISPOSITION);
+ assertEquals(Attachment.FLAG_ICS_ALTERNATIVE_PART,
+ att.mFlags & Attachment.FLAG_ICS_ALTERNATIVE_PART);
assertEquals("text/calendar; method=REPLY", att.mMimeType);
assertNotNull(att.mContentBytes);
assertEquals(att.mSize, att.mContentBytes.length);
@@ -272,8 +272,8 @@
Attachment att = msg.mAttachments.get(0);
// And that the attachment has the correct elements
assertEquals("invite.ics", att.mFileName);
- assertEquals(Attachment.FLAG_SUPPRESS_DISPOSITION,
- att.mFlags & Attachment.FLAG_SUPPRESS_DISPOSITION);
+ assertEquals(Attachment.FLAG_ICS_ALTERNATIVE_PART,
+ att.mFlags & Attachment.FLAG_ICS_ALTERNATIVE_PART);
assertEquals("text/calendar; method=REQUEST", att.mMimeType);
assertNotNull(att.mContentBytes);
assertEquals(att.mSize, att.mContentBytes.length);
@@ -337,8 +337,8 @@
Attachment att = msg.mAttachments.get(0);
// And that the attachment has the correct elements
assertEquals("invite.ics", att.mFileName);
- assertEquals(Attachment.FLAG_SUPPRESS_DISPOSITION,
- att.mFlags & Attachment.FLAG_SUPPRESS_DISPOSITION);
+ assertEquals(Attachment.FLAG_ICS_ALTERNATIVE_PART,
+ att.mFlags & Attachment.FLAG_ICS_ALTERNATIVE_PART);
assertEquals("text/calendar; method=REQUEST", att.mMimeType);
assertNotNull(att.mContentBytes);