编写好邮件点击发送,代码执行MessageCompose.java 中的(邮件的编写,及添加附件都在这个类中处理)
private void sendOrSaveMessage(boolean send) { if (!mMessageLoaded) { Log.w(Logging.LOG_TAG, "Attempted to save draft message prior to the state being fully loaded"); return; } synchronized (sActiveSaveTasks) { mLastSaveTaskId = sNextSaveTaskId++; SendOrSaveMessageTask task = new SendOrSaveMessageTask(mLastSaveTaskId, send); // Ensure the tasks are executed serially so that rapid scheduling doesn't result // in inconsistent data.// task.executeSerial(); } }
private class SendOrSaveMessageTask extends EmailAsyncTask<Void, Void, Long> { private final boolean mSend; private final long mTaskId; /** A context that will survive even past activity destruction. */ private final Context mContext; public SendOrSaveMessageTask(long taskId, boolean send) { super(null /* DO NOT cancel in onDestroy */); if (send && ActivityManager.isUserAMonkey()) { Log.d(Logging.LOG_TAG, "Inhibiting send while monkey is in charge."); send = false; } mTaskId = taskId; mSend = send; mContext = getApplicationContext(); sActiveSaveTasks.put(mTaskId, this); } @Override protected Long doInBackground(Void... params) { synchronized (mDraft) { updateMessage(mDraft, mAccount, mAttachments.size() > 0, mSend); ContentResolver resolver = getContentResolver(); if (mDraft.isSaved()) { // Update the message Uri draftUri = ContentUris.withAppendedId(Message.SYNCED_CONTENT_URI, mDraft.mId); resolver.update(draftUri, getUpdateContentValues(mDraft), null, null); // Update the body ContentValues values = new ContentValues(); values.put(BodyColumns.TEXT_CONTENT, mDraft.mText); values.put(BodyColumns.TEXT_REPLY, mDraft.mTextReply); values.put(BodyColumns.HTML_REPLY, mDraft.mHtmlReply); values.put(BodyColumns.INTRO_TEXT, mDraft.mIntroText); values.put(BodyColumns.SOURCE_MESSAGE_KEY, mDraft.mSourceKey); Body.updateBodyWithMessageId(MessageCompose.this, mDraft.mId, values); } else { // mDraft.mId is set upon return of saveToMailbox() mController.saveToMailbox(mDraft, Mailbox.TYPE_DRAFTS); } // For any unloaded attachment, set the flag saying we need it loaded boolean hasUnloadedAttachments = false; //mAttachments 处理附件部分 -----开始 for (Attachment attachment : mAttachments) { if (attachment.mContentUri == null && ((attachment.mFlags & Attachment.FLAG_SMART_FORWARD) == 0)) { attachment.mFlags |= Attachment.FLAG_DOWNLOAD_FORWARD; hasUnloadedAttachments = true; if (Email.DEBUG) { Log.d(Logging.LOG_TAG, "Requesting download of attachment #" + attachment.mId); } } // Make sure the UI version of the attachment has the now-correct id; we will // use the id again when coming back from picking new attachments if (!attachment.isSaved()) { // this attachment is new so save it to DB. attachment.mMessageKey = mDraft.mId; attachment.save(MessageCompose.this); } else if (attachment.mMessageKey != mDraft.mId) { // We clone the attachment and save it again; otherwise, it will // continue to point to the source message. From this point forward, // the attachments will be independent of the original message in the // database; however, we still need the message on the server in order // to retrieve unloaded attachments attachment.mMessageKey = mDraft.mId; //attachment.toContentValues()是最重要的,因为在toContentValues()这里 是将所有关于附件的信息都put 到了 //ContentValues 中,然后执行 insert后,发送的邮件附件信息就存储在了数据表中,也就是在toContentValues中的时候 //中文名就会出现解码 乱码问题,具体看下面贴出的代码部分。 ContentValues cv = attachment.toContentValues(); cv.put(Attachment.FLAGS, attachment.mFlags); cv.put(Attachment.MESSAGE_KEY, mDraft.mId); getContentResolver().insert(Attachment.CONTENT_URI, cv); } } //处理附件部分 -----结束 if (mSend) { // Let the user know if message sending might be delayed by background // downlading of unloaded attachments if (hasUnloadedAttachments) { Utility.showToast(MessageCompose.this, R.string.message_view_attachment_background_load); } mController.sendMessage(mDraft); ArrayList<CharSequence> addressTexts = new ArrayList<CharSequence>(); addressTexts.add(mToView.getText()); addressTexts.add(mCcView.getText()); addressTexts.add(mBccView.getText()); DataUsageStatUpdater updater = new DataUsageStatUpdater(mContext); updater.updateWithRfc822Address(addressTexts); } return mDraft.mId; } } private boolean shouldShowSaveToast() { // Don't show the toast when rotating, or when opening an Activity on top of this one. return !isChangingConfigurations() && !mPickingAttachment; } @Override protected void onSuccess(Long draftId) { // Note that send or save tasks are always completed, even if the activity // finishes earlier. sActiveSaveTasks.remove(mTaskId); // Don't display the toast if the user is just changing the orientation if (!mSend && shouldShowSaveToast()) { Toast.makeText(mContext, R.string.message_saved_toast, Toast.LENGTH_LONG).show(); } } }
就上面附件注释部分说的,附件信息解析并添加到数据表中,主要是在 com.android.emailcommon.provider中的EmailContent中,里面有对个Message 数据解析处理模块。下面看对附件部分的解析。
@Override public ContentValues toContentValues() { Log.i("EmailContent", "toContentValues ----> mFileName: "+mFileName+" mContentUri: "+mContentUri+"===mEncoding==="+mEncoding); //这里就是对 附件 mFileName 为中文时编码处理,否则就会乱码,至于用mEncoding是否为空来判断是否 //对附件名做编码处理,是因为在解决这个问题反复测试发现,如果PC端发邮件,android 应用端接受邮件,mEncoding会 //有编码值,如果这里做了加密及强制转换编码,那么客户端接受到的附件,因为做了下面处理就也会出现乱码,所以我们是 //不处理的。但是客户端发出去邮件时 mEncoding始终会是NULL,最终添加到表中时,Exchange 服务类型的编码会是 //base64,至于在什么地方给处理的没研究太深,POP,IMAP 的 mEncoding却是NULL (我也不知到在哪处理的,没时间研究啊) //如果大家发现不有特殊情况的话,欢迎纠正。。。谢谢啦 if(TextUtils.isEmpty(mEncoding)){ mFileName = MimeUtility.foldAndEncode2(mFileName,"Content-Disposition".length() + 2); } Log.i("EmailContent", "toContentValues --1-->"+ mFileName); ContentValues values = new ContentValues(); values.put(AttachmentColumns.FILENAME, mFileName); values.put(AttachmentColumns.MIME_TYPE, mMimeType); values.put(AttachmentColumns.SIZE, mSize); values.put(AttachmentColumns.CONTENT_ID, mContentId); values.put(AttachmentColumns.CONTENT_URI, mContentUri); values.put(AttachmentColumns.MESSAGE_KEY, mMessageKey); values.put(AttachmentColumns.LOCATION, mLocation); values.put(AttachmentColumns.ENCODING, mEncoding); values.put(AttachmentColumns.CONTENT, mContent); values.put(AttachmentColumns.FLAGS, mFlags); values.put(AttachmentColumns.CONTENT_BYTES, mContentBytes); values.put(AttachmentColumns.ACCOUNT_KEY, mAccountKey); values.put(AttachmentColumns.UI_STATE, mUiState); values.put(AttachmentColumns.UI_DESTINATION, mUiDestination); values.put(AttachmentColumns.UI_DOWNLOADED_SIZE, mUiDownloadedSize); return values; }
对于上面在往表里put 数据的时候对附件名称做了处理那么。在显示名称时当然也要解密
如下:
@Override public void restore(Cursor cursor) { mBaseUri = CONTENT_URI; mId = cursor.getLong(CONTENT_ID_COLUMN); mEncoding = cursor.getString(CONTENT_ENCODING_COLUMN); mFileName= cursor.getString(CONTENT_FILENAME_COLUMN); Log.i("EmailContent", "restore-->mFileName: "+ mFileName+" mEncoding: "+mEncoding); if(TextUtils.isEmpty(mEncoding)){ mFileName = MimeUtility.unfoldAndDecode(mFileName); } Log.i("EmailContent", "restore-->mFileName: "+ mFileName); mMimeType = cursor.getString(CONTENT_MIME_TYPE_COLUMN); mSize = cursor.getLong(CONTENT_SIZE_COLUMN); mContentId = cursor.getString(CONTENT_CONTENT_ID_COLUMN); mContentUri = cursor.getString(CONTENT_CONTENT_URI_COLUMN); mMessageKey = cursor.getLong(CONTENT_MESSAGE_ID_COLUMN); mLocation = cursor.getString(CONTENT_LOCATION_COLUMN); mContent = cursor.getString(CONTENT_CONTENT_COLUMN); mFlags = cursor.getInt(CONTENT_FLAGS_COLUMN); mContentBytes = cursor.getBlob(CONTENT_CONTENT_BYTES_COLUMN); mAccountKey = cursor.getLong(CONTENT_ACCOUNT_KEY_COLUMN); mUiState = cursor.getInt(CONTENT_UI_STATE_COLUMN); mUiDestination = cursor.getInt(CONTENT_UI_DESTINATION_COLUMN); mUiDownloadedSize = cursor.getInt(CONTENT_UI_DOWNLOADED_SIZE_COLUMN); }
以上是针对Exchange 服务 中文乱码问题解决,因为 原生代码中,使用Exchange 登录邮箱,发送邮件,与使用POP,IMAP不是走同一个流程,具体看Controller.java中
public void sendPendingMessages(long accountId) { // 1. make sure we even have an outbox, exit early if not final long outboxId = Mailbox.findMailboxOfType(mProviderContext, accountId, Mailbox.TYPE_OUTBOX); if (outboxId == Mailbox.NO_MAILBOX) { return; } //如果使用的是Exchange 账户service便会得到值,这里是根据accountId判断是哪个服务,否则service便是NULL // 2. dispatch as necessary IEmailService service = getServiceForAccount(accountId); if (service != null) { // Service implementation try { service.startSync(outboxId, false); } catch (RemoteException e) { // TODO Change exception handling to be consistent with however this method // is implemented for other protocols Log.d("updateMailbox", "RemoteException" + e); } } else { // MessagingController implementation sendPendingMessagesSmtp(accountId); } }
再看sendPendingMessagesSmtp() 方法中执行了
mLegacyController.sendPendingMessages(account, sentboxId, mLegacyListener);
然后
public void sendPendingMessagesSynchronous(final Account account, long sentFolderId) { TrafficStats.setThreadStatsTag(TrafficFlags.getSmtpFlags(mContext, account)); NotificationController nc = NotificationController.getInstance(mContext); // 1. Loop through all messages in the account's outbox long outboxId = Mailbox.findMailboxOfType(mContext, account.mId, Mailbox.TYPE_OUTBOX); if (outboxId == Mailbox.NO_MAILBOX) { return; } ContentResolver resolver = mContext.getContentResolver(); Cursor c = resolver.query(EmailContent.Message.CONTENT_URI, EmailContent.Message.ID_COLUMN_PROJECTION, EmailContent.Message.MAILBOX_KEY + "=?", new String[] { Long.toString(outboxId) }, null); try { // 2. exit early if (c.getCount() <= 0) { return; } // 3. do one-time setup of the Sender & other stuff mListeners.sendPendingMessagesStarted(account.mId, -1); //注意,下面这一行便是处理POP,IMAP 服务的Sender 类,该 sender是父类 POP,IMAP最终走的是 //com.android.email.mail.transport包下的SmtpSender类,也就是下面执行的 sender.sendMessage(messageId) //最终是执行的SmtpSender中的sendMessage方法。 Sender sender = Sender.getInstance(mContext, account); Store remoteStore = Store.getInstance(account, mContext); boolean requireMoveMessageToSentFolder = remoteStore.requireCopyMessageToSentFolder(); ContentValues moveToSentValues = null; if (requireMoveMessageToSentFolder) { moveToSentValues = new ContentValues(); moveToSentValues.put(MessageColumns.MAILBOX_KEY, sentFolderId); } boolean faild =false; // 4. loop through the available messages and send them while (c.moveToNext()) { long messageId = -1; try { messageId = c.getLong(0); mListeners.sendPendingMessagesStarted(account.mId, messageId); // Don't send messages with unloaded attachments if (Utility.hasUnloadedAttachments(mContext, messageId)) { if (Email.DEBUG) { Log.d(Logging.LOG_TAG, "Can't send #" + messageId + "; unloaded attachments"); } continue; } sender.sendMessage(messageId); } catch (MessagingException me) { // report error for this message, but keep trying others if (me instanceof AuthenticationFailedException) { nc.showLoginFailedNotification(account.mId); } faild = true; handler.sendEmptyMessage(1); mListeners.sendPendingMessagesFailed(account.mId, messageId, me); continue; } // 5. move to sent, or delete Uri syncedUri = ContentUris.withAppendedId(EmailContent.Message.SYNCED_CONTENT_URI, messageId); if (requireMoveMessageToSentFolder) { // If this is a forwarded message and it has attachments, delete them, as they // duplicate information found elsewhere (on the server). This saves storage. EmailContent.Message msg = EmailContent.Message.restoreMessageWithId(mContext, messageId); if (msg != null && ((msg.mFlags & EmailContent.Message.FLAG_TYPE_FORWARD) != 0)) { AttachmentUtilities.deleteAllAttachmentFiles(mContext, account.mId, messageId); } resolver.update(syncedUri, moveToSentValues, null, null); } else { AttachmentUtilities.deleteAllAttachmentFiles(mContext, account.mId, messageId); Uri uri = ContentUris.withAppendedId(EmailContent.Message.CONTENT_URI, messageId); resolver.delete(uri, null, null); resolver.delete(syncedUri, null, null); } } // 6. report completion/success if(!faild){ handler.sendEmptyMessage(0); } mListeners.sendPendingMessagesCompleted(account.mId); nc.cancelLoginFailedNotification(account.mId); } catch (MessagingException me) { if (me instanceof AuthenticationFailedException) { nc.showLoginFailedNotification(account.mId); } handler.sendEmptyMessage(1); mListeners.sendPendingMessagesFailed(account.mId, -1, me); } finally { c.close(); } }
在 SmtpSender 的sendMessage 中有一个
Rfc822Output.writeTo(mContext, messageId, new EOLConvertingOutputStream(mTransport.getOutputStream()), false /* do not use smart reply */, false /* do not send BCC */);
在这里就是对POP,IMAP 的邮件信息处理,至于这里怎么解决邮件发送 中文名附件出现乱码,就参考下面的网址吧,
偷懒不想写了 ^_^,
http://blog.csdn.net/jaycee110905/article/details/17677931