How To Open Camera In Android Programmatically Using Intent

This article will show you an example of how to use intent to invoke an android camera programmatically to take and save pictures. It will also tell you how to display those pictures one by one when the user clicks one picture.

1. Invoke Android Camera Using Intent Example Overview.

If you can not watch the above video, you can see it on the youtube URL https://youtu.be/b4JRDdOuMOw

  1. As you can see from the above video. There is one Button and one ImageView on the screen. When you click the button, the android camera app will pop up, then you can take pictures with it.
  2. When you close the camera, the picture will be displayed in the image view object under the button. You can take several images, then when you click one image, it will show the next image in the camera taken images list.
  3. You can not run this example in the android emulator. You need a physical android device that has a camera. I use Hua Wei mate 8.
  4. Before you can run it on a physical device, you need to enable USB debugging mode in the physical device, Please read the article How To Enable USB Debugging Mode On Android Device to learn more.
  5. If you run this example in the android emulator, you will find below exception be thrown.

    android.content.ActivityNotFoundException: No Activity found to handle Intent { act=android.media.action.IMAGE_PICTURE (has extras) }

2. Where The Pictures Are Saved In.

  1. We save all the pictures in the app external storage cache folder in this example.
  2. You can use the below code to get the android device external storage root folder.
     Environment.getExternalStorageDirectory()
  3. Different Android devices may use different root folders. But generally external storage root folder is /sdcard, /mnt or /storage. But for some Android devices such as Hua Wei mate 8, the root directory (/sdcard) has been linked to (/storage/sdcard1) and then link to /storage/41B7-12F1, we can see it in the Android Device Monitor —> Devices ( left side) —> File Explorer tab window (right side).
  4. So the app-specific cache folder will be /storage/41B7-12F1/Android/data/com.dev2qa.example/cache. All the temporary camera-taken pictures will be saved in this folder.

3. How To Save Those Pictures In Above Folder.

  1. The camera app is responsible for saving the pictures in the above folder. So you should tell the camera app the folder path by using a Uri object. The Uri object is a wrapper of the picture file path. It is used to identify the resource’s ( file ) path uniquely.
  2. Below is the code that passes the output picture save folder to the camera app using intent.
    cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, outputImgUri)
  3. After the camera app takes an image, when you close the camera, you can find the picture files are saved by the camera in the app-specific cache directory.

4. How To Startup Camera Using Intent.

  1. First you need create an Intent object with action MediaStore.ACTION_IMAGE_CAPTURE (android.media.action.IMAGE_CAPTURE).
    Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
  2. Then put the output image Uri as the extra parameter pass to camera activity.
    cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, outputImgUri);
  3. And then start the camera app and wait for camera app process result.
    startActivityForResult(cameraIntent, REQUEST_CODE_TAKE_PICTURE);

5. Use FileProvider To Get Picture File Uri Wrapper.

  1. From Android OS version 7.0 ( SDK version 24 ), you need to use android.support.v4.content.FileProvider class to share files between android apps.
  2. Because those picture files are created by the camera app, and only the camera and camera same group users can read them, all other users can only execute them. You can get this conclusion from the camera-taken picture files permission(for example -rwxrwx–x).
  3. So if you want to read those picture files in this example app, you must use a content resolver to read them by their Uri.
  4. FileProvider is a content provider which focuses on file sharing. But before you can use it, you should configure it in the AndroidManifest.xml file.
    <!-- FileProvider settings, after this configuration you can use FileProvider in your activity. -->
    <provider
        <!-- The authority of this file provider -->
        android:authorities="com.dev2qa.fileprovider"
        android:name="android.support.v4.content.FileProvider"
        android:exported="false"
        android:grantUriPermissions="true">
    
        <!-- Specify which folder will be shared by this file provider. -->
        <meta-data
            android:name="android.support.FILE_PROVIDER_PATHS"
            android:resource="@xml/shared_file_paths" />
    </provider>
  5. Please remember the provider’s android: authorities attribute value, this value will be used as the second parameter of FileProvider.getUriForFile method when getting shared files URI.
    ret = FileProvider.getUriForFile(ctx, "com.dev2qa.fileprovider", file);
  6. The meta-data XML tag specifies the shared file directories in an XML resource file. The file name is shared_file_paths.xml which is saved in the app/res/xml folder, but you can use any file name in your code as you like.
  7. If the XML folder does not exist, you need to do the following to create it.
  8. Right-click the app/res folder.
  9. Click the New —> Directory menu item in the popup menu list.
  10. Enter the keyword xml for the directory name.
  11. Below are the steps to create the shared_file_paths.xml file.
  12. Right-click app/res/xml folder.
  13. Click New —> XML resource file.
  14. Input the XML file name.
  15. Now enter the below XML content in shared_file_paths.xml.
    <paths xmlns:android="http://schemas.android.com/apk/res/android">
        <!-- Configure shared external storage path, path value is relative to your device external storage root path ( /sdcard ). -->
        <external-path name="CameraPicture" path="Android/data/com.dev2qa.example/cache/" />
    </paths>

6. Main Activity File.

  1. TakePictureActivity.java
    package com.dev2qa.example.camera;
    
    import android.content.ContentResolver;
    import android.content.Context;
    import android.content.Intent;
    import android.graphics.Bitmap;
    import android.graphics.BitmapFactory;
    import android.net.Uri;
    import android.os.Build;
    import android.os.Bundle;
    import android.os.Environment;
    import android.provider.MediaStore;
    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 android.widget.ImageView;
    
    import com.dev2qa.example.R;
    
    import java.io.File;
    import java.io.FileNotFoundException;
    import java.io.IOException;
    import java.io.InputStream;
    
    public class TakePictureActivity extends AppCompatActivity {
    
        // This tag is used for error or debug log.
        private static final String TAG_TAKE_PICTURE = "TAKE_PICTURE";
    
        // This is the request code when start camera activity use implicit intent.
        public static final int REQUEST_CODE_TAKE_PICTURE = 1;
    
        // This imageview is used to show camera taken picture.
        private ImageView takePictureImageView;
    
        // This output image file uri is used by camera app to save taken picture.
        private Uri outputImgUri;
    
        // Save the camera taken picture in this folder.
        private File pictureSaveFolderPath;
    
        // Save imageview currently displayed picture index in all camera taken pictures..
        private int currentDisplayImageIndex = 0;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_take_picture);
    
            setTitle("dev2qa.com - Android Take Picture Example");
    
            // Get this app's external cache directory, manipulate this directory in app do not need android os system permission check.
            // The cache folder is application specific, when the app is uninstalled it will be removed also.
            pictureSaveFolderPath = getExternalCacheDir();
    
            // Get the display camera taken picture imageview object.
            takePictureImageView = (ImageView)findViewById(R.id.take_picture_image_view);
    
            // When you click the image view object, all the taken pictures will be shown one by one like slide.
            takePictureImageView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
    
                    if(pictureSaveFolderPath!=null) {
                        // Get all camera taken pictures in picture save folder.
                        File imageFiles[] = pictureSaveFolderPath.listFiles();
                        if (imageFiles!=null)
                        {
                            // Get content resolver object.
                            ContentResolver contentResolver = getContentResolver();
    
                            int allImagesCount = imageFiles.length;
    
                            // If current display picture index is bigger than image count.
                            if(currentDisplayImageIndex >= allImagesCount-1)
                            {
                                currentDisplayImageIndex = 0;
                            }else
                            {
                                currentDisplayImageIndex++;
                            }
    
                            // Get to be displayed image file object.
                            File displayImageFile = imageFiles[currentDisplayImageIndex];
    
                            // Get display image Uri wrapped object.
                            Uri displayImageFileUri = getImageFileUriByOsVersion(displayImageFile);
    
                            try {
                                // Open display image input stream.
                                InputStream inputStream = contentResolver.openInputStream(displayImageFileUri);
    
                                // Decode the image input stream to a bitmap use BitmapFactory.
                                Bitmap pictureBitmap = BitmapFactory.decodeStream(inputStream);
    
                                // Set the image bitmap in the image view component to display it.
                                takePictureImageView.setImageBitmap(pictureBitmap);
    
                            }catch(FileNotFoundException ex) {
                                Log.e(TAG_TAKE_PICTURE, ex.getMessage(), ex);
                            }
                        }
                    }
                }
            });
    
            // Get the take picture button object.
            Button takePictureButton = (Button)findViewById(R.id.take_picture_button);
    
            // When the button is clicked.
            takePictureButton.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    try {
    
                        // Create a random image file name.
                        String imageFileName = "outputImage_" + System.currentTimeMillis() + ".png";
    
                        // Construct a output file to save camera taken picture temporary.
                        File outputImageFile = new File(pictureSaveFolderPath, imageFileName);
    
                        // If cached temporary file exist then delete it.
                        if (outputImageFile.exists()) {
                            outputImageFile.delete();
                        }
    
                        // Create a new temporary file.
                        outputImageFile.createNewFile();
    
                        // Get the output image file Uri wrapper object.
                        outputImgUri = getImageFileUriByOsVersion(outputImageFile);
    
                        // Startup camera app.
                        // Create an implicit intent which require take picture action..
                        Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
                        // Specify the output image uri for the camera app to save taken picture.
                        cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, outputImgUri);
                        // Start the camera activity with the request code and waiting for the app process result.
                        startActivityForResult(cameraIntent, REQUEST_CODE_TAKE_PICTURE);
    
                    }catch(IOException ex)
                    {
                        Log.e(TAG_TAKE_PICTURE, ex.getMessage(), ex);
                    }
                }
            });
        }
    
        /* Get the file Uri object by android os version.
        *  return a Uri object. */
        private Uri getImageFileUriByOsVersion(File file)
        {
            Uri ret = null;
    
            // Get output image unique resource identifier. This uri is used by camera app to save taken picture temporary.
            if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
            {
                // /sdcard/ folder link to /storage/41B7-12F1 folder
                // so below code return /storage/41B7-12F1
                File externalStorageRootDir = Environment.getExternalStorageDirectory();
    
                // contextRootDir = /data/user/0/com.dev2qa.example/files in my Huawei mate 8.
                File contextRootDir = getFilesDir();
    
                // contextCacheDir = /data/user/0/com.dev2qa.example/cache in my Huawei mate 8.
                File contextCacheDir = getCacheDir();
    
                // For android os version bigger than or equal to 7.0 use FileProvider class.
                // Otherwise android os will throw FileUriExposedException.
                // Because the system considers it is unsafe to use local real path uri directly.
                Context ctx = getApplicationContext();
                ret = FileProvider.getUriForFile(ctx, "com.dev2qa.fileprovider", file);
            }else
            {
                // For android os version less than 7.0 there are no safety issue,
                // So we can get the output image uri by file real local path directly.
                ret = Uri.fromFile(file);
            }
    
            return ret;
        }
    
        /* This method is used to process the result of camera app. It will be invoked after camera app return.
        It will show the camera taken picture in the image view component. */
        @Override
        protected void onActivityResult(int requestCode, int resultCode, Intent data) {
            try {
                // Process result for camera activity.
                if (requestCode == REQUEST_CODE_TAKE_PICTURE) {
    
                    // If camera take picture success.
                    if (resultCode == RESULT_OK) {
    
                        // Get content resolver.
                        ContentResolver contentResolver = getContentResolver();
    
                        // Use the content resolver to open camera taken image input stream through image uri.
                        InputStream inputStream = contentResolver.openInputStream(outputImgUri);
    
                        // Decode the image input stream to a bitmap use BitmapFactory.
                        Bitmap pictureBitmap = BitmapFactory.decodeStream(inputStream);
    
                        // Set the camera taken image bitmap in the image view component to display.
                        takePictureImageView.setImageBitmap(pictureBitmap);
                    }
                }
            }catch(FileNotFoundException ex)
            {
                Log.e(TAG_TAKE_PICTURE, ex.getMessage(), ex);
            }
        }
    }

7. Layout Xml File.

  1. activity_take_picture.xml
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">
    
        <Button
            android:id="@+id/take_picture_button"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Take A Picture"/>
    
        <ImageView
            android:id="@+id/take_picture_image_view"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />
    
    </LinearLayout>

8. Android Manifest Xml File.

  1. AndroidManifest.xml
    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.dev2qa.example">
    
        <!-- Declare bellow permission to make this example 
             compatible with android os version smaller than 4.4. 
             Those version of android os require write external storage permission when write to sdcard. -->
        <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    
        <application
            android:allowBackup="true"
            android:icon="@mipmap/ic_launcher"
            android:label="@string/app_name"
            android:roundIcon="@mipmap/ic_launcher_round"
            android:supportsRtl="true"
            android:theme="@style/AppTheme">
    
            <activity android:name=".camera.TakePictureActivity">
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
    
                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>
    
            <!-- FileProvider settings, after this configuration you can use FileProvider in your activity. -->
            <provider
                android:authorities="com.dev2qa.fileprovider"
                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/shared_file_paths" />
            </provider>
        </application>
    
    </manifest>

9. File Provider Share Folder Configuration File.

  1. shared_file_paths.xml ( saved in folder C:\WorkSpace\Work\dev2qa.com-example-code\AndroidExampleProject\Example\app\src\main\res\xml)
    <?xml version="1.0" encoding="utf-8"?>
    <paths xmlns:android="http://schemas.android.com/apk/res/android">
    
        <!-- Share folder under device root directory. The base folder is new File("/") -->
        <root-path name="root" path="" />
    
        <!-- Share folder under internal file folder. The base folder is context.getFilesDir() -->
        <files-path name="internal_files" path="" />
    
        <!-- Share folder under internal cache folder. The base folder is context.getCacheDir() -->
        <cache-path name="internal_cache" path="" />
    
        <!-- Share folder under public external storage folder.The base folder is Environment.getExternalStorageDirectory()-->
        <external-path name="external" path="Android/data/com.dev2qa.example/cache/" />
    
        <!-- Share folder under app specific external file folder.The base folder is context.getExternalFilesDirs()-->
        <external-files-path name="external_files" path="" />
    
        <!-- Share folder under app specific external cache folder.The base folder is context.getExternalCacheDirs()-->
        <external-cache-path name="external_cache" path="" />
    </paths>

4 thoughts on “How To Open Camera In Android Programmatically Using Intent”

  1. Has this solution been tested on Android 8.1, I tried implementing opening camera using startActivityForResult () but my application is killed before result is returned to the fragment.

Leave a Comment

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.