Handle viewing of attachments that are, themselves, emails
* Add intent filter for application/eml and message/rfc822 mime types, launching MessageView with a Uri * Modify loadMessageTask to handle the Uri by parsing the attachment's input stream with Pop3Message.parse(), and then creating an EmailProvider message in a special Mailbox created to hold "attachment" messages * Delete all "attachment" messages after the parent message is closed * Add unit tests Change-Id: I20276ee006b9f05b889f3c808d3dc407cde26d49
This commit is contained in:
parent
8ade2fe010
commit
391ae25c43
|
@ -191,6 +191,12 @@
|
|||
<activity
|
||||
android:name=".activity.MessageView"
|
||||
android:theme="@android:style/Theme.NoTitleBar" >
|
||||
<intent-filter android:label="@string/app_name">
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<data android:mimeType="application/eml" />
|
||||
<data android:mimeType="message/rfc822" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".activity.MessageCompose"
|
||||
|
|
|
@ -308,6 +308,8 @@
|
|||
<string name="message_saved_toast">Message saved as draft.</string>
|
||||
<!-- String that is displayed when the attachment could not be displayed. -->
|
||||
<string name="message_view_display_attachment_toast">This attachment cannot be displayed.</string>
|
||||
<!-- String that is displayed when a long message is being parsed. -->
|
||||
<string name="message_view_parse_message_toast">Opening message\u2026</string>
|
||||
|
||||
<!-- Title of screen when setting up new email account -->
|
||||
<string name="account_setup_basics_title">Set up email</string>
|
||||
|
|
|
@ -19,6 +19,7 @@ package com.android.email;
|
|||
import com.android.email.mail.AuthenticationFailedException;
|
||||
import com.android.email.mail.MessagingException;
|
||||
import com.android.email.mail.Store;
|
||||
import com.android.email.mail.store.Pop3Store.Pop3Message;
|
||||
import com.android.email.provider.AttachmentProvider;
|
||||
import com.android.email.provider.EmailContent;
|
||||
import com.android.email.provider.EmailContent.Account;
|
||||
|
@ -41,6 +42,9 @@ import android.os.RemoteException;
|
|||
import android.util.Log;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.HashSet;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
|
@ -59,6 +63,17 @@ public class Controller {
|
|||
private final ServiceCallback mServiceCallback = new ServiceCallback();
|
||||
private final HashSet<Result> mListeners = new HashSet<Result>();
|
||||
|
||||
|
||||
// Note that 0 is a syntactically valid account key; however there can never be an account
|
||||
// with id = 0, so attempts to restore the account will return null. Null values are
|
||||
// handled properly within the code, so this won't cause any issues.
|
||||
private static final long ATTACHMENT_MAILBOX_ACCOUNT_KEY = 0;
|
||||
/*package*/ static final String ATTACHMENT_MAILBOX_SERVER_ID = "__attachment_mailbox__";
|
||||
/*package*/ static final String ATTACHMENT_MESSAGE_UID_PREFIX = "__attachment_message__";
|
||||
private static final String WHERE_TYPE_ATTACHMENT =
|
||||
MailboxColumns.TYPE + "=" + Mailbox.TYPE_ATTACHMENT;
|
||||
private static final String WHERE_MAILBOX_KEY = MessageColumns.MAILBOX_KEY + "=?";
|
||||
|
||||
private static String[] MESSAGEID_TO_ACCOUNTID_PROJECTION = new String[] {
|
||||
EmailContent.RECORD_ID,
|
||||
EmailContent.MessageColumns.ACCOUNT_KEY
|
||||
|
@ -83,7 +98,7 @@ public class Controller {
|
|||
protected Controller(Context _context) {
|
||||
mContext = _context.getApplicationContext();
|
||||
mProviderContext = _context;
|
||||
mLegacyController = MessagingController.getInstance(mContext);
|
||||
mLegacyController = MessagingController.getInstance(mProviderContext);
|
||||
mLegacyController.addListener(mLegacyListener);
|
||||
}
|
||||
|
||||
|
@ -137,6 +152,89 @@ public class Controller {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all Messages that live in the attachment mailbox
|
||||
*/
|
||||
public void deleteAttachmentMessages() {
|
||||
// Note: There should only be one attachment mailbox at present
|
||||
ContentResolver resolver = mProviderContext.getContentResolver();
|
||||
Cursor c = null;
|
||||
try {
|
||||
c = resolver.query(Mailbox.CONTENT_URI, EmailContent.ID_PROJECTION,
|
||||
WHERE_TYPE_ATTACHMENT, null, null);
|
||||
while (c.moveToNext()) {
|
||||
long mailboxId = c.getLong(EmailContent.ID_PROJECTION_COLUMN);
|
||||
// Must delete attachments BEFORE messages
|
||||
AttachmentProvider.deleteAllMailboxAttachmentFiles(mProviderContext, 0, mailboxId);
|
||||
resolver.delete(Message.CONTENT_URI, WHERE_MAILBOX_KEY,
|
||||
new String[] {Long.toString(mailboxId)});
|
||||
}
|
||||
} finally {
|
||||
if (c != null) {
|
||||
c.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the attachment Mailbox (where we store eml attachment Emails), creating one
|
||||
* if necessary
|
||||
* @return the account's temporary Mailbox
|
||||
*/
|
||||
public Mailbox getAttachmentMailbox() {
|
||||
Cursor c = mProviderContext.getContentResolver().query(Mailbox.CONTENT_URI,
|
||||
Mailbox.CONTENT_PROJECTION, WHERE_TYPE_ATTACHMENT, null, null);
|
||||
try {
|
||||
if (c.moveToFirst()) {
|
||||
return new Mailbox().restore(c);
|
||||
}
|
||||
} finally {
|
||||
c.close();
|
||||
}
|
||||
Mailbox m = new Mailbox();
|
||||
m.mAccountKey = ATTACHMENT_MAILBOX_ACCOUNT_KEY;
|
||||
m.mServerId = ATTACHMENT_MAILBOX_SERVER_ID;
|
||||
m.mFlagVisible = false;
|
||||
m.mDisplayName = ATTACHMENT_MAILBOX_SERVER_ID;
|
||||
m.mSyncInterval = Mailbox.CHECK_INTERVAL_NEVER;
|
||||
m.mType = Mailbox.TYPE_ATTACHMENT;
|
||||
m.save(mProviderContext);
|
||||
return m;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Message from the Uri and store it in the attachment mailbox
|
||||
* @param uri the uri containing message content
|
||||
* @return the Message or null
|
||||
*/
|
||||
public Message loadMessageFromUri(Uri uri) {
|
||||
Mailbox mailbox = getAttachmentMailbox();
|
||||
if (mailbox == null) return null;
|
||||
try {
|
||||
InputStream is = mProviderContext.getContentResolver().openInputStream(uri);
|
||||
try {
|
||||
// First, create a Pop3Message from the attachment and then parse it
|
||||
Pop3Message pop3Message = new Pop3Message(
|
||||
ATTACHMENT_MESSAGE_UID_PREFIX + System.currentTimeMillis(), null);
|
||||
pop3Message.parse(is);
|
||||
// Now, pull out the header fields
|
||||
Message msg = new Message();
|
||||
LegacyConversions.updateMessageFields(msg, pop3Message, 0, mailbox.mId);
|
||||
// Commit the message to the local store
|
||||
msg.save(mProviderContext);
|
||||
// Setup the rest of the message and mark it completely loaded
|
||||
mLegacyController.copyOneMessageToProvider(pop3Message, msg,
|
||||
Message.FLAG_LOADED_COMPLETE, mProviderContext);
|
||||
// Restore the complete message and return it
|
||||
return Message.restoreMessageWithId(mProviderContext, msg.mId);
|
||||
} catch (MessagingException e) {
|
||||
} catch (IOException e) {
|
||||
}
|
||||
} catch (FileNotFoundException e) {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable/disable logging for external sync services
|
||||
*
|
||||
|
|
|
@ -435,11 +435,11 @@ public class MessagingController implements Runnable {
|
|||
}
|
||||
}
|
||||
|
||||
private void saveOrUpdate(EmailContent content) {
|
||||
private void saveOrUpdate(EmailContent content, Context context) {
|
||||
if (content.isSaved()) {
|
||||
content.update(mContext, content.toContentValues());
|
||||
content.update(context, content.toContentValues());
|
||||
} else {
|
||||
content.save(mContext);
|
||||
content.save(context);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -619,7 +619,7 @@ public class MessagingController implements Runnable {
|
|||
LegacyConversions.updateMessageFields(localMessage,
|
||||
message, account.mId, folder.mId);
|
||||
// Commit the message to the local store
|
||||
saveOrUpdate(localMessage);
|
||||
saveOrUpdate(localMessage, mContext);
|
||||
// Track the "new" ness of the downloaded message
|
||||
if (!message.isSet(Flag.SEEN)) {
|
||||
newMessages.add(message);
|
||||
|
@ -916,7 +916,7 @@ public class MessagingController implements Runnable {
|
|||
|
||||
/**
|
||||
* Copy one downloaded message (which may have partially-loaded sections)
|
||||
* into a provider message
|
||||
* into a newly created EmailProvider Message, given the account and mailbox
|
||||
*
|
||||
* @param message the remote message we've just downloaded
|
||||
* @param account the account it will be stored into
|
||||
|
@ -924,47 +924,59 @@ public class MessagingController implements Runnable {
|
|||
* @param loadStatus when complete, the message will be marked with this status (e.g.
|
||||
* EmailContent.Message.LOADED)
|
||||
*/
|
||||
private void copyOneMessageToProvider(Message message, EmailContent.Account account,
|
||||
public void copyOneMessageToProvider(Message message, EmailContent.Account account,
|
||||
EmailContent.Mailbox folder, int loadStatus) {
|
||||
EmailContent.Message localMessage = null;
|
||||
Cursor c = null;
|
||||
try {
|
||||
EmailContent.Message localMessage = null;
|
||||
Cursor c = null;
|
||||
try {
|
||||
c = mContext.getContentResolver().query(
|
||||
EmailContent.Message.CONTENT_URI,
|
||||
EmailContent.Message.CONTENT_PROJECTION,
|
||||
EmailContent.MessageColumns.ACCOUNT_KEY + "=?" +
|
||||
" AND " + MessageColumns.MAILBOX_KEY + "=?" +
|
||||
" AND " + SyncColumns.SERVER_ID + "=?",
|
||||
new String[] {
|
||||
String.valueOf(account.mId),
|
||||
String.valueOf(folder.mId),
|
||||
String.valueOf(message.getUid())
|
||||
},
|
||||
null);
|
||||
if (c.moveToNext()) {
|
||||
localMessage = EmailContent.getContent(c, EmailContent.Message.class);
|
||||
}
|
||||
} finally {
|
||||
if (c != null) {
|
||||
c.close();
|
||||
}
|
||||
c = mContext.getContentResolver().query(
|
||||
EmailContent.Message.CONTENT_URI,
|
||||
EmailContent.Message.CONTENT_PROJECTION,
|
||||
EmailContent.MessageColumns.ACCOUNT_KEY + "=?" +
|
||||
" AND " + MessageColumns.MAILBOX_KEY + "=?" +
|
||||
" AND " + SyncColumns.SERVER_ID + "=?",
|
||||
new String[] {
|
||||
String.valueOf(account.mId),
|
||||
String.valueOf(folder.mId),
|
||||
String.valueOf(message.getUid())
|
||||
},
|
||||
null);
|
||||
if (c.moveToNext()) {
|
||||
localMessage = EmailContent.getContent(c, EmailContent.Message.class);
|
||||
localMessage.mMailboxKey = folder.mId;
|
||||
localMessage.mAccountKey = account.mId;
|
||||
copyOneMessageToProvider(message, localMessage, loadStatus, mContext);
|
||||
}
|
||||
if (localMessage == null) {
|
||||
Log.d(Email.LOG_TAG, "Could not retrieve message from db, UUID="
|
||||
+ message.getUid());
|
||||
return;
|
||||
} finally {
|
||||
if (c != null) {
|
||||
c.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EmailContent.Body body = EmailContent.Body.restoreBodyWithMessageId(mContext,
|
||||
/**
|
||||
* Copy one downloaded message (which may have partially-loaded sections)
|
||||
* into an already-created EmailProvider Message
|
||||
*
|
||||
* @param message the remote message we've just downloaded
|
||||
* @param localMessage the EmailProvider Message, already created
|
||||
* @param loadStatus when complete, the message will be marked with this status (e.g.
|
||||
* EmailContent.Message.LOADED)
|
||||
* @param context the context to be used for EmailProvider
|
||||
*/
|
||||
public void copyOneMessageToProvider(Message message, EmailContent.Message localMessage,
|
||||
int loadStatus, Context context) {
|
||||
try {
|
||||
|
||||
EmailContent.Body body = EmailContent.Body.restoreBodyWithMessageId(context,
|
||||
localMessage.mId);
|
||||
if (body == null) {
|
||||
body = new EmailContent.Body();
|
||||
}
|
||||
try {
|
||||
// Copy the fields that are available into the message object
|
||||
LegacyConversions.updateMessageFields(localMessage, message, account.mId,
|
||||
folder.mId);
|
||||
LegacyConversions.updateMessageFields(localMessage, message,
|
||||
localMessage.mAccountKey, localMessage.mMailboxKey);
|
||||
|
||||
// Now process body parts & attachments
|
||||
ArrayList<Part> viewables = new ArrayList<Part>();
|
||||
|
@ -974,11 +986,11 @@ public class MessagingController implements Runnable {
|
|||
LegacyConversions.updateBodyFields(body, localMessage, viewables);
|
||||
|
||||
// Commit the message & body to the local store immediately
|
||||
saveOrUpdate(localMessage);
|
||||
saveOrUpdate(body);
|
||||
saveOrUpdate(localMessage, context);
|
||||
saveOrUpdate(body, context);
|
||||
|
||||
// process (and save) attachments
|
||||
LegacyConversions.updateAttachments(mContext, localMessage,
|
||||
LegacyConversions.updateAttachments(context, localMessage,
|
||||
attachments, false);
|
||||
|
||||
// One last update of message with two updated flags
|
||||
|
@ -989,7 +1001,7 @@ public class MessagingController implements Runnable {
|
|||
cv.put(EmailContent.MessageColumns.FLAG_LOADED, localMessage.mFlagLoaded);
|
||||
Uri uri = ContentUris.withAppendedId(EmailContent.Message.CONTENT_URI,
|
||||
localMessage.mId);
|
||||
mContext.getContentResolver().update(uri, cv, null, null);
|
||||
context.getContentResolver().update(uri, cv, null, null);
|
||||
|
||||
} catch (MessagingException me) {
|
||||
Log.e(Email.LOG_TAG, "Error while copying downloaded message." + me);
|
||||
|
|
|
@ -17,9 +17,9 @@
|
|||
package com.android.email.activity;
|
||||
|
||||
import com.android.email.Controller;
|
||||
import com.android.email.ControllerResultUiThreadWrapper;
|
||||
import com.android.email.Email;
|
||||
import com.android.email.R;
|
||||
import com.android.email.ControllerResultUiThreadWrapper;
|
||||
import com.android.email.Utility;
|
||||
import com.android.email.mail.Address;
|
||||
import com.android.email.mail.MeetingInfo;
|
||||
|
@ -89,7 +89,10 @@ import java.util.regex.Pattern;
|
|||
public class MessageView extends Activity implements OnClickListener {
|
||||
private static final String EXTRA_MESSAGE_ID = "com.android.email.MessageView_message_id";
|
||||
private static final String EXTRA_MAILBOX_ID = "com.android.email.MessageView_mailbox_id";
|
||||
/* package */ static final String EXTRA_DISABLE_REPLY = "com.android.email.MessageView_disable_reply";
|
||||
private static final String EXTRA_ORIGINAL_MAILBOX_ID =
|
||||
"com.android.email.MessageView_original_mailbox_id";
|
||||
/* package */ static final String EXTRA_DISABLE_REPLY =
|
||||
"com.android.email.MessageView_disable_reply";
|
||||
|
||||
// for saveInstanceState()
|
||||
private static final String STATE_MESSAGE_ID = "messageId";
|
||||
|
@ -141,6 +144,8 @@ public class MessageView extends Activity implements OnClickListener {
|
|||
private long mMailboxId;
|
||||
private Message mMessage;
|
||||
private long mWaitForLoadMessageId;
|
||||
// Set to true for messages that are attachments
|
||||
private boolean mAttachmentMessageFlag = false;
|
||||
|
||||
private LoadMessageTask mLoadMessageTask;
|
||||
private LoadBodyTask mLoadBodyTask;
|
||||
|
@ -384,6 +389,10 @@ public class MessageView extends Activity implements OnClickListener {
|
|||
mMessageContentView.destroy();
|
||||
mMessageContentView = null;
|
||||
// the cursor was closed in onPause()
|
||||
// If we're leaving a non-attachment message, delete any/all attachment messages
|
||||
if (!mAttachmentMessageFlag) {
|
||||
mController.deleteAttachmentMessages();
|
||||
}
|
||||
}
|
||||
|
||||
private void onDelete() {
|
||||
|
@ -875,7 +884,6 @@ public class MessageView extends Activity implements OnClickListener {
|
|||
* @param attachment A single attachment loaded from the provider
|
||||
*/
|
||||
private void addAttachment(Attachment attachment) {
|
||||
|
||||
AttachmentInfo attachmentInfo = new AttachmentInfo();
|
||||
attachmentInfo.size = attachment.mSize;
|
||||
attachmentInfo.contentType =
|
||||
|
@ -1056,18 +1064,41 @@ public class MessageView extends Activity implements OnClickListener {
|
|||
|
||||
private long mId;
|
||||
private boolean mOkToFetch;
|
||||
private Uri mIntentUri;
|
||||
|
||||
/**
|
||||
* Special constructor to cache some local info
|
||||
*/
|
||||
public LoadMessageTask(long messageId, boolean okToFetch) {
|
||||
mIntentUri = getIntent().getData();
|
||||
mId = messageId;
|
||||
mOkToFetch = okToFetch;
|
||||
mAttachmentMessageFlag = (mIntentUri != null);
|
||||
}
|
||||
|
||||
/**
|
||||
* There will either be a Uri in the Intent (i.e. whose content is the Message to be
|
||||
* loaded), or mId will be holding the id of the Message as stored in the provider.
|
||||
* If we're loading via Uri, the Controller does the actual message parsing and storage,
|
||||
* and we setup the message id and mailbox id based on the result; forward and reply are
|
||||
* disabled for messages loaded via Uri
|
||||
*/
|
||||
@Override
|
||||
protected Message doInBackground(Void... params) {
|
||||
if (mId == Long.MIN_VALUE) {
|
||||
// If we have a URI, then we were opened via an intent filter (e.g. an attachment that
|
||||
// has a mime type that we can handle (e.g. message/rfc822).
|
||||
if (mIntentUri != null) {
|
||||
final Activity activity = MessageView.this;
|
||||
// Put up a toast; this can take a little while...
|
||||
Utility.showToast(activity, R.string.message_view_parse_message_toast);
|
||||
Message msg = mController.loadMessageFromUri(mIntentUri);
|
||||
if (msg == null) {
|
||||
// Indicate that the attachment couldn't be loaded
|
||||
Utility.showToast(activity, R.string.message_view_display_attachment_toast);
|
||||
return null;
|
||||
}
|
||||
return msg;
|
||||
} else if (mId == Long.MIN_VALUE) {
|
||||
return null;
|
||||
}
|
||||
return Message.restoreMessageWithId(MessageView.this, mId);
|
||||
|
@ -1094,6 +1125,9 @@ public class MessageView extends Activity implements OnClickListener {
|
|||
}
|
||||
return;
|
||||
}
|
||||
mMessageId = message.mId;
|
||||
mMailboxId = message.mMailboxKey;
|
||||
mDisableReplyAndForward = mIntentUri != null;
|
||||
reloadUiFromMessage(message, mOkToFetch);
|
||||
startPresenceCheck();
|
||||
}
|
||||
|
|
|
@ -423,7 +423,7 @@ public class MimeMessage extends Message {
|
|||
return;
|
||||
}
|
||||
if (mExtendedHeader == null) {
|
||||
mExtendedHeader = new MimeHeader();
|
||||
mExtendedHeader = new MimeHeader();
|
||||
}
|
||||
mExtendedHeader.setHeader(name, END_OF_LINE.matcher(value).replaceAll(""));
|
||||
}
|
||||
|
@ -433,7 +433,7 @@ public class MimeMessage extends Message {
|
|||
*
|
||||
* @param name Extended header name
|
||||
* @return header value - null if header does not exist
|
||||
* @throws MessagingException
|
||||
* @throws MessagingException
|
||||
*/
|
||||
public String getExtendedHeader(String name) throws MessagingException {
|
||||
if (mExtendedHeader == null) {
|
||||
|
|
|
@ -935,7 +935,7 @@ public class Pop3Store extends Store {
|
|||
}
|
||||
}
|
||||
|
||||
class Pop3Message extends MimeMessage {
|
||||
public static class Pop3Message extends MimeMessage {
|
||||
public Pop3Message(String uid, Pop3Folder folder) throws MessagingException {
|
||||
mUid = uid;
|
||||
mFolder = folder;
|
||||
|
@ -947,7 +947,7 @@ public class Pop3Store extends Store {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected void parse(InputStream in) throws IOException, MessagingException {
|
||||
public void parse(InputStream in) throws IOException, MessagingException {
|
||||
super.parse(in);
|
||||
}
|
||||
|
||||
|
|
|
@ -2003,6 +2003,10 @@ public abstract class EmailContent {
|
|||
public static final int TYPE_TASKS = 0x43;
|
||||
public static final int TYPE_EAS_ACCOUNT_MAILBOX = 0x44;
|
||||
|
||||
public static final int TYPE_NOT_SYNCABLE = 0x100;
|
||||
// A mailbox that holds Messages that are attachments
|
||||
public static final int TYPE_ATTACHMENT = 0x101;
|
||||
|
||||
// Bit field flags
|
||||
public static final int FLAG_HAS_CHILDREN = 1<<0;
|
||||
public static final int FLAG_CHILDREN_VISIBLE = 1<<1;
|
||||
|
|
|
@ -1737,7 +1737,6 @@ public class SyncManager extends Service implements Runnable {
|
|||
public void onCreate() {
|
||||
synchronized (sSyncLock) {
|
||||
alwaysLog("!!! EAS SyncManager, onCreate");
|
||||
// If we're in the process of shutting down, try again in 5 seconds
|
||||
if (sStop) {
|
||||
return;
|
||||
}
|
||||
|
@ -2187,15 +2186,24 @@ public class SyncManager extends Service implements Runnable {
|
|||
serviceRequest(mailboxId, 5*SECONDS, reason);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a boolean indicating whether the mailbox can be synced
|
||||
* @param m the mailbox
|
||||
* @return whether or not the mailbox can be synced
|
||||
*/
|
||||
static /*package*/ boolean isSyncable(Mailbox m) {
|
||||
if (m == null || m.mType == Mailbox.TYPE_DRAFTS || m.mType == Mailbox.TYPE_OUTBOX ||
|
||||
m.mType >= Mailbox.TYPE_NOT_SYNCABLE) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static public void serviceRequest(long mailboxId, long ms, int reason) {
|
||||
SyncManager syncManager = INSTANCE;
|
||||
if (syncManager == null) return;
|
||||
Mailbox m = Mailbox.restoreMailboxWithId(syncManager, mailboxId);
|
||||
// Never allow manual start of Drafts or Outbox via serviceRequest
|
||||
if (m == null || m.mType == Mailbox.TYPE_DRAFTS || m.mType == Mailbox.TYPE_OUTBOX) {
|
||||
log("Ignoring serviceRequest for drafts/outbox/null mailbox");
|
||||
return;
|
||||
}
|
||||
if (!isSyncable(m)) return;
|
||||
try {
|
||||
AbstractSyncService service = syncManager.mServiceMap.get(mailboxId);
|
||||
if (service != null) {
|
||||
|
|
|
@ -16,16 +16,23 @@
|
|||
|
||||
package com.android.email;
|
||||
|
||||
import com.android.email.mail.MessagingException;
|
||||
import com.android.email.mail.transport.Rfc822Output;
|
||||
import com.android.email.provider.EmailContent;
|
||||
import com.android.email.provider.EmailProvider;
|
||||
import com.android.email.provider.ProviderTestUtils;
|
||||
import com.android.email.provider.EmailContent.Account;
|
||||
import com.android.email.provider.EmailContent.Body;
|
||||
import com.android.email.provider.EmailContent.Mailbox;
|
||||
import com.android.email.provider.EmailContent.Message;
|
||||
|
||||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
import android.test.ProviderTestCase2;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
|
@ -282,6 +289,63 @@ public class ControllerProviderOpsTests extends ProviderTestCase2<EmailProvider>
|
|||
assertFalse(message1get.mFlagFavorite);
|
||||
}
|
||||
|
||||
public void testGetAndDeleteAttachmentMailbox() {
|
||||
Controller ct = new TestController(mProviderContext, mContext);
|
||||
Mailbox box = ct.getAttachmentMailbox();
|
||||
assertNotNull(box);
|
||||
Mailbox anotherBox = ct.getAttachmentMailbox();
|
||||
assertNotNull(anotherBox);
|
||||
// We should always get back the same Mailbox row
|
||||
assertEquals(box.mId, anotherBox.mId);
|
||||
// Add two messages to this mailbox
|
||||
ProviderTestUtils.setupMessage("message1", 0, box.mId, false, true,
|
||||
mProviderContext);
|
||||
ProviderTestUtils.setupMessage("message2", 0, box.mId, false, true,
|
||||
mProviderContext);
|
||||
// Make sure we can find them where they are expected
|
||||
assertEquals(2, EmailContent.count(mProviderContext, Message.CONTENT_URI,
|
||||
Message.MAILBOX_KEY + "=?", new String[] {Long.toString(box.mId)}));
|
||||
// Delete them
|
||||
ct.deleteAttachmentMessages();
|
||||
// Make sure they're gone
|
||||
assertEquals(0, EmailContent.count(mProviderContext, Message.CONTENT_URI,
|
||||
Message.MAILBOX_KEY + "=?", new String[] {Long.toString(box.mId)}));
|
||||
}
|
||||
|
||||
public void testLoadMessageFromUri() throws IOException, MessagingException {
|
||||
// Create a simple message
|
||||
Message msg = new Message();
|
||||
String text = "This is some text";
|
||||
msg.mText = text;
|
||||
String sender = "sender@host.com";
|
||||
msg.mFrom = sender;
|
||||
// Save this away
|
||||
msg.save(mProviderContext);
|
||||
|
||||
// Write out the message in rfc822 format
|
||||
File outputFile = File.createTempFile("message", "tmp", mContext.getFilesDir());
|
||||
assertNotNull(outputFile);
|
||||
FileOutputStream outputStream = new FileOutputStream(outputFile);
|
||||
Rfc822Output.writeTo(mProviderContext, msg.mId, outputStream, false, false);
|
||||
outputStream.close();
|
||||
|
||||
// Load the message via Controller and a Uri
|
||||
Controller ct = new TestController(mProviderContext, mContext);
|
||||
Message loadedMsg = ct.loadMessageFromUri(Uri.fromFile(outputFile));
|
||||
|
||||
// Check server id, mailbox key, account key, and from
|
||||
assertNotNull(loadedMsg);
|
||||
assertTrue(loadedMsg.mServerId.startsWith(Controller.ATTACHMENT_MESSAGE_UID_PREFIX));
|
||||
Mailbox box = ct.getAttachmentMailbox();
|
||||
assertNotNull(box);
|
||||
assertEquals(box.mId, loadedMsg.mMailboxKey);
|
||||
assertEquals(0, loadedMsg.mAccountKey);
|
||||
assertEquals(loadedMsg.mFrom, sender);
|
||||
// Check body text
|
||||
String loadedMsgText = Body.restoreBodyTextWithMessageId(mProviderContext, loadedMsg.mId);
|
||||
assertEquals(text, loadedMsgText);
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: releasing associated data (e.g. attachments, embedded images)
|
||||
*/
|
||||
|
|
|
@ -211,4 +211,24 @@ public class SyncManagerAccountTests extends AccountTestCase {
|
|||
assertEquals(0, errorMap.keySet().size());
|
||||
}
|
||||
|
||||
public void testIsSyncable() {
|
||||
Context context = mMockContext;
|
||||
Account acct1 = ProviderTestUtils.setupAccount("acct1", true, context);
|
||||
Mailbox box1 = ProviderTestUtils.setupMailbox("box1", acct1.mId, true, context,
|
||||
Mailbox.TYPE_DRAFTS);
|
||||
Mailbox box2 = ProviderTestUtils.setupMailbox("box2", acct1.mId, true, context,
|
||||
Mailbox.TYPE_OUTBOX);
|
||||
Mailbox box3 = ProviderTestUtils.setupMailbox("box2", acct1.mId, true, context,
|
||||
Mailbox.TYPE_ATTACHMENT);
|
||||
Mailbox box4 = ProviderTestUtils.setupMailbox("box2", acct1.mId, true, context,
|
||||
Mailbox.TYPE_NOT_SYNCABLE + 64);
|
||||
Mailbox box5 = ProviderTestUtils.setupMailbox("box2", acct1.mId, true, context,
|
||||
Mailbox.TYPE_MAIL);
|
||||
assertFalse(SyncManager.isSyncable(null));
|
||||
assertFalse(SyncManager.isSyncable(box1));
|
||||
assertFalse(SyncManager.isSyncable(box2));
|
||||
assertFalse(SyncManager.isSyncable(box3));
|
||||
assertFalse(SyncManager.isSyncable(box4));
|
||||
assertTrue(SyncManager.isSyncable(box5));
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue