Android calls the system camera to take pictures and get pictures

Keywords: Android FileProvider xml Java

Catalog

Call System Camera

If it is not a special requirement, we usually call the system to take pictures to complete the work, and there is no need to implement a photo function by ourselves. It's very simple to call the system camera, just need one intent to jump to several interfaces, and then get the picture through onActivity Result.

Intent openCameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); // System Constant, the Key to Starting Camera
startActivityForResult(openCameraIntent, REQUEST_CODE_TAKE_PICTURE); // Parameter constants are custom request code s that are useful for retrieving results

Get pictures

Rewrite the onActivityResult method to get request_code.

    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        switch (requestCode) {
            case REQUEST_CODE_TAKE_PICTURE:
               // Write "How to Get Pictures" here.
                break;

        }
    }

How to Get Pictures

No storage directory specified

You can see from the top that Intent Action: MediaStore.ACTION_IMAGE_CAPTURE opens the camera and takes a picture and returns the result.

If no additional parameter MediaStore.EXTRA_OUTPUT is set to control the storage path of the image, the result will be a small Bitmap.

 Bitmap bm = (Bitmap) data.getExtras().get("data");
 ImageView.setImageBitmap(bm);

The above method is only suitable when the application needs a small picture. And after testing, it is found that the image saved is seriously distorted when compared with the preview image taken. The reason is that the pixels of the camera are very large now. Every picture is on M. The maximum memory allocated by Android system to each application is 16M. If the image is returned directly to the caller through memory, it will take up too much memory. So here is a processed thumbnail.

Specify storage directory

The second way to get a picture is to specify the location of the image in intent. This method obtains the original image. By setting MediaStore.EXTRA_OUTPUT parameters. This method saves the original image to the specified Uri without compression. The code is as follows:

// Open Camera Intent
 Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
 
 // Specify storage locations for photographs taken
String f = System.currentTimeMillis()+".jpg"; // Designated name
Uri fileUri = Uri.fromFile(new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM), f)); // Specify the uri of the image to be saved, where the image is saved in the system album
cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri); //Specify where the image is stored, and when specified, the Data in onActivityResult will be null

// Start the camera
startActivityForResult(cameraIntent, REQUEST_CODE_CAMERA);

Designated storage directories above Android 7.0

In general, the above "designated storage directory" method has no problem running; however, when targetSdkVersion is designated as 24 and above and running on API >= 24 (Android 7.0 or more) devices, an exception will be thrown:

android.os.FileUriExposedException: The file path and file name you specify (i.e. fileUri above) exposed beyond app through ClipData.Item.getUri()

Reason: Android no longer allows file://Uri to be exposed to other apps in apps, including but not limited to methods such as Intent or ClipData. The reason is that there are some risks in using file://Uri, such as: the file is private and the app receiving file://Uri cannot access the file.

Runtime privileges are introduced after Android 6.0. If the app receiving file://Uri does not apply for READ_EXTERNAL_STORAGE privileges, the crash will occur when the file is read.

Therefore, Google provides FileProvider, which generates content://Uri instead of file://Uri.

Simple Use of FileProvider

Simple use of FileProvider can be referred to: http://gelitenight.github.io/android/2017/01/29/solve-FileUriExposedException-caused-by-file-uri-with-FileProvider.html#fileprovider-1

I use FileProvider with reference to the description here. The specific method is not to go into detail, but to paste the code.

provider_paths.xml

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <external-path path="DCIM" name="external_files"/>
</paths>

In the code:

// Open Camera Intent
Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
// Specify storage locations for photographs taken
String f = System.currentTimeMillis()+".jpg"; // Designated name
File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM), f); // Designated file
fileUri = FileProvider.getUriForFile(MainActivity.this, getPackageName() + ".provider", file); // Path Conversion
cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri); //Specify where the image is stored, and when specified, the Data in onActivityResult will be null
startActivityForResult(cameraIntent, REQUEST_CODE_CAMERA);

Next, I'll talk about some of the problems encountered in using the methods in the links.

  1. android:name="android.support.v4.content.FileProvider" cannot identify problems when provider s are added to the Android Manifest. XML file.
    Solution: android.support.v4.content.FileProvider was changed to androidx.core.content.FileProvider. The migration of Android libraries to Androidx resulted in the failure of android.support.v4.content.FileProvider. Replace the library.

  2. Error opening camera:

java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.res.XmlResourceParser android.content.pm.PackageItemInfo.loadXmlMetaData(android.content.pm.PackageManager, java.lang.String)' on a null object reference

This error occurs because android:authorities at Android Manifest. xml do not match mActivity. getPackageName ()+". provider".

In Android Manifest.xml:

android:authorities="${applicationId}.fileprovider"

In the code:

fileUri = FileProvider.getUriForFile(MainActivity.this, getPackageName() + ".provider", file); // Path Conversion

Change the code to:

 fileUri = FileProvider.getUriForFile(MainActivity.this, getPackageName() + ".fileprovider", file); // Path Conversion

Problem solving.

Reference link

Posted by scuzzo84 on Wed, 28 Aug 2019 05:47:18 -0700