• 调用相机 Intent intent=new Intent("android.media.action.IMAGE_CAPTURE"); intent.putExtra(MediaStore.EXTRA_OUTPUT,imageUri); startActivityForResult(intent,...

    调用相机

                    Intent intent=new Intent("android.media.action.IMAGE_CAPTURE");
                    intent.putExtra(MediaStore.EXTRA_OUTPUT,imageUri);
                    startActivityForResult(intent,TAKE_PHOTO);

    调用相册两种

    Intent intent = new Intent();
    intent.setAction(Intent.ACTION_PICK);
    // 设置文件类型
    intent.setType("image/*");
    activity.startActivityForResult(intent, requestCode);
    
    
    Intent intent = new Intent();
    intent.setAction(Intent.ACTION_GET_CONTENT);
    // 设置文件类型
    intent.setType("image/*");
    activity.startActivityForResult(intent, requestCode);
    

    详细代码请看(解析封装的uri获取真实图片路径那一块还没看懂,有空看看)

    https://github.com/18668197127/PhotoAndGallery 

     

     两者的区别

    如果你有一些特定的集合(由URI标识)想让用户选择,使用ACTION_PICK
    如果让用户基于MIME Type选择数据,使用ACTION_GET_CONTENT
    在平局的情况下,建议使用ACTION_GET_CONTENT

     

    调用系统的图片剪裁

        //剪裁图片
        protected void startPhotoZoom(Uri uri) {
    
            if (uri == null) {
                Log.i("tag", "The uri is not exist.");
            }
    //        tempUri = uri;
            Intent intent = new Intent("com.android.camera.action.CROP");
            intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
            intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
            intent.setDataAndType(uri, "image/*");
            // 设置裁剪
            intent.putExtra("crop", "true");
            // aspectX aspectY 是宽高的比例
            intent.putExtra("aspectX", 1);
            intent.putExtra("aspectY", 1);
            // outputX outputY 是裁剪图片宽高
            intent.putExtra("outputX", 100);
            intent.putExtra("outputY", 100);
            //true直接返回一个Bitmap
            intent.putExtra("return-data", false);
            //设置格式
            intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
            //是否保留图片比例
            intent.putExtra("scale", true);
            File out = new File(getExternalStorageDirectory(),"crop1.jpg");
            if (out.exists()){
                out.delete();
                try {
                    out.createNewFile();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (Build.VERSION.SDK_INT>=24){
                cropFinishUri=FileProvider.getUriForFile(MainActivity.this,"fileProvider",out);
                //这段代码不知道什么作用,先放着以后研究
                List<ResolveInfo> resInfoList = getPackageManager().queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
                Log.i(TAG, "ResolveInfo的Size: "+resInfoList.size());
                for (ResolveInfo resolveInfo : resInfoList) {
                    String packageName = resolveInfo.activityInfo.packageName;
                    grantUriPermission(packageName, cropFinishUri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION);
                }
            }else {
                cropFinishUri=Uri.fromFile(out);
            }
            Log.i(TAG, "startPhotoZoom: "+cropFinishUri);
            //设置输出到的uri
            intent.putExtra(MediaStore.EXTRA_OUTPUT, cropFinishUri);
            startActivityForResult(intent, CROP_SMALL_PICTURE);
        }

    (参考别人的代码,还未自己研究过)

    cropFinishUri=FileProvider.getUriForFile(MainActivity.this,"fileProvider",out);使用FileProvider封装过的Uri保存文件时报错,使用cropFinishUri=Uri.fromFile(out);方法可以,不知道为什么

    如果使用FileProvider封装的Uri加上以下代码也可以实现

    (FileProvider封装的Uri需要用grantUriPermission手动赋予临时权限)

            List<ResolveInfo> resInfoList = getPackageManager().queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
            for (ResolveInfo resolveInfo : resInfoList) {
                String packageName = resolveInfo.activityInfo.packageName;
                grantUriPermission(packageName, cropFinishUri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION);
            }

    获取拍照的图片发生旋转的情况

    解决 拍照之后手动调整回来:

    Matrix matrix = new Matrix();
    matrix.postRotate(90);
    Bitmap bitmap1=Bitmap.createBitmap(bitmap,0,0,bitmap.getWidth(),bitmap.getHeight(),matrix,true);

    获取旋转角度(有待研究)根据获取的旋转度数,再手动旋转回来

    (小米8手机自动旋转90度,华为P10手机正常)

    String filePath=new File(getExternalStorageDirectory(),"take_photo1.jpg").getPath();
    ExifInterface exifInterface = new ExifInterface(filePath);
    int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
    Log.i(TAG, "onActivityResult: orientation "+orientation);

    这里我的小米手机 orientation 值为6,代表向左旋转90°,华为手机orientation 值为0,代表不明确,实际为正常

    展开全文
  • 在最開始接触Android相机功能之前,先来体验一下Android调用系统照相功能吧 核心代码 Intent intent = new Intent(); //调用照相机 intent.setAction("android.media.action.STILL_IMAGE_CAMERA"); ...
    在最開始接触Android相机功能之前,先来体验一下Android调用系统照相功能吧 核心代码
    Intent intent = new Intent(); //调用照相机
    intent.setAction("android.media.action.STILL_IMAGE_CAMERA");
    startActivity(intent);
    
    加上一个button,当点击button时为我们打开相机功能
    Button btn = (Button)findViewById(R.id.button1);
    btn.setOnClickListener(new OnClickListener(){
    
    @Override
    public void onClick(View v) {
    // TODO Auto-generated method stub
    Intent intent = new Intent(); //调用照相机
    intent.setAction("android.media.action.STILL_IMAGE_CAMERA");
    startActivity(intent);
    }});
    
    展开全文
  • diff --git a/frameworks/base/core/res/res/values/config.xml b/frameworks/base/core/res/res/values/config.xml index 2a61967..aab832d 100755 --- a/frameworks/base/core/res/res/values/config.xml ...

    diff --git a/frameworks/base/core/res/res/values/config.xml b/frameworks/base/core/res/res/values/config.xml
    index 2a61967..aab832d 100755
    --- a/frameworks/base/core/res/res/values/config.xml
    +++ b/frameworks/base/core/res/res/values/config.xml
    @@ -2427,7 +2427,7 @@
     
         <!-- Allow the gesture to double tap the power button twice to start the camera while the device
              is non-interactive. -->
    -    <bool name="config_cameraDoubleTapPowerGestureEnabled">true</bool>
    +    <bool name="config_cameraDoubleTapPowerGestureEnabled">false</bool>
     
         <!-- Name of the component to handle network policy notifications. If present,
              disables NetworkPolicyManagerService's presentation of data-usage notifications. -->

    展开全文
  • 参考: Taking Photos Simply FileProvider 项目地址(好多人找我要,...一.... 要说拍照,如果只是调用系统相机的话,步骤比较简单,就是利用隐式Intent打开相机,然后会相机会传回来排好的图片,传回来的图片分为...

    参考:

    一. 步骤简介

    要说拍照,如果只是调用系统相机的话,步骤比较简单,就是利用隐式Intent打开相机,然后会相机会传回来排好的图片,传回来的图片分为比较小的缩略图和比较大的原图,缩略图的话可以直接进行展示,而原图的话就要输出到文件中,因此简单的拍照分以下步骤:

    • 使用隐式Intent打开相机
    • 在onActivityResult回调中对图片进行处理

    二. 详解

    1. 拍照并获取缩略图
        拍照并获取缩略图不需要任何权限,只需要调用相机然后获取结果即可
      • 调用相机
    Intent takePhotoIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);//用来打开相机的Intent
    if(takePhotoIntent.resolveActivity(getPackageManager())!=null){//这句作用是如果没有相机则该应用不会闪退,要是不加这句则当系统没有相机应用的时候该应用会闪退
           startActivityForResult(takePhotoIntent,REQ_CODE);//启动相机
     }
    
    • 获取结果
    @Override
        protected void onActivityResult(int requestCode, int resultCode, Intent data) {
            if(requestCode==REQ_CODE&&resultCode==RESULT_OK){
                /*缩略图信息是储存在返回的intent中的Bundle中的,
                * 对应Bundle中的键为data,因此从Intent中取出
                * Bundle再根据data取出来Bitmap即可*/
                Bundle extras = data.getExtras();
                Bitmap bitmap = (Bitmap) extras.get("data");
                mPicture.setImageBitmap(bitmap);
            }
        }
    
    1. 拍照并获取完整图片
        因为完整图片较大,所以需要将其存储到文件中,因此需要创建用来存储图片的文件,其次又因为存储图片需要访问外存,因此可能需要申请读写权限。
      • 调用相机
    private void takePhoto(){
            Intent takePhotoIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);//打开相机的Intent
            if(takePhotoIntent.resolveActivity(getPackageManager())!=null){//这句作用是如果没有相机则该应用不会闪退,要是不加这句则当系统没有相机应用的时候该应用会闪退
                File imageFile = createImageFile();//创建用来保存照片的文件
                if(imageFile!=null){
                    if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.N){
                        /*7.0以上要通过FileProvider将File转化为Uri*/
                        mImageUri = FileProvider.getUriForFile(this,FILE_PROVIDER_AUTHORITY,imageFile);
                    }else {
                        /*7.0以下则直接使用Uri的fromFile方法将File转化为Uri*/
                        mImageUri = Uri.fromFile(imageFile);
                    }
                    takePhotoIntent.putExtra(MediaStore.EXTRA_OUTPUT,mImageUri);//将用于输出的文件Uri传递给相机
                    startActivityForResult(takePhotoIntent, REQUEST_TAKE_PHOTO_CODE);//打开相机
                }
            }
        }
    /**
         * 创建用来存储图片的文件,以时间来命名就不会产生命名冲突
         * @return 创建的图片文件
         */
        private File createImageFile() {
            String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
            String imageFileName = "JPEG_"+timeStamp+"_";
            File storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES);
            File imageFile = null;
            try {
                imageFile = File.createTempFile(imageFileName,".jpg",storageDir);
            } catch (IOException e) {
                e.printStackTrace();
            }
            return imageFile;
        }
    
    • 获取结果
    @Override
        protected void onActivityResult(int requestCode, int resultCode, Intent data) {
            if(requestCode== REQUEST_TAKE_PHOTO_CODE &&resultCode==RESULT_OK){
                try {
                    /*如果拍照成功,将Uri用BitmapFactory的decodeStream方法转为Bitmap*/
                    Bitmap bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(mImageUri));
                    mPicture.setImageBitmap(bitmap);//显示到ImageView上
                } catch (FileNotFoundException e) {
                    e.printStackTrace();
                }
            }
        }
    
    1. 将拍的照片添加到媒体库以便相册可以扫描到(当照片存储在应用目录下的时候会扫描不到)
      • 其实就是发送一条扫描文件的广播
    /**
         * 将拍的照片添加到相册
         * @param uri 拍的照片的Uri
         */
        private void galleryAddPic(Uri uri){
            Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
            mediaScanIntent.setData(uri);
            sendBroadcast(mediaScanIntent);
        }
    

    三. 有关7.0以上FileProvider的使用

    • 注册FileProvider
            <provider
                android:authorities="cn.fonxnickel.officialcamerademo.fileprovider"//自己定义的authority
                android:name="android.support.v4.content.FileProvider"
                android:exported="false"
                android:grantUriPermissions="true">//获取临时读取存储的权限
                <meta-data
                    android:name="android.support.FILE_PROVIDER_PATHS"
                    android:resource="@xml/file_paths"/>
            </provider>
    
    • 新建路径文件(xml/file_paths)
    <?xml version="1.0" encoding="utf-8"?>
    <paths>
        <external-path
            name="my_images"
            path="."/>
    </paths>
    

    四. 对拍好的照片进行剪裁

    五. 从相册选取图片

    1. 相册选取图片和拍照步骤差不多,都是打开应用程序,然后返回Uri,然后进行处理
    2. 步骤如下:
      • 打开相册
    /**
         * 打开相册
         */
        private void openAlbum() {
            Intent openAlbumIntent = new Intent(Intent.ACTION_GET_CONTENT);
            openAlbumIntent.setType("image/*");
            startActivityForResult(openAlbumIntent, CHOOSE_PHOTO);//打开相册
        }
    
    • 处理返回的Uri
    /*相机或者相册返回来的数据*/
        @Override
        protected void onActivityResult(int requestCode, int resultCode, Intent data) {
            
            switch (requestCode) {
                case TAKE_PHOTO:
                    if (resultCode == RESULT_OK) {
                        try {
                    /*如果拍照成功,将Uri用BitmapFactory的decodeStream方法转为Bitmap*/
                            Bitmap bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(mImageUri));
                            Log.i(TAG, "onActivityResult: imageUri " + mImageUri);
                            galleryAddPic(mImageUriFromFile);
                            mPicture.setImageBitmap(bitmap);//显示到ImageView上
                        } catch (FileNotFoundException e) {
                            e.printStackTrace();
                        }
                    }
                    break;
                case CHOOSE_PHOTO:
                
                    Log.i(TAG, "onActivityResult: ImageUriFromAlbum: "+data.getData());
                    if (resultCode == RESULT_OK) {
                        if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.KITKAT){
                            handleImageOnKitKat(data);//4.4之后图片解析
                        }else {
                            handleImageBeforeKitKat(data);//4.4之前图片解析
                        }
                    }
                    break;
                default:
                    break;
            }
        }
    
        /**
         * 4.4版本以下对返回的图片Uri的处理:
         * 就是从返回的Intent中取出图片Uri,直接显示就好
         * @param data 调用系统相册之后返回的Uri
         */
        private void handleImageBeforeKitKat(Intent data) {
            Uri uri = data.getData();
            String imagePath = getImagePath(uri,null);
            displayImage(imagePath);
        }
    
        /**
         * 4.4版本以上对返回的图片Uri的处理:
         * 返回的Uri是经过封装的,要进行处理才能得到真实路径
         * @param data 调用系统相册之后返回的Uri
         */
        @TargetApi(19)
        private void handleImageOnKitKat(Intent data) {
            String imagePath = null;
            Uri uri = data.getData();
            if (DocumentsContract.isDocumentUri(this, uri)) {
                //如果是document类型的Uri,则提供document id处理
                String docId = DocumentsContract.getDocumentId(uri);
                if ("com.android.providers.media.documents".equals(uri.getAuthority())) {
                    String id = docId.split(":")[1];//解析出数字格式的id
                    String selection = MediaStore.Images.Media._ID + "=" + id;
                    imagePath = getImagePath(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, selection);
                } else if ("com.android.providers.downloads.documents".equals(uri.getAuthority())) {
                    Uri contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"), Long.valueOf(docId));
                    imagePath = getImagePath(contentUri, null);
                }
            } else if ("content".equalsIgnoreCase(uri.getScheme())) {
                //如果是content类型的uri,则进行普通处理
                imagePath = getImagePath(uri, null);
            } else if ("file".equalsIgnoreCase(uri.getScheme())) {
                //如果是file类型的uri,则直接获取路径
                imagePath = uri.getPath();
            }
            displayImage(imagePath);
        }
    
        /**
         * 将imagePath指定的图片显示到ImageView上
         */
        private void displayImage(String imagePath) {
            if (imagePath != null) {
                Bitmap bitmap = BitmapFactory.decodeFile(imagePath);
                mPicture.setImageBitmap(bitmap);
            } else {
                Toast.makeText(this, "failed to get image", Toast.LENGTH_SHORT).show();
            }
        }
    
        /**
         * 将Uri转化为路径
         * @param uri 要转化的Uri
         * @param selection 4.4之后需要解析Uri,因此需要该参数
         * @return 转化之后的路径
         */
        private String getImagePath(Uri uri, String selection) {
            String path = null;
            Cursor cursor = getContentResolver().query(uri, null, selection, null, null);
            if (cursor != null) {
                if (cursor.moveToFirst()) {
                    path = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA));
                }
                cursor.close();
            }
            return path;
        }
    

    六. 源码

    • 布局
    <?xml version="1.0" encoding="utf-8"?>
    <android.support.constraint.ConstraintLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context="cn.foxnickel.officialcamerademo.MainActivity">
    
        <Button
            android:id="@+id/bt_take_photo"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:text="@string/take_photo"
            android:layout_marginTop="8dp"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            android:layout_marginEnd="8dp"
            app:layout_constraintStart_toStartOf="parent"
            android:layout_marginStart="8dp"/>
    
        <ImageView
            android:id="@+id/iv_picture"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:layout_marginBottom="8dp"
            android:layout_marginEnd="8dp"
            android:layout_marginStart="8dp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:srcCompat="@mipmap/ic_launcher"
            android:layout_marginTop="8dp"
            app:layout_constraintTop_toBottomOf="@+id/bt_choose_from_album"/>
    
        <Button
            android:id="@+id/bt_choose_from_album"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:text="@string/choose_from_album"
            android:layout_marginTop="8dp"
           app:layout_constraintTop_toBottomOf="@+id/bt_take_photo"
            app:layout_constraintStart_toStartOf="parent"
            android:layout_marginStart="8dp"
            app:layout_constraintEnd_toEndOf="parent"
            android:layout_marginEnd="8dp"/>
    </android.support.constraint.ConstraintLayout>
    
    • 主要逻辑
    public class MainActivity extends AppCompatActivity {
    
        private final String TAG = getClass().getSimpleName();
        private Button mTakePhoto, mChooseFromAlbum;
        private ImageView mPicture;
        private static final String PERMISSION_WRITE_STORAGE = Manifest.permission.WRITE_EXTERNAL_STORAGE;
        private static final int REQUEST_PERMISSION_CODE = 267;
        private static final int TAKE_PHOTO = 189;
        private static final int CHOOSE_PHOTO = 385;
        private static final String FILE_PROVIDER_AUTHORITY = "cn.fonxnickel.officialcamerademo.fileprovider";
        private Uri mImageUri, mImageUriFromFile;
        private File imageFile;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            /*申请读取存储的权限*/
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                if (checkSelfPermission(PERMISSION_WRITE_STORAGE) != PackageManager.PERMISSION_GRANTED) {
                    requestPermissions(new String[]{PERMISSION_WRITE_STORAGE}, REQUEST_PERMISSION_CODE);
                }
            }
    
            mPicture = (ImageView) findViewById(R.id.iv_picture);
            mTakePhoto = (Button) findViewById(R.id.bt_take_photo);
            mChooseFromAlbum = (Button) findViewById(R.id.bt_choose_from_album);
    
            mTakePhoto.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    takePhoto();
                }
            });
    
            mChooseFromAlbum.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    openAlbum();
                }
            });
    
        }
    
        /**
         * 打开相册
         */
        private void openAlbum() {
            Intent openAlbumIntent = new Intent(Intent.ACTION_GET_CONTENT);
            openAlbumIntent.setType("image/*");
            startActivityForResult(openAlbumIntent, CHOOSE_PHOTO);//打开相册
        }
    
        /**
         * 拍照
         */
        private void takePhoto() {
            Intent takePhotoIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);//打开相机的Intent
            if (takePhotoIntent.resolveActivity(getPackageManager()) != null) {//这句作用是如果没有相机则该应用不会闪退,要是不加这句则当系统没有相机应用的时候该应用会闪退
                imageFile = createImageFile();//创建用来保存照片的文件
                mImageUriFromFile = Uri.fromFile(imageFile);
                Log.i(TAG, "takePhoto: uriFromFile " + mImageUriFromFile);
                if (imageFile != null) {
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                        /*7.0以上要通过FileProvider将File转化为Uri*/
                        mImageUri = FileProvider.getUriForFile(this, FILE_PROVIDER_AUTHORITY, imageFile);
                    } else {
                        /*7.0以下则直接使用Uri的fromFile方法将File转化为Uri*/
                        mImageUri = Uri.fromFile(imageFile);
                    }
                    takePhotoIntent.putExtra(MediaStore.EXTRA_OUTPUT, mImageUri);//将用于输出的文件Uri传递给相机
                    startActivityForResult(takePhotoIntent, TAKE_PHOTO);//打开相机
                }
            }
        }
    
        /**
         * 创建用来存储图片的文件,以时间来命名就不会产生命名冲突
         *
         * @return 创建的图片文件
         */
        private File createImageFile() {
            String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
            String imageFileName = "JPEG_" + timeStamp + "_";
            File storageDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
            File imageFile = null;
            try {
                imageFile = File.createTempFile(imageFileName, ".jpg", storageDir);
            } catch (IOException e) {
                e.printStackTrace();
            }
            return imageFile;
        }
    
        /*申请权限的回调*/
        @Override
        public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
            super.onRequestPermissionsResult(requestCode, permissions, grantResults);
            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                Log.i(TAG, "onRequestPermissionsResult: permission granted");
            } else {
                Log.i(TAG, "onRequestPermissionsResult: permission denied");
                Toast.makeText(this, "You Denied Permission", Toast.LENGTH_SHORT).show();
            }
        }
    
        /*相机或者相册返回来的数据*/
        @Override
        protected void onActivityResult(int requestCode, int resultCode, Intent data) {
            switch (requestCode) {
                case TAKE_PHOTO:
                    if (resultCode == RESULT_OK) {
                        try {
                    /*如果拍照成功,将Uri用BitmapFactory的decodeStream方法转为Bitmap*/
                            Bitmap bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(mImageUri));
                            Log.i(TAG, "onActivityResult: imageUri " + mImageUri);
                            galleryAddPic(mImageUriFromFile);
                            mPicture.setImageBitmap(bitmap);//显示到ImageView上
                        } catch (FileNotFoundException e) {
                            e.printStackTrace();
                        }
                    }
                    break;
                case CHOOSE_PHOTO:
                    if (data == null) {//如果没有选取照片,则直接返回
                        return;
                    }
                    Log.i(TAG, "onActivityResult: ImageUriFromAlbum: " + data.getData());
                    if (resultCode == RESULT_OK) {
                        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
                            handleImageOnKitKat(data);//4.4之后图片解析
                        } else {
                            handleImageBeforeKitKat(data);//4.4之前图片解析
                        }
                    }
                    break;
                default:
                    break;
            }
        }
    
        /**
         * 4.4版本以下对返回的图片Uri的处理:
         * 就是从返回的Intent中取出图片Uri,直接显示就好
         * @param data 调用系统相册之后返回的Uri
         */
        private void handleImageBeforeKitKat(Intent data) {
            Uri uri = data.getData();
            String imagePath = getImagePath(uri, null);
            displayImage(imagePath);
        }
    
        /**
         * 4.4版本以上对返回的图片Uri的处理:
         * 返回的Uri是经过封装的,要进行处理才能得到真实路径
         * @param data 调用系统相册之后返回的Uri
         */
        @TargetApi(19)
        private void handleImageOnKitKat(Intent data) {
            String imagePath = null;
            Uri uri = data.getData();
            if (DocumentsContract.isDocumentUri(this, uri)) {
                //如果是document类型的Uri,则提供document id处理
                String docId = DocumentsContract.getDocumentId(uri);
                if ("com.android.providers.media.documents".equals(uri.getAuthority())) {
                    String id = docId.split(":")[1];//解析出数字格式的id
                    String selection = MediaStore.Images.Media._ID + "=" + id;
                    imagePath = getImagePath(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, selection);
                } else if ("com.android.providers.downloads.documents".equals(uri.getAuthority())) {
                    Uri contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"), Long.valueOf(docId));
                    imagePath = getImagePath(contentUri, null);
                }
            } else if ("content".equalsIgnoreCase(uri.getScheme())) {
                //如果是content类型的uri,则进行普通处理
                imagePath = getImagePath(uri, null);
            } else if ("file".equalsIgnoreCase(uri.getScheme())) {
                //如果是file类型的uri,则直接获取路径
                imagePath = uri.getPath();
            }
            displayImage(imagePath);
        }
    
        /**
         * 将imagePath指定的图片显示到ImageView上
         */
        private void displayImage(String imagePath) {
            if (imagePath != null) {
                Bitmap bitmap = BitmapFactory.decodeFile(imagePath);
                mPicture.setImageBitmap(bitmap);
            } else {
                Toast.makeText(this, "failed to get image", Toast.LENGTH_SHORT).show();
            }
        }
    
        /**
         * 将Uri转化为路径
         * @param uri 要转化的Uri
         * @param selection 4.4之后需要解析Uri,因此需要该参数
         * @return 转化之后的路径
         */
        private String getImagePath(Uri uri, String selection) {
            String path = null;
            Cursor cursor = getContentResolver().query(uri, null, selection, null, null);
            if (cursor != null) {
                if (cursor.moveToFirst()) {
                    path = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA));
                }
                cursor.close();
            }
            return path;
        }
    
        /**
         * 将拍的照片添加到相册
         *
         * @param uri 拍的照片的Uri
         */
        private void galleryAddPic(Uri uri) {
            Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
            mediaScanIntent.setData(uri);
            sendBroadcast(mediaScanIntent);
        }
    }
    

     




    转载自:https://www.jianshu.com/p/fcc7f8507211
     

    展开全文
  • 关于Android7.0调用系统相机拍照、访问相册的一些问题: 在Android6.0中Google提出了动态申请权限的Api,调用相机拍照,访问SDcard等操作都需要先申请对应的权限如下:   &lt;uses-permission android:name=...

    关于Android7.0调用系统相机拍照、访问相册的一些问题:

    在Android6.0中Google提出了动态申请权限的Api,调用相机拍照,访问SDcard等操作都需要先申请对应的权限如下:

     

    <uses-permission android:name="android.permission.CAMERA" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

    Google是反对放宽私有目录的访问权限的,所以收起对私有文件的访问权限是Android将来发展的趋势。

     

    Android7.0中尝试传递 file:// URI 会触发 FileUriExposedException,因为在Android7.0之后Google认为直接使用本地的根目录即file:// URI是不安全的操作,直接访问会抛出FileUriExposedExCeption异常,这就意味着在Android7.0以前我们访问相机拍照存储时,如果使用URI的方式直接存储剪裁图片就会造成这个异常,那么如何解决这个问题呢?(文章结尾会附上demo的连接)

    补充说明:本文Demo是直接在activity中访问相机、相册,发布后很多老哥留言说需要在Fragment中使用,为了大家使用方便,博主又增加了一个在fragment中调用的Demo,在文章结尾我会附上两个Demo的链接。

    Google为我们提供了FileProvider类,进行一种特殊的内容提供,FileProvider时ContentProvide的子类,它使用了和内容提供器类似的机制来对数据进行保护,可以选择性地将封装过的Uri共享给外部,从而提高了应用的安全性。下面就让我们看一下如何使用这个内容提供者进行数据访问的:

    使用FileProvider获取Uri就会将以前的file:// URI准换成content:// URI,实现一种安全的应用间数据访问,内容提供者作为Android的四大组件之一,使用同样需要在清单文件AndroidManifest.xml中进行注册的,注册方法如下:

     

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

    provider标签里的 android:name的值是FileProvider的包名+类名为固定值。android:authorities的值相当于一个标志,当我们使用FileProvider的getUriForFile方法时的一个参数需和清单文件注册时的保持一致,这里我使用的是:com.zz.fileprovider可自行定义。exported:要求必须为false,为true则会报安全异常。grantUriPermissions:true,表示授予 URI 临时访问权限。<meta-data />标签里面是用来指定共享的路径。 android:resource="@xml/file_paths"就是我们的共享路径配置的xml文件。关于xml文件的配置如下:

     

    在res目录下创建xml文件夹,file_paths.xml文件内容如下:

     

    <?xml version="1.0" encoding="utf-8"?>
    <resources>
        <paths>
            <external-path
                name="camera_photos"
                path="" />
        </paths>
    </resources>

    external-path标签用来指定Uri共享的,name属性的值可以自定义,path属性的值表示共享的具体位置,设置为空,就表示共享整个SD卡,也可指定对应的SDcard下的文件目录,根据需求自行定义。接下来就是调用系统相机进行拍照了,代码如下:

     

    首先获取相机和访问SDcard权限:

     

    /**
     * 自动获取相机权限
     */
    private void autoObtainCameraPermission() {
    
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED
                || ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
    
            if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.CAMERA)) {
                ToastUtils.showShort(this, "您已经拒绝过一次");
            }
            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA, Manifest.permission.READ_EXTERNAL_STORAGE}, CAMERA_PERMISSIONS_REQUEST_CODE);
        } else {//有权限直接调用系统相机拍照
            if (hasSdcard()) {
                imageUri = Uri.fromFile(fileUri);
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
                    imageUri = FileProvider.getUriForFile(MainActivity.this, "com.zz.fileprovider", fileUri);//通过FileProvider创建一个content类型的Uri
                PhotoUtils.takePicture(this, imageUri, CODE_CAMERA_REQUEST);
            } else {
                ToastUtils.showShort(this, "设备没有SD卡!");
            }
        }
    }

    动态申请权限的回调方法:

     

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    
        switch (requestCode) {
            case CAMERA_PERMISSIONS_REQUEST_CODE: {//调用系统相机申请拍照权限回调
                if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    if (hasSdcard()) {
                        imageUri = Uri.fromFile(fileUri);
                        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
                            imageUri = FileProvider.getUriForFile(MainActivity.this, "com.zz.fileprovider", fileUri);//通过FileProvider创建一个content类型的Uri
                        PhotoUtils.takePicture(this, imageUri, CODE_CAMERA_REQUEST);
                    } else {
                        ToastUtils.showShort(this, "设备没有SD卡!");
                    }
                } else {
    
                    ToastUtils.showShort(this, "请允许打开相机!!");
                }
                break;
    
    
            }
            case STORAGE_PERMISSIONS_REQUEST_CODE://调用系统相册申请Sdcard权限回调
                if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    PhotoUtils.openPic(this, CODE_GALLERY_REQUEST);
                } else {
    
                    ToastUtils.showShort(this, "请允许打操作SDCard!!");
                }
                break;
        }
    }

    *注:PhotoUtils是博主对拍照和相册获取照片的封装下面会给出,PhotoUtils类和完整的MainActivity类

     

    重点看一下imageUri的获取,代码中imageUri是用于存储拍照后照片的Uri,调用相机拍照之前首先判断一下系统版本,AndroidN也就是Android7.0以上的系统通过FileProvider获取Uri方法的参数分别为,上下文对象、清单文件配置的android:authorities和对应的拍照存储的图片。之后就是通过PhotoUtils调用系统相机进行拍照。

    PhotoUtils相应代码如下:

     

    /**
     * @param activity    当前activity
     * @param imageUri    拍照后照片存储路径
     * @param requestCode 调用系统相机请求码
     */
    public static void takePicture(Activity activity, Uri imageUri, int requestCode) {
        //调用系统相机
        Intent intentCamera = new Intent();
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            intentCamera.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); //添加这一句表示对目标应用临时授权该Uri所代表的文件
        }
        intentCamera.setAction(MediaStore.ACTION_IMAGE_CAPTURE);
        //将拍照结果保存至photo_file的Uri中,不保留在相册中
        intentCamera.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
        activity.startActivityForResult(intentCamera, requestCode);
    }

    方法说明:通过Intent调用系统相机拍照,如果本机版本大于等于anroid7.0需要临时授权Uri的访问权限如下:

    intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
    
    1. 其他部分和以前正常调用系统相机一样。

    2. 接下来就是对拍完的照片进行剪裁:

    3.  
    4.  
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
    
        if (resultCode == RESULT_OK) {
            switch (requestCode) {
                case CODE_CAMERA_REQUEST://拍照完成回调
                    cropImageUri = Uri.fromFile(fileCropUri);
                    PhotoUtils.cropImageUri(this, imageUri, cropImageUri, 1, 1, output_X, output_Y, CODE_RESULT_REQUEST);
                    break;
                case CODE_GALLERY_REQUEST://访问相册完成回调
                    if (hasSdcard()) {
                        cropImageUri = Uri.fromFile(fileCropUri);
                        Uri newUri = Uri.parse(PhotoUtils.getPath(this, data.getData()));
                        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
                            newUri = FileProvider.getUriForFile(this, "com.zz.fileprovider", new File(newUri.getPath()));
                        PhotoUtils.cropImageUri(this, newUri, cropImageUri, 1, 1, output_X, output_Y, CODE_RESULT_REQUEST);
                    } else {
                        ToastUtils.showShort(this, "设备没有SD卡!");
                    }
                    break;
                case CODE_RESULT_REQUEST:
                    Bitmap bitmap = PhotoUtils.getBitmapFromUri(cropImageUri, this);
                    if (bitmap != null) {
                        showImages(bitmap);
                    }
                    break;
            }
        }
    }

    剪裁代码如下:

    /**
     * @param activity    当前activity
     * @param orgUri      剪裁原图的Uri
     * @param desUri      剪裁后的图片的Uri
     * @param aspectX     X方向的比例
     * @param aspectY     Y方向的比例
     * @param width       剪裁图片的宽度
     * @param height      剪裁图片高度
     * @param requestCode 剪裁图片的请求码
     */
    public static void cropImageUri(Activity activity, Uri orgUri, Uri desUri, int aspectX, int aspectY, int width, int height, int requestCode) {
        Intent intent = new Intent("com.android.camera.action.CROP");
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
        }
        intent.setDataAndType(orgUri, "image/*");
        intent.putExtra("crop", "true");
        intent.putExtra("aspectX", aspectX);
        intent.putExtra("aspectY", aspectY);
        intent.putExtra("outputX", width);
        intent.putExtra("outputY", height);
        intent.putExtra("scale", true);
        //将剪切的图片保存到目标Uri中
        intent.putExtra(MediaStore.EXTRA_OUTPUT, desUri);
        intent.putExtra("return-data", false);
        intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
        intent.putExtra("noFaceDetection", true);
        activity.startActivityForResult(intent, requestCode);
    }
    

    和以前正常剪裁代码基本相同,和上面意图打开相机一样,如果本机版本大于等于anroid7.0需要临时授权Uri的访问权限如下:

    intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
    
    
     
    1. 到此整体调用系统相机拍照、剪裁完成,剪裁后照片存储到cropImageUri对应路径。

    2.  

    访问相册代码如下:

    /**
     * @param activity    当前activity
     * @param requestCode 打开相册的请求码
     */
    public static void openPic(Activity activity, int requestCode) {
        Intent photoPickerIntent = new Intent(Intent.ACTION_GET_CONTENT);
        photoPickerIntent.setType("image/*");
        activity.startActivityForResult(photoPickerIntent, requestCode);
    }
    

    上文中已贴出访问相册后的onActivityResult的回调,主要也是一样的操作解析Uri调用剪裁图片:

    
     
     if (hasSdcard()) {
                        cropImageUri = Uri.fromFile(fileCropUri);
                        Uri newUri = Uri.parse(PhotoUtils.getPath(this, data.getData()));
                        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
                            newUri = FileProvider.getUriForFile(this, "com.zz.fileprovider", new File(newUri.getPath()));
                        PhotoUtils.cropImageUri(this, newUri, cropImageUri, 1, 1, output_X, output_Y, CODE_RESULT_REQUEST);
                    } else {
                        ToastUtils.showShort(this, "设备没有SD卡!");
                    }
                    break;

    *注:Android4.4之后选取中的图片不再返回真实的Uri了,而是封装过的Uri,所以在4.4以上,就要对这个Uri进行解析,即上面的PhotoUtils.getPath()方法,
    具体Uri的解析见
    PhotoUtils类。android4.4以前直接data.getData就可以获取到真是Uri不用解析。

    解析获取真实的Uri后,判断系统版本开始通过FileProvider获取新的Uri之后就可以同样的图片剪裁了。 

    MainActivity代码如下:

    package choicemmed.com.android60permissionsdemo;
    
    import android.Manifest;
    import android.content.Intent;
    import android.content.pm.PackageManager;
    import android.graphics.Bitmap;
    import android.graphics.Matrix;
    import android.media.ExifInterface;
    import android.net.Uri;
    import android.os.Build;
    import android.os.Bundle;
    import android.os.Environment;
    import android.support.annotation.NonNull;
    import android.support.v4.app.ActivityCompat;
    import android.support.v4.content.ContextCompat;
    import android.support.v4.content.FileProvider;
    import android.support.v7.app.AppCompatActivity;
    import android.util.Log;
    import android.view.View;
    import android.widget.Button;
    
    import com.google.android.gms.common.api.GoogleApiClient;
    import com.lidroid.xutils.ViewUtils;
    import com.lidroid.xutils.view.annotation.ViewInject;
    import com.lidroid.xutils.view.annotation.event.OnClick;
    
    import java.io.File;
    
    import de.hdodenhof.circleimageview.CircleImageView;
    
    public class MainActivity extends AppCompatActivity implements View.OnClickListener {
        private static final String TAG = "MainActivity";
        @ViewInject(R.id.photo)
        private CircleImageView photo;
        @ViewInject(R.id.takePic)
        private Button takePic;
        @ViewInject(R.id.takeGallery)
        private Button takeGallery;
        @ViewInject(R.id.test)
        private Button test;
        private static final int CODE_GALLERY_REQUEST = 0xa0;
        private static final int CODE_CAMERA_REQUEST = 0xa1;
        private static final int CODE_RESULT_REQUEST = 0xa2;
        private static final int CAMERA_PERMISSIONS_REQUEST_CODE = 0x03;
        private static final int STORAGE_PERMISSIONS_REQUEST_CODE = 0x04;
        private File fileUri = new File(Environment.getExternalStorageDirectory().getPath() + "/photo.jpg");
        private File fileCropUri = new File(Environment.getExternalStorageDirectory().getPath() + "/crop_photo.jpg");
        private Uri imageUri;
        private Uri cropImageUri;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            ViewUtils.inject(this);
        }
        
    
        @OnClick({R.id.takePic, R.id.takeGallery})
        @Override
        public void onClick(View v) {
            switch (v.getId()) {
                case R.id.takePic:
                    autoObtainCameraPermission();
                    break;
                case R.id.takeGallery:
                    autoObtainStoragePermission();
                    break;
            }
        }
    
        /**
         * 自动获取相机权限
         */
        private void autoObtainCameraPermission() {
    
            if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED
                    || ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
    
                if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.CAMERA)) {
                    ToastUtils.showShort(this, "您已经拒绝过一次");
                }
                ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA, Manifest.permission.READ_EXTERNAL_STORAGE}, CAMERA_PERMISSIONS_REQUEST_CODE);
            } else {//有权限直接调用系统相机拍照
                if (hasSdcard()) {
                    imageUri = Uri.fromFile(fileUri);
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
                        imageUri = FileProvider.getUriForFile(MainActivity.this, "com.zz.fileprovider", fileUri);//通过FileProvider创建一个content类型的Uri
                    PhotoUtils.takePicture(this, imageUri, CODE_CAMERA_REQUEST);
                } else {
                    ToastUtils.showShort(this, "设备没有SD卡!");
                }
            }
        }
    
        @Override
        public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
            super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    
            switch (requestCode) {
                case CAMERA_PERMISSIONS_REQUEST_CODE: {//调用系统相机申请拍照权限回调
                    if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                        if (hasSdcard()) {
                            imageUri = Uri.fromFile(fileUri);
                            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
                                imageUri = FileProvider.getUriForFile(MainActivity.this, "com.zz.fileprovider", fileUri);//通过FileProvider创建一个content类型的Uri
                            PhotoUtils.takePicture(this, imageUri, CODE_CAMERA_REQUEST);
                        } else {
                            ToastUtils.showShort(this, "设备没有SD卡!");
                        }
                    } else {
    
                        ToastUtils.showShort(this, "请允许打开相机!!");
                    }
                    break;
    
    
                }
                case STORAGE_PERMISSIONS_REQUEST_CODE://调用系统相册申请Sdcard权限回调
                    if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                        PhotoUtils.openPic(this, CODE_GALLERY_REQUEST);
                    } else {
    
                        ToastUtils.showShort(this, "请允许打操作SDCard!!");
                    }
                    break;
            }
        }
    
        private int output_X = 480;
        private int output_Y = 480;
    
        @Override
        protected void onActivityResult(int requestCode, int resultCode, Intent data) {
            super.onActivityResult(requestCode, resultCode, data);
    
            if (resultCode == RESULT_OK) {
                switch (requestCode) {
                    case CODE_CAMERA_REQUEST://拍照完成回调
                        cropImageUri = Uri.fromFile(fileCropUri);
                        PhotoUtils.cropImageUri(this, imageUri, cropImageUri, 1, 1, output_X, output_Y, CODE_RESULT_REQUEST);
                        break;
                    case CODE_GALLERY_REQUEST://访问相册完成回调
                        if (hasSdcard()) {
                            cropImageUri = Uri.fromFile(fileCropUri);
                            Uri newUri = Uri.parse(PhotoUtils.getPath(this, data.getData()));
                            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
                                newUri = FileProvider.getUriForFile(this, "com.zz.fileprovider", new File(newUri.getPath()));
                            PhotoUtils.cropImageUri(this, newUri, cropImageUri, 1, 1, output_X, output_Y, CODE_RESULT_REQUEST);
                        } else {
                            ToastUtils.showShort(this, "设备没有SD卡!");
                        }
                        break;
                    case CODE_RESULT_REQUEST:
                        Bitmap bitmap = PhotoUtils.getBitmapFromUri(cropImageUri, this);
                        if (bitmap != null) {
                            showImages(bitmap);
                        }
                        break;
                }
            }
        }
    
    
        /**
         * 自动获取sdk权限
         */
    
        private void autoObtainStoragePermission() {
            if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
                ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, STORAGE_PERMISSIONS_REQUEST_CODE);
            } else {
                PhotoUtils.openPic(this, CODE_GALLERY_REQUEST);
            }
    
        }
    
        private void showImages(Bitmap bitmap) {
            photo.setImageBitmap(bitmap);
        }
    
        /**
         * 检查设备是否存在SDCard的工具方法
         */
        public static boolean hasSdcard() {
            String state = Environment.getExternalStorageState();
            return state.equals(Environment.MEDIA_MOUNTED);
        }
    
    
    }
    

    PhotoUtils代码如下:

    package choicemmed.com.android60permissionsdemo;
    
    import android.annotation.SuppressLint;
    import android.app.Activity;
    import android.content.ContentUris;
    import android.content.Context;
    import android.content.Intent;
    import android.database.Cursor;
    import android.graphics.Bitmap;
    import android.net.Uri;
    import android.os.Build;
    import android.os.Environment;
    import android.provider.DocumentsContract;
    import android.provider.MediaStore;
    
    /**
     * Created by:zheng zhong on 2016/8/6 16:16
     * Email zheng_zhong@163.com
     */
    public class PhotoUtils {
        private static final String TAG = "PhotoUtils";
    
        /**
         * @param activity    当前activity
         * @param imageUri    拍照后照片存储路径
         * @param requestCode 调用系统相机请求码
         */
        public static void takePicture(Activity activity, Uri imageUri, int requestCode) {
            //调用系统相机
            Intent intentCamera = new Intent();
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                intentCamera.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); //添加这一句表示对目标应用临时授权该Uri所代表的文件
            }
            intentCamera.setAction(MediaStore.ACTION_IMAGE_CAPTURE);
            //将拍照结果保存至photo_file的Uri中,不保留在相册中
            intentCamera.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
            activity.startActivityForResult(intentCamera, requestCode);
        }
    
        /**
         * @param activity    当前activity
         * @param requestCode 打开相册的请求码
         */
        public static void openPic(Activity activity, int requestCode) {
            Intent photoPickerIntent = new Intent(Intent.ACTION_GET_CONTENT);
            photoPickerIntent.setType("image/*");
            activity.startActivityForResult(photoPickerIntent, requestCode);
        }
    
        /**
         * @param activity    当前activity
         * @param orgUri      剪裁原图的Uri
         * @param desUri      剪裁后的图片的Uri
         * @param aspectX     X方向的比例
         * @param aspectY     Y方向的比例
         * @param width       剪裁图片的宽度
         * @param height      剪裁图片高度
         * @param requestCode 剪裁图片的请求码
         */
        public static void cropImageUri(Activity activity, Uri orgUri, Uri desUri, int aspectX, int aspectY, int width, int height, int requestCode) {
            Intent intent = new Intent("com.android.camera.action.CROP");
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
            }
            intent.setDataAndType(orgUri, "image/*");
            intent.putExtra("crop", "true");
            intent.putExtra("aspectX", aspectX);
            intent.putExtra("aspectY", aspectY);
            intent.putExtra("outputX", width);
            intent.putExtra("outputY", height);
            intent.putExtra("scale", true);
            //将剪切的图片保存到目标Uri中
            intent.putExtra(MediaStore.EXTRA_OUTPUT, desUri);
            intent.putExtra("return-data", false);
            intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
            intent.putExtra("noFaceDetection", true);
            activity.startActivityForResult(intent, requestCode);
        }
    
        /**
         * 读取uri所在的图片
         *
         * @param uri      图片对应的Uri
         * @param mContext 上下文对象
         * @return 获取图像的Bitmap
         */
        public static Bitmap getBitmapFromUri(Uri uri, Context mContext) {
            try {
                Bitmap bitmap = MediaStore.Images.Media.getBitmap(mContext.getContentResolver(), uri);
                return bitmap;
            } catch (Exception e) {
                e.printStackTrace();
                return null;
            }
        }
    
        /**
         * @param context 上下文对象
         * @param uri     当前相册照片的Uri
         * @return 解析后的Uri对应的String
         */
        @SuppressLint("NewApi")
        public static String getPath(final Context context, final Uri uri) {
    
            final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
            String pathHead = "file:///";
            // DocumentProvider
            if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {
                // ExternalStorageProvider
                if (isExternalStorageDocument(uri)) {
                    final String docId = DocumentsContract.getDocumentId(uri);
                    final String[] split = docId.split(":");
                    final String type = split[0];
                    if ("primary".equalsIgnoreCase(type)) {
                        return pathHead + Environment.getExternalStorageDirectory() + "/" + split[1];
                    }
                }
                // DownloadsProvider
                else if (isDownloadsDocument(uri)) {
    
                    final String id = DocumentsContract.getDocumentId(uri);
    
                    final Uri contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));
    
                    return pathHead + getDataColumn(context, contentUri, null, null);
                }
                // MediaProvider
                else if (isMediaDocument(uri)) {
                    final String docId = DocumentsContract.getDocumentId(uri);
                    final String[] split = docId.split(":");
                    final String type = split[0];
    
                    Uri contentUri = null;
                    if ("image".equals(type)) {
                        contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
                    } else if ("video".equals(type)) {
                        contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
                    } else if ("audio".equals(type)) {
                        contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
                    }
    
                    final String selection = "_id=?";
                    final String[] selectionArgs = new String[]{split[1]};
    
                    return pathHead + getDataColumn(context, contentUri, selection, selectionArgs);
                }
            }
            // MediaStore (and general)
            else if ("content".equalsIgnoreCase(uri.getScheme())) {
                return pathHead + getDataColumn(context, uri, null, null);
            }
            // File
            else if ("file".equalsIgnoreCase(uri.getScheme())) {
                return pathHead + uri.getPath();
            }
            return null;
        }
    
        /**
         * Get the value of the data column for this Uri. This is useful for
         * MediaStore Uris, and other file-based ContentProviders.
         *
         * @param context       The context.
         * @param uri           The Uri to query.
         * @param selection     (Optional) Filter used in the query.
         * @param selectionArgs (Optional) Selection arguments used in the query.
         * @return The value of the _data column, which is typically a file path.
         */
        private static String getDataColumn(Context context, Uri uri, String selection, String[] selectionArgs) {
    
            Cursor cursor = null;
            final String column = "_data";
            final String[] projection = {column};
            try {
                cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, null);
                if (cursor != null && cursor.moveToFirst()) {
                    final int column_index = cursor.getColumnIndexOrThrow(column);
                    return cursor.getString(column_index);
                }
            } finally {
                if (cursor != null)
                    cursor.close();
            }
            return null;
        }
    
        /**
         * @param uri The Uri to check.
         * @return Whether the Uri authority is ExternalStorageProvider.
         */
        private static boolean isExternalStorageDocument(Uri uri) {
            return "com.android.externalstorage.documents".equals(uri.getAuthority());
        }
    
        /**
         * @param uri The Uri to check.
         * @return Whether the Uri authority is DownloadsProvider.
         */
        private static boolean isDownloadsDocument(Uri uri) {
            return "com.android.providers.downloads.documents".equals(uri.getAuthority());
        }
    
        /**
         * @param uri The Uri to check.
         * @return Whether the Uri authority is MediaProvider.
         */
        private static boolean isMediaDocument(Uri uri) {
            return "com.android.providers.media.documents".equals(uri.getAuthority());
        }
    
    }
    

     

    最后附上:

    1、Activity中调用demo的GitHub地址点击打开链接

    2、Fragment中调用Demo的GitHub地址:点击打开链接

    展开全文
  • 直接贴修改记录 +++ b/frameworks/base/core/res/res/values/config.xml @@ -2471,7 +2471,7 @@    &lt;!-- Allow the gesture to double tap the power button twice to start the camera while the device ...
  • 调用系统相机: /*** * 启动拍照 */ private void capture(){ Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); // 获取文件 File file=new File(tempPicPath);... //拍照后原图回存入此...
  • Android WebView调用系统相册和相机,注入以及与H5的交互 推荐: 如何设计一个优雅健壮的Android WebView?(上) 如何设计一个优雅健壮的Android WebView?(下) Android Webview在使用的过程中,其实也是挺简单的...
  • 图片拍照上传的功能,唤起相机,上传文件实现
  • Android 2.3 Gingerbread开始,原生支持前置摄像头。下面我们看看如何在程序里来调用前置的摄像头。  第一种方式是采用MediaStore,调用系统原生的相机。 view plain Intent intent = ...
  • 场景描述: 比如你再应用中打开了系统相机,然后需要在几分钟后自动关闭这个系统相机(不是手动关闭) 1.在activityA中利用startActivityForResult(intent,requestCode), 2.在activityA中new Timer(),在delay后执行...
  • 2,网页说明编码格式 2,设置WebView编码 httpview.getSettings().setDefaultTextEncodingName("gbk"); 注意为gb2312或gbk如果大家可以试试上面的方法,我的乱码问题用第二种方法解决了
  • 都能够调用系统照相机或摄像机并且返回包含数据的intent,那录音机该如何调用? MediaStore.Audio.Media.RECORD_SOUND_ACTION并不能返回数据啊,它直接就把音频存储了。 为什么相机和视频都有了,没有录音机的呢?
  • frameworks/base/packages/SettingsProvider/res/values/defaults.xml + &lt;bool name="def_camera_double_tap_power_gesture_disable"&gt;true&lt;/bool&gt; frameworks/base/packages...
  • 打开110  String phoneNumber = "120";  Intent intentPhone = new Intent(Intent.ACTION_CALL, Uri.parse("tel:" + phoneNumber));  startActivity(int
  • 从AMD到i7的CPU,6G内存到14G内存,打开 AndroidStudio 的速度终于杠杆的上去了,感动到泪流满面啊!!!!!!!扯了这么多,回归一下正题,还是来说说本篇文章要写什么吧!说起调用系统相机来拍照的功能,大家肯定...
  • Android_照相机Camera_调用系统照相机返回data为空 1.调用系统照相机 1 //实例化一个intent,并指定action 2 Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); 3 //指定一个图片路径对应的file对象 4 ...
  • 先上html界面的代码,放在assets里面就可以了,我也不太会html,所以随便写了点<!doctype html> ®"> <m
1 2 3 4
收藏数 69
精华内容 27