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