Android invoking system camera to take pictures

Outline

Look at the recent nanChen write the image picker ImagePicker, feeling fairly good, also I intend to write down the things learned. Many times, met a good framework to reduce development costs which is a good thing. But also need to understand the specific implementation of its internal logic, maybe someday you need to complete a similar small feature, you can quickly know the principles written, rather than introducing the whole framework.

This article speaks of them first function: How to transfer from the phone's camera to take pictures?

Existing camera systems applications

How to call for existing applications, simple to tell you here. Call system in the prior application development application, it is necessary to specify the use of Intent application and opened Action Category, and then open the specified Activity by startActivity (Intent) or startActivityForResult (Intent, int), if using the startActivityForResult () method and requires opening The return value, then rewriting onActivityResult (int, int, Intent) can.

Let's look at the existing system Activity camera application AndroidManifest.xml manifest file definitions:

        <activity
            android:name="com.android.camera.Camera"
            android:clearTaskOnLaunch="true"
            android:configChanges="orientation|keyboardHidden"
            android:screenOrientation="landscape"
            android:taskAffinity="android.task.camera"
            android:theme="@android:style/Theme.Black.NoTitleBar.Fullscreen" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <categroy android:name="android.intent.category.DEFAULT" />
                <categroy android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
            <intent-filter>
                <action android:name="android.media.action.IMAGE_CAPTURE" />
                <categroy android:name="android.intent.category.DEFAULT" />
            </intent-filter>
            <intent-filter>
                <action android:name="android.media.action.STILL_IMAGE_CAMERA" />
                <categroy android:name="android.intent.category.DEFAULT" />
            </intent-filter>
        </activity>
        <activity
            android:name="com.android.camera.VideoCamera"
            android:clearTaskOnLaunch="true"
            android:configChanges="origientation|keyboardHidden"
            android:label="@string/video_camera_label"
            android:screenOrientation="landscape"
            android:taskAffinity="android.task.camcorder"
            android:theme="@android:style/theme.Black.NoTitleBar.Fullscreen" >
            <intent-filter>
                <action android:name="android.media.action.VIDEO_CAMERA" />
                <categroy android:name="android.intent.category.DEFAULT" />
            </intent-filter>
            <intent-filter>
                <action android:name="android.media.action.VIDEO_CAPTURE" />
                <categroy android:name="android.intent.category.DEFAULT" />
            </intent-filter>
        </activity>    

 It defines two Activity, com.android.camera.Camera denotes a camera, com.android.camera.VideoCamera  expressed cameras. As can be seen from the literal meaning, in order to capture the data returned by the camera system, generally requires about two Action to turn the camera to the camera:

  • android.media.action.IMAGE_CAPTURE : the Intent of the Action type, request a picture from an existing camera applications.

  • android.media.action.VIDEO_CAPTURE : Action of the Intent type, request a video camera from the existing application.

The above two parameters are defined in the class MediaStore well as static constants are: MediaStore.ACTION_IMAGE_CAPTURE (camera) and MediaStore.ACTION_VIDEO_CAPTURE (camera).

Get Picture existing camera system

Activity in the newly opened, if necessary to obtain its return value, you need to use startActivityForResult (Intent, int) method to open Activity, and rewrite onActivityResult (int, int, Intent) to return data acquisition system of the camera, then we only need the return value can be obtained in the onActivityResult () in.

Photo System camera, if you do not specify a path, the system will be saved in the default folder, you can use Intent.getExtra () method to get, get is a Uri address, the address represents a content provider. If by MediaStore.EXTRA_OUTPUT specify the save path, then by Intent.getExtra () will get an empty address, but since it is our designated address, but also no shortage of it.

But if it is more than 7.0, you need to get the uri FileProvider address.

Implementation

After the clear process, the following is the specific code to achieve:

The first is a statement permission to take pictures in AndroidManiFest.xml:

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

After declaring permission before starting taking pictures, still need to determine whether the user has given permission to take pictures of us:

if (( mActivity).checkSelfPermission(Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
  ActivityCompat.requestPermissions(mActivity, new String[]{Manifest.permission.CAMERA}, GalleryActivity.REQUEST_PERMISSION_CAMERA);
} else {
  imagePicker.takePicture(mActivity, GalleryActivity.REQUEST_CODE_TAKE);
}

If the user does not give permission, you need to apply for permission to apply for permission in the future, there will be a callback notification whether to allow a developer specific hair below code:

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (requestCode == REQUEST_PERMISSION_CAMERA) {
            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                imagePicker.takePicture(this, REQUEST_CODE_TAKE);
            } else {
                showToast("权限被禁止,无法打开相机");
            }
        }
    }

After the permissions allowed to take pictures through imagePicker.takePicture. The following specific look photographed code logic:

    /**
     * 拍照的方法
     */
    public void takePicture(Activity activity, int requestCode) {
        Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        takePictureIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
        if (takePictureIntent.resolveActivity(activity.getPackageManager()) != null) {
            if (Utils.existSDCard()) takeImageFile = new File(Environment.getExternalStorageDirectory(), "/DCIM/camera/");
            else takeImageFile = Environment.getDataDirectory();
            takeImageFile CreateFile = (takeImageFile, "IMG_", ".jpg" );
             IF (! TakeImageFile = null ) {
                 // default, i.e., no need to specify intent.putExtra (MediaStore.EXTRA_OUTPUT, URI);
                 // camera has its own default storage path, photographs returns a thumbnail. If you want to access the original picture,
                 // by dat extra you can get the original picture position. That is, if the target uri is specified, data is no data,
                 // if uri is not specified, the data returns data! 

                URI URI; 
                IF (VERSION.SDK_INT <= VERSION_CODES.M) { 
                    URI = Uri.fromFile (takeImageFile); 
                } the else { 

                    / **
                     * 7.0 are no longer allowed to call the system using a camera to take pictures Uri way, should be replaced FileProvider 
                     * and this can be resolved camera on MIUI system returns size is 0 
                     * / 
                    uri = FileProvider.getUriForFile (Activity, "com.example.myapplication.provider " , takeImageFile);
                     // adding uri rights or else Samsung mobile phones can not take pictures 
                    List <resolveInfo> resInfoList = activity.getPackageManager () queryIntentActivities (takePictureIntent, PackageManager.MATCH_DEFAULT_ONLY);.
                     for (resolveInfo resolveInfo: resInfoList) { 
                        String packageName = resolveInfo. activityInfo.packageName;
                        activity.grantUriPermission(packageName, uri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION);
                    }
                }

              //  Log.e("nanchen", ProviderUtil.getFileProviderName(activity));
                takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
            }
        }
        activity.startActivityForResult(takePictureIntent, requestCode);
    }

About Intent.resolveActivity role, in short, when you call the third-party software or system Activity, similar to turn on the camera, send pictures and other implicit Intent, it is not necessarily able to run properly on all Android devices. The intent is determined whether the corresponding activity by the present method, to ensure that collapse does not occur.

takeImageFile is a picture memory address, before 7.0, you need to be treated with Uri.fromFile. After 7.0 using FileProvider. Here the use of FileProvider:

registered

Use FileProvider need to declare in AndroidManiFest.xml in:

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

Here is the v4 package directly used in the FileProvider, we can also inherit FileProvider class directly, appropriate rewrite overloaded functions, but is not recommended to do so. To introduce the above several settings:

  • name: provider class name, if the default FileProvider v4 can use the "android.support.v4.content.FileProvider", it can also be set to inherit FileProvider class provider of custom;

  • authorities:  a signed certificate, you can customize, but at the time of acquisition uri need to be consistent;

  • grantUriPermissions: Use FileProvider we need to use out of the URI given temporary access (READ and WRITE), this setting is to allow us to exercise that power;

  • the Data-Meta:  Meta-configuration of the Data is our path to the file can access the configuration information, you need to use the xml files for configuration, FileProvider will get a Configuration Item by parsing the xml file, where name name can not be changed to: android.support.FILE_PROVIDER_PATHS, resource path for the configuration item configuration information.

Path Configuration

Path accessible configuration may be established following a xml file to create a profile in the res in the following format:

<? Xml Version = "1.0" encoding = "UTF-8" ?> 
< Paths > 
  <-! Path: path to the temporary need for authorized access (on behalf of all the paths.) -> 
  <-! Name: what you give the access path a name -> 
  < External path- name = "CAM" path . "" =  /> 
</ paths >

Under the following explanation:

  • <files-path />    root represented by: Context.getFilesDir ()

  • <external-path />   root represented by: Environment.getExternalStorageDirectory ()
  • <cache-path />  root represented by: getCacheDir ()

Finally, the uri into MediaStore.EXTRA_OUTPUT in.

takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, uri);

After the camera is complete, the callback onActivityResult, where we can based on the value of the previously passed to the ImageView Photo Gallery:

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        Log.i(TAG, "系统相机拍照完成,resultCode=" + resultCode + " " + requestCode);
        if (requestCode == REQUEST_CODE_TAKE) {
            Uri uri = Uri.fromFile(takeImageFile);
            iv_CameraImg.setImageURI(uri);
        } 
    }

This, call the system camera to take pictures of this process is over.

 

Guess you like

Origin www.cnblogs.com/huansky/p/12104662.html