Showing posts with label Android N File Uri. Show all posts

How to use Camera API for Android N and above devices in Android


Introduction:

In my previous article, we have learned How to handle “android.os.FileUriExposedException”, if we have an app that shares files with other apps using an Uri on API 24+. In this article, we will learn “How to use Camera Intent in Android N above devices”.

Creating New Project with Android Studio:

  1. Open Android Studio and Select Create new project. 
  2. Name the project as your wish and select your activity template.


  3. Click “finish” button to create new project in Android Studio.

Steps to use Camera API:

  1. We already know how to open camera from our app using intents. But for Android N & above devices, Google changed the approach for accessing Camera API.
  2. In this step, we will see how to use Camera Intent for Pre Android N & Android N above devices.
  3. Open your MainActivity.java file and add a button with click event to open Camera. The following code snippet shows the camera intent.
    btnPickCamera.setOnClickListener(new View.OnClickListener() {
     @Override
     public void onClick(View view) {
      // Checking Permission for Android M and above
      if (ActivityCompat.checkSelfPermission(MainActivity.this,
        Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED
        || ActivityCompat.checkSelfPermission(MainActivity.this,
        Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
       ActivityCompat.requestPermissions(MainActivity.this,
         new String[]{Manifest.permission.CAMERA, Manifest.permission.READ_EXTERNAL_STORAGE}, PICK_FROM_CAMERA);
       return;
      }
    
      if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
       ContentValues values = new ContentValues(1);
       values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpg");
       outputFileUri = getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
       Intent captureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
       captureIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
       captureIntent.putExtra(MediaStore.EXTRA_OUTPUT, outputFileUri);
       startActivityForResult(captureIntent, PICK_FROM_CAMERA);
      } else {
       Intent captureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
       File file = new File(Environment.getExternalStorageDirectory(), "MyPhoto.jpg");
       outputFileUri = Uri.fromFile(file);
       captureIntent.putExtra(MediaStore.EXTRA_OUTPUT, outputFileUri);
       startActivityForResult(captureIntent, PICK_FROM_CAMERA);
      }
     }
    });
  4. Here, I have added runtime permission checking for Android M & above devices.
    ContentValues values = new ContentValues(1);
    values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpg");
    outputFileUri = getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
    Intent captureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
    captureIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION |       Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
    captureIntent.putExtra(MediaStore.EXTRA_OUTPUT, outputFileUri);
    startActivityForResult(captureIntent, PICK_FROM_CAMERA);
  5. Here, we have created ContentValues and added MIME type as image. Then created an output Uri for the camera api output image.
  6. Then we have added flags “FLAG_GRANT_READ_URI_PERMISSION” and “FLAG_GRANT_WRITE_URI_PERMISSION” to allow the camera api to take image in Android N & above devices.
  7. We can retrieve the picked camera image by “onActivityResult” and same like the old approach

Full Code:

The following code shows, How to access image from Gallery, How to take picture from camera & How to open file using intent in Android N & above devices.

public class MainActivity extends AppCompatActivity {

    ImageView imgPreview;
    TextView imgPath;
    Button btnPickCamera;
    Button btnPickGallery;
    Button btnOpenFile;

    Uri outputFileUri;
    private static final int PICK_FROM_CAMERA = 1;
    private static final int PICK_FROM_GALLERY = 2;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initViews();
        initOperations();
    }

    private void initViews() {
        imgPreview = findViewById(R.id.imgPreview);
        imgPath = findViewById(R.id.imgPath);
        btnPickCamera = findViewById(R.id.btnCapture);
        btnPickGallery = findViewById(R.id.btnGallery);
        btnOpenFile = findViewById(R.id.btnOpenImg);
    }

    private void initOperations() {
        btnPickGallery.setOnClickListener(new View.OnClickListener() {
            @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
            @Override
            public void onClick(View view) {
                // Checking Permission for Android M and above
                if (ActivityCompat.checkSelfPermission(MainActivity.this,
                        Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
                    ActivityCompat.requestPermissions(MainActivity.this,
                            new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, PICK_FROM_GALLERY);
                    return;
                }
                Intent galleryIntent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
                // Start the Intent
                startActivityForResult(galleryIntent, PICK_FROM_GALLERY);
            }
        });

        btnPickCamera.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                // Checking Permission for Android M and above
                if (ActivityCompat.checkSelfPermission(MainActivity.this,
                        Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED
                        || ActivityCompat.checkSelfPermission(MainActivity.this,
                        Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
                    ActivityCompat.requestPermissions(MainActivity.this,
                            new String[]{Manifest.permission.CAMERA, Manifest.permission.READ_EXTERNAL_STORAGE}, PICK_FROM_CAMERA);
                    return;
                }

                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                    ContentValues values = new ContentValues(1);
                    values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpg");
                    outputFileUri = getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
                    Intent captureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
                    captureIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
                    captureIntent.putExtra(MediaStore.EXTRA_OUTPUT, outputFileUri);
                    startActivityForResult(captureIntent, PICK_FROM_CAMERA);
                } else {
                    Intent captureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
                    File file = new File(Environment.getExternalStorageDirectory(), "MyPhoto.jpg");
                    outputFileUri = Uri.fromFile(file);
                    captureIntent.putExtra(MediaStore.EXTRA_OUTPUT, outputFileUri);
                    startActivityForResult(captureIntent, PICK_FROM_CAMERA);
                }
            }
        });

        btnOpenFile.setOnClickListener(new View.OnClickListener() {
            @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
            @Override
            public void onClick(View v) {
                // Checking Permission for Android M and above
                if (ActivityCompat.checkSelfPermission(MainActivity.this,
                        Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
                    ActivityCompat.requestPermissions(MainActivity.this,
                            new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, PICK_FROM_GALLERY);
                    return;
                }
                File file = new File(imgPath.getText().toString());
                Intent intent = new Intent(Intent.ACTION_VIEW);
                intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                    Uri apkURI = FileProvider.getUriForFile(getApplicationContext(), getPackageName() + ".provider", file);
                    intent.setDataAndType(apkURI, "image/jpg");
                    intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
                } else {
                    intent.setDataAndType(Uri.fromFile(file), "image/jpg");
                }
                startActivity(intent);
            }
        });
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        Bitmap bitmap;
        switch (requestCode) {
            case PICK_FROM_CAMERA:
                if (resultCode == Activity.RESULT_OK) {

                    Uri selectedImage = outputFileUri;
                    ContentResolver cr = getContentResolver();
                    getContentResolver().notifyChange(selectedImage, null);
                    try {
                        bitmap = android.provider.MediaStore.Images.Media.getBitmap(cr, selectedImage);
                        int nh = (int) ( bitmap.getHeight() * (512.0 / bitmap.getWidth()) );
                        bitmap = Bitmap.createScaledBitmap(bitmap, 512, nh, true);
                        imgPreview.setImageBitmap(bitmap);
                        imgPath.setText(outputFileUri.getPath());
                    } catch (Exception e) {
                        Toast.makeText(this, "Failed to load", Toast.LENGTH_SHORT)
                                .show();
                    }
                }
                break;
            case PICK_FROM_GALLERY:
                if (resultCode == Activity.RESULT_OK) {
                    //pick image from gallery
                    Uri selectedImage = data.getData();
                    String[] filePathColumn = {MediaStore.Images.Media.DATA};
                    // Get the cursor
                    assert selectedImage != null;
                    Cursor cursor = getContentResolver().query(selectedImage, filePathColumn,
                            null, null, null);
                    // Move to first row
                    assert cursor != null;
                    cursor.moveToFirst();

                    int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
                    String imgDecodableString = cursor.getString(columnIndex);
                    cursor.close();
                    bitmap = BitmapFactory.decodeFile(imgDecodableString);
                    imgPreview.setImageBitmap(bitmap);
                    imgPath.setText(imgDecodableString);
                }
                break;
        }
    }
}

Download Code 

You can download the full source code from GitHub. If you like this article, do like, share and star the repo in GitHub.

How to handle “android.os.FileUriExposedException” in Android

Introduction:

In this article, we will learn How to handle “android.os.FileUriExposedException”, if we have an app that shares files with other apps using an Uri on API 24+. As of Android N, we need to use FileProvider API 

Creating New Project with Android Studio

  1. Open Android Studio and Select Create new project. 
  2. Name the project as your wish and select your activity template.


  3. Click “finish” button to create new project in Android Studio.

Steps to Change File Provider API 

To replace “file://” to “uri://”, We should follow the three steps.

Step 1: Change Manifest Entry
  1. Add <provider /> tag with FileProvider inside the tag as shown in the below code.
    <provider
     android:name="android.support.v4.content.FileProvider"
     android:authorities="${applicationId}.provider"
     android:exported="false"
     android:grantUriPermissions="true">
     <meta-data
      android:name="android.support.FILE_PROVIDER_PATHS"
      android:resource="@xml/provider_paths"/>
    </provider>
  2. Here, provider_paths is a xml file which is used to specify the path to be accessed via File Provider API for Android N & above devices.
  3. Don't forget to add the following permission in your manifest file
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
Step 2: Create XML file in res/xml/provider_paths.xml
  1. Create a new xml folder in res folder. Then create xml file and named as provider_paths.xml
  2. Add the following code to the file.
    <?xml version="1.0" encoding="utf-8"?>
    <paths>
        <external-path name="external_files" path="."/>
    </paths>
Step 3: Create an Intent to open file for Android N
  1. Change the normal Uri method for Android N.
    File file = new File("File Path");
    Uri.fromFile(file)
    To
    File file = new File("File Path");
    Uri apkURI = FileProvider.getUriForFile(getApplicationContext(), getPackageName() + ".provider", file);
  2. Then Grant Read Uri Permission for Android N & above devices. The following code shows how to use Open file Intent for Android N devices & before Android N devices.
    File file = new File("File Path");
    Intent intent = new Intent(Intent.ACTION_VIEW);
    intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
     Uri apkURI = FileProvider.getUriForFile(getApplicationContext(), getPackageName() + ".provider", file);
     intent.setDataAndType(apkURI, "image/jpg");
     intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
    } else {
     intent.setDataAndType(Uri.fromFile(file), "image/jpg");
    }
    startActivity(intent);

Reference:

https://developer.android.com/reference/android/support/v4/content/FileProvider.html
If you have any doubt or need any help, contact me.

Next Article:

It is a first part for accessing file uri for Android N & above devices. Next article, we will learn how to access Camera API for Android N & above devices.