android 原生 電子郵件 應用 發送郵件附帶 中文名附件時 附件名稱亂碼問題解決

編寫好郵件點擊發送,代碼執行MessageCompose.java 中的(郵件的編寫,及添加附件都在這個類中處理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 數據解析處理模塊。下面看對附件部分的解析。android

 @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 數據的時候對附件名稱作了處理那麼。在顯示名稱時固然也要解密api

以下:ide

@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中oop

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

而後ui

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 中有一個
this

 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

相關文章
相關標籤/搜索