您的位置:首页 > 移动开发 > Android开发

android 原生 电子邮件 应用 发送邮件附带 中文名附件时 附件名称乱码问题解决

2015-01-15 00:00 495 查看
摘要: 原生 电子邮件 应用 发送邮件附带 中文名附件时 收到邮件的邮箱显示的中文附件名称会乱码,而且查看Email 应用中已发邮件 中的附件,也是乱码。就此贴出解决方法,及分析。。。希望对后面做这一块的同胞有所帮助,时间有限,忙里偷闲写的,技术同胞如果有别的发现,请委婉 吐槽。。。^_^

编写好邮件点击发送,代码执行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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  android Email 电子邮件
相关文章推荐