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

编写好邮件点击发送,代码执行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


转载于:https://my.oschina.net/u/563014/blog/368150

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值