Android4.0 Message 中添加附件

一,基本情况
不说废话,先直接上图,大致情况就是,在一则New Message中添加一些附件(图片,视频,声音等)和信息一起发送,如下图;Android4.0 Message 中添加附件_第1张图片

二,基本思路    

其实,这就类似于我们的拍照上传,是采用一样的处理方法,这里选择临时拍一张照片作为一起发送的附件,即上图中的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)方法来处理返回的数据;

三,具体流程

首先,我们已经启动Message-->New Message-->Attachment,在Message主活动ComposeMessageActivity中有一个addAttachment()方法来实现为新信息添加附件;

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
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:<span></span><span></span> 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。

在Camera中会进行正常的onCreate()-->Open Camera-->Preview,在此处会有一个不同之处,

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
     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);
         }
         ……
     }
?
1
2
3
4
    private boolean isImageCaptureIntent() {
        String action = getIntent().getAction();
        return (MediaStore.ACTION_IMAGE_CAPTURE.equals(action));
    }

从上面代码可以看出,Camera会判断当前的action,若为ACTION_IMAGE_CAPTURE,isImageCaptureIntent()会返回true,这时显示的界面也会有所不同。

接下来就是Shutter键进行拍照,都知道正常拍照后会回到PictureCallback中的onPictureTaken()方法,再次Preview,保存图片等一些事务处理,而在这里也会回到onPictureTaken(),但有一些不同,不再Preview,而是停留在拍照的画面;

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
        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();
                }
            }
 
             ……
         }
?
1
mQuickCapture = getIntent().getBooleanExtra(EXTRA_QUICK_CAPTURE, false );

从前面我们已经知道mIsImageCaptureIntent()返回true,取反则代码会直接运行else语句,这时我们来到showPostCaptureAlert()方法,onCreate方法中mQuickCapture默认会是false。

?
1
2
3
4
5
6
7
8
9
10
11
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";

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@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()方法,仔细的人会发现这个方法我们之前看到过。


?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
private void doAttach() {
     if (mPausing) {
         return ;
     } <span></span> 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);
     }
}
?
1
2
3
4
5
6
7
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。

?
1
2
3
4
protected void setResultEx( int resultCode) {
     mResultCodeForTesting = resultCode;
     setResult(resultCode);
}

setResult()方法终于出现了,至此,Camera的功能已经完成。

然后,我们继续回到ComposeMessageActivity,来到onActivityResult();

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
     @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。

你可能感兴趣的:(UI,android)