从0开始认识android(六):启动系统相机拍照、摄像的Intent

1、启动系统相机
1.1、只是简单的获取所拍照片的缩略图

启动相机

static final int REQUEST_IMAGE_CAPTURE = 1;

private void dispatchTakePictureIntent() { 
    Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
    if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
        startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE);
    } 
}

获取缩略图

@Override 
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (requestCode == REQUEST_IMAGE_CAPTURE && resultCode == RESULT_OK) {
        Bundle extras = data.getExtras();
        Bitmap imageBitmap = (Bitmap) extras.get("data");
        mImageView.setImageBitmap(imageBitmap);
    } 
}

1.2、获取所拍的全尺寸照片文件
必须的权限
< 
uses-permission android:name=”android.permission.WRITE_EXTERNAL_STORAGE” />
这里的全尺寸是相对于上面的缩略图来讲的,这里为什么需要读取储存的权限呢?因为我们要获取所拍照片的文件的话需要给启动相机的intent传入一个文件以储存所拍的照片,到时候我们读取这个文件就可以了。
如果你APP拍的照片可以让其他应用读写,那么这个文件路径可以用系统公共的图片路径:

Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);

如果你想APP拍的照片只能自己读写,即其他应用和系统相册都无法读写,那么用以下的路径:

getExternalFilesDir(Environment.DIRECTORY_PICTURES);

确定了文件路径,还要保证文件名不能重复:

String mCurrentPhotoPath;

private File createImageFile() throws IOException {
        // 唯一的文件名称
        String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
        String imageFileName = "JPEG_" + timeStamp + "_";
        //        File publicDirectory = Environment.getExternalStoragePublicDirectory
        //                (Environment.DIRECTORY_PICTURES);
        File storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES);
        File image = File.createTempFile(
                imageFileName,  /* 文件名前缀 */
                ".jpg",         /* 文件名后缀 */
                storageDir      /* 路径 */
        );

        // mCurrentPhotoPath下面会被发送到系统相册里去显示
        mCurrentPhotoPath = image.getAbsolutePath();
        return image;
    }

启动相机

static final int REQUEST_TAKE_PHOTO = 2;

    private void dispatchTakePictureIntent() {
    //action为MediaStore.ACTION_IMAGE_CAPTURE
        Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
            // 保存所拍照片的文件
            File photoFile = null;
            try {
                photoFile = createImageFile();
            } catch (IOException ex) {
                //
            }
            if (photoFile != null) {
                //这里为了兼容7.0以下的设备,需要在清单文件中定义一个FileProvider,这里的
                //com.jackbear.notificationtimer.fileprovider要和FileProvider中的authorities相同,如下图
                Uri photoURI = FileProvider.getUriForFile(this,
                        "com.jackbear.notificationtimer.fileprovider",
                        photoFile);
                //如果photoFile路径是公共的系统图片路径即通过Environment.getExternalStoragePublicDirectory
                //(Environment.DIRECTORY_PICTURES)获取的话则不能用FileProvider的方式了,否则会异常
//                Uri photoURI = Uri.fromFile(photoFile);
                takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI);
                startActivityForResult(takePictureIntent, REQUEST_TAKE_PHOTO);
            }
        }

    }

清单文件中的FileProvider

<application>
   ...
   <provider
            android:name="android.support.v4.content.FileProvider"
            android:authorities="com.jackbear.notificationtimer.fileprovider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/file_paths"></meta-data>
        </provider>
    ...
</application>

上面FileProvider的@xml/file_paths路径为res/xml/file_paths.xml,内容如下:

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <external-path name="my_images"
                   path="Android/data/com.jackbear.notificationtimer/files/Pictures" />
</paths>

其中com.jackbear.notificationtime为你的包名,当你获取文件路径传入Environment.DIRECTORY_PICTURES获取的就是上面这个路径。
上面我们用于保存所拍照的文件的路径是通过getExternalFilesDir(Environment.DIRECTORY_PICTURES);获取的,即这个文件是在我们app私有的空间里的,哪怕我们打开系统相册都是无法看到的,那怎样让我们拍摄的照片在系统相册里也能看到呢?
首先,将保存照片的文件路径换为公共的图片路径,即通过以下方式获取:

Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);

其次,通过以下方式将我们的文件路径发送给系统相册:

private void galleryAddPic() {
        Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
        //mCurrentPhotoPath即文件的路径
        File f = new File(mCurrentPhotoPath);
        Uri contentUri = Uri.fromFile(f);
        mediaScanIntent.setData(contentUri);
        this.sendBroadcast(mediaScanIntent);
    }

显示拍摄的照片

@Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (resultCode == RESULT_OK) {
            switch (requestCode) {
                case REQUEST_TAKE_PHOTO:
                    //将照片插入系统相册
                    galleryAddPic();
                    //显示图片
                    setPic();
                    break;
                default:
                    break;
            }
        }
    }

为了避免oom,setPic()函数对照片进行了缩放显示

private void setPic() {
        // 获取控件尺寸
        int targetW = mImageView.getWidth();
        int targetH = mImageView.getHeight();

        // 获取照片bitmap对象尺寸
        BitmapFactory.Options bmOptions = new BitmapFactory.Options();
        bmOptions.inJustDecodeBounds = true;
        BitmapFactory.decodeFile(mCurrentPhotoPath, bmOptions);
        int photoW = bmOptions.outWidth;
        int photoH = bmOptions.outHeight;

        // 计算缩放比例
        int scaleFactor = Math.min(photoW/targetW, photoH/targetH);

        // 按缩放比例解析出照片文件
        bmOptions.inJustDecodeBounds = false;
        bmOptions.inSampleSize = scaleFactor;
        bmOptions.inPurgeable = true;

        Bitmap bitmap = BitmapFactory.decodeFile(mCurrentPhotoPath, bmOptions);
        mImageView.setImageBitmap(bitmap);
    }

1.3、以视频模式启动相机
拍摄视频的话,系统会默认把你APP拍摄的视频插入相册里了。

static final int REQUEST_VIDEO_CAPTURE = 1;

private void dispatchTakeVideoIntent() {
//action为MediaStore.ACTION_VIDEO_CAPTURE 
    Intent takeVideoIntent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);
    if (takeVideoIntent.resolveActivity(getPackageManager()) != null) {
        startActivityForResult(takeVideoIntent, REQUEST_VIDEO_CAPTURE);
    } 
}

查看所拍视频

@Override 
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
    if (requestCode == REQUEST_VIDEO_CAPTURE && resultCode == RESULT_OK) {
        Uri videoUri = intent.getData();
        mVideoView.setVideoURI(videoUri);
    } 
}

猜你喜欢

转载自blog.csdn.net/jack_bear_csdn/article/details/80430889