Android4.0 Message 中添加附件

一,基本狀況
不說廢話,先直接上圖,大體狀況就是,在一則New Message中添加一些附件(圖片,視頻,聲音等)和信息一塊兒發送,以下圖; java

二,基本思路     android

其實,這就相似於咱們的拍照上傳,是採用同樣的處理方法,這裏選擇臨時拍一張照片做爲一塊兒發送的附件,即上圖中的Capture Picture。主要步驟: 異步

    1)點擊Capture Picture時,會啓動系統Camera應用程序來拍照;主要使用startActivityForResult(Intent intent, int requestCode)方法來啓動Camera程序;
    2)拍攝照片;這裏就是用Camera進行拍照,這裏不作介紹;
    3)保存照片,並將照片數據返回給Message應用;主要用到一個setResult(int resultCode, Intent intent)方法,返回到原調用程序,關閉Camera;
    4)在Message應用中處理返回的數據;重寫onActivityResult(int requestCode, int resultCode, Intent data)方法來處理返回的數據; ide

三,具體流程 佈局

首先,咱們已經啓動Message-->New Message-->Attachment,在Message主活動ComposeMessageActivity中有一個addAttachment()方法來實現爲新信息添加附件; ui

private void addAttachment(int type, boolean replace) {
    switch (type) {
            case AttachmentTypeSelectorAdapter.ADD_IMAGE:
                /* TODO */
                break;

            case AttachmentTypeSelectorAdapter.TAKE_PICTURE: {
                Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
                intent.putExtra(MediaStore.EXTRA_OUTPUT, TempFileProvider.SCRAP_CONTENT_URI);
                startActivityForResult(intent, REQUEST_CODE_TAKE_PICTURE);
                break;
            }

            case AttachmentTypeSelectorAdapter.ADD_VIDEO: break;

            case AttachmentTypeSelectorAdapter.RECORD_VIDEO: {                
                break;

            case AttachmentTypeSelectorAdapter.ADD_SOUND:
                break;

            case AttachmentTypeSelectorAdapter.RECORD_SOUND:
                break;

            case AttachmentTypeSelectorAdapter.ADD_SLIDESHOW:
                break;

            default:
                break;
        }

新建一個 MediaStore.ACTION_IMAGE_CAPTURE 意圖的Intent,ACTION_IMAGE_CAPTURE 的定義爲"android.media.action.IMAGE_CAPTURE",這就時告訴系統,要進行抓取圖片,調用startActivityForResult()啓動Camera。 this

在Camera中會進行正常的onCreate()-->Open Camera-->Preview,在此處會有一個不一樣之處, spa

public void onCreate(Bundle icicle) {
        super.onCreate(icicle);
        ……

        mIsImageCaptureIntent = isImageCaptureIntent();
        setContentView(R.layout.camera);
        if (mIsImageCaptureIntent) {			
            mReviewDoneButton = (Rotatable) findViewById(R.id.btn_done);
            mReviewCancelButton = (Rotatable) findViewById(R.id.btn_cancel);
            findViewById(R.id.btn_cancel).setVisibility(View.VISIBLE);
        } else {			        
            mThumbnailView = (RotateImageView) findViewById(R.id.thumbnail);
            mThumbnailView.enableFilter(false);
            mThumbnailView.setVisibility(View.VISIBLE);
        }
        ……
    }
    private boolean isImageCaptureIntent() {
        String action = getIntent().getAction();
        return (MediaStore.ACTION_IMAGE_CAPTURE.equals(action));
    }

從上面代碼能夠看出,Camera會判斷當前的action,若爲ACTION_IMAGE_CAPTURE,isImageCaptureIntent()會返回true,這時顯示的界面也會有所不一樣。 code

接下來就是Shutter鍵進行拍照,都知道正常拍照後會回到PictureCallback中的onPictureTaken()方法,再次Preview,保存圖片等一些事務處理,而在這裏也會回到onPictureTaken(),但有一些不一樣,再也不Preview,而是停留在拍照的畫面; 視頻

        public void onPictureTaken
            ……

            if (!mIsImageCaptureIntent) {
                startPreview();
                startFaceDetection();
            }
            if (!mIsImageCaptureIntent) {
                Size s = mParameters.getPictureSize();
                mImageSaver.addImage(jpegData, mLocation, s.width, s.height);
            } else {
                mJpegImageData = jpegData;  
                if (!mQuickCapture) {
                    showPostCaptureAlert();
                } else {                  
                    doAttach();
                }
            }

            ……
        }
mQuickCapture = getIntent().getBooleanExtra(EXTRA_QUICK_CAPTURE, false);

從前面咱們已經知道mIsImageCaptureIntent()返回true,取反則代碼會直接運行else語句,這時咱們來到showPostCaptureAlert()方法,onCreate方法中mQuickCapture默認會是false。

private void showPostCaptureAlert() {
        if (mIsImageCaptureIntent) {
            Util.fadeOut(mIndicatorControlContainer);
            Util.fadeOut(mShutterButton);

            int[] pickIds = {R.id.btn_retake, R.id.btn_done};
            for (int id : pickIds) {			
                Util.fadeIn(findViewById(id));
            }
        }
    }
到這裏,咱們仍是會看到mIsImageCaptureIntent,看來 mIsImageCaptureIntent始終貫徹整個過程,時咱們區別正常Camera拍照的根本所在,在showPostCaptureAlert()中將咱們的Shutter鍵改爲R.id.btn_retake,另外新加一個R.id.btn_done,這是一個選擇當前照片的ImageButton,其佈局文件xml中配置了一個點擊方法android:onClick="onReviewDoneClicked";

@OnClickAttr
    public void onReviewRetakeClicked(View v) {
        hidePostCaptureAlert();
        startPreview();
        startFaceDetection();
    }

    @OnClickAttr
    public void onReviewDoneClicked(View v) {
        doAttach();
    }

    @OnClickAttr
    public void onReviewCancelClicked(View v) {
        doCancel();
    }
其實,不僅是btn_done,其餘的兩個按鈕btn_retake,btn_cacel都配置了相應的點擊方法,因此咱們最終仍是回到了doAttach()方法,仔細的人會發現這個方法咱們以前看到過。


private void doAttach() {
        if (mPausing) {
            return;
        }  byte[] data = mJpegImageData;

        if (mCropValue == null) {
            // First handle the no crop case -- just return the value.  If the
            // caller specifies a "save uri" then write the data to it's
            // stream. Otherwise, pass back a scaled down version of the bitmap
            // directly in the extras.
            if (mSaveUri != null) {
                OutputStream outputStream = null;
                try {
                    outputStream = mContentResolver.openOutputStream(mSaveUri);
                    outputStream.write(data);
                    outputStream.close();

                    setResultEx(RESULT_OK);
                    finish();
                } catch (IOException ex) {
                    // ignore exception
                } finally {
                    Util.closeSilently(outputStream);
                }
            } else {
                int orientation = Exif.getOrientation(data);
                Bitmap bitmap = Util.makeBitmap(data, 50 * 1024);
                bitmap = Util.rotate(bitmap, orientation);
                setResultEx(RESULT_OK,
                        new Intent("inline-data").putExtra("data", bitmap));
                finish();
            }
        } else {
            // Save the image to a temp file and invoke the cropper
            Uri tempUri = null;
            FileOutputStream tempStream = null;
            try {
                File path = getFileStreamPath(sTempCropFilename);
                path.delete();
                tempStream = openFileOutput(sTempCropFilename, 0);
                tempStream.write(data);
                tempStream.close();
                tempUri = Uri.fromFile(path);
            } catch (FileNotFoundException ex) {
                setResultEx(Activity.RESULT_CANCELED);
                finish();
                return;
            } catch (IOException ex) {
                setResultEx(Activity.RESULT_CANCELED);
                finish();
                return;
            } finally {
                Util.closeSilently(tempStream);
            }

            Bundle newExtras = new Bundle();
            if (mCropValue.equals("circle")) {
                newExtras.putString("circleCrop", "true");
            }
            if (mSaveUri != null) {
                newExtras.putParcelable(MediaStore.EXTRA_OUTPUT, mSaveUri);
            } else {
                newExtras.putBoolean("return-data", true);
            }

            Intent cropIntent = new Intent("com.android.camera.action.CROP");

            cropIntent.setData(tempUri);
            cropIntent.putExtras(newExtras);

            startActivityForResult(cropIntent, CROP_MSG);
        }
    }
private void setupCaptureParams() {
        Bundle myExtras = getIntent().getExtras();
        if (myExtras != null) {
            mSaveUri = (Uri) myExtras.getParcelable(MediaStore.EXTRA_OUTPUT);
            mCropValue = myExtras.getString("crop");
        }
    }

mCropValue爲null,至於mSaveUri在onCreate()方法中會調用一個setupCaptureParams()方法,取得Uri;這時會執行setResultEx(RESULT_OK),並調用 finish()關閉Camera。

protected void setResultEx(int resultCode) {
        mResultCodeForTesting = resultCode;
        setResult(resultCode);
    }

setResult()方法終於出現了,至此,Camera的功能已經完成。

而後,咱們繼續回到ComposeMessageActivity,來到onActivityResult();

@Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        ……
    
        switch (requestCode) {
            case REQUEST_CODE_CREATE_SLIDESHOW:
                if (data != null) {
                    WorkingMessage newMessage = WorkingMessage.load(this, data.getData());
                    if (newMessage != null) {
                        mWorkingMessage = newMessage;
                        mWorkingMessage.setConversation(mConversation);
                        drawTopPanel(false);
                        updateSendButtonState();
                        invalidateOptionsMenu();
                    }
                }
                break;
 
            case REQUEST_CODE_TAKE_PICTURE: {
                // create a file based uri and pass to addImage(). We want to read the JPEG
                // data directly from file (using UriImage) instead of decoding it into a Bitmap,
                // which takes up too much memory and could easily lead to OOM.

                File file = new File(TempFileProvider.getScrapPath(this));
                Uri uri = Uri.fromFile(file);
                addImageAsync(uri, false);
                break;
            }

            ……
        }
    }
再次switch (requestCode),case REQUEST_CODE_TAKE_PICTURE,這也是咱們最初startActivityForResult()中發送的參數,最終回到Capture Picture的處理:

1) TempFileProvider.getScrapPath(this)獲取媒體文件的路徑,我打印了絕對路徑,一看結果我想你們都懂了,這是一個系統隱藏文件.temp.jpg
/mnt/sdcard/Android/data/com.android.mms/cache/.temp.jpg

2)調用addImageAsync(uri, false)方法異步加載圖片到Message。

相關文章
相關標籤/搜索