Search code examples
androidandroid-cameraandroid-11

Capture and crop image in Android 11 (R)


As per android R privacy policy changes, I want to perform the capture and crop image feature for android R devices. I tried the below method but it saving the empty file (file is creating in a specified folder but having a size of 0kb).

I'm using Android-image-cropper library to crop images.

public static File createImageFile(Context context) throws IOException {
    String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(new Date());
    String imageFileName = "JPEG_" + timeStamp + ".jpg";

    File storageDir, image;

    if(SDK_INT >= Build.VERSION_CODES.Q){
        OutputStream outputStream;
        ContentResolver contentResolver = context.getContentResolver();
        ContentValues contentValues = new ContentValues();
        contentValues.put(MediaStore.MediaColumns.DISPLAY_NAME, imageFileName);
        contentValues.put(MediaStore.MediaColumns.MIME_TYPE, "image/jpeg");
        contentValues.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_PICTURES +  File.separator + SD_FOLDER_NAME);
        Uri imageUri = contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues);
        outputStream = contentResolver.openOutputStream(Objects.requireNonNull(imageUri));
        Objects.requireNonNull(outputStream);
        storageDir = new File(Environment.DIRECTORY_PICTURES +  File.separator + SD_FOLDER_NAME);
    }else{
        storageDir = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + SD_FOLDER_NAME);
    }

    if (!storageDir.exists()) {
        storageDir.mkdirs();
    }

    image = new File(storageDir, imageFileName);

    if (image.createNewFile()) {
        Log.d(TAG, ":Image file created");
    } else {
        Log.d(TAG, ":Image file not created");
    }
    return image;
}

Below are my camera open and capture functions:

 private void openCamera() {
        Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        Uri photoURI = null;
        try {
            fileUri = Utils.createImageFile(requireContext());
            if(SDK_INT >= Build.VERSION_CODES.Q)
                photoURI = FileProvider.getUriForFile(requireActivity(), requireActivity().getPackageName(), fileUri);
            else
                photoURI = FileProvider.getUriForFile(requireActivity(), requireActivity().getPackageName() + ".com.enrich.salonapp.provider", fileUri);
        } catch (IOException e) {
            e.printStackTrace();
        }
        intent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI);
        startActivityForResult(intent, REQUEST_CODE_CAMERA_PICTURE);
    }

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == PictureSelectorDialog.REQUEST_CODE_CAMERA_PICTURE && resultCode == Activity.RESULT_OK) {
            imageCapture.onImageCaptured(fileUri.getAbsolutePath(), false);
        } else if (requestCode == PictureSelectorDialog.REQUEST_CODE_GALLERY_PICTURE && resultCode == Activity.RESULT_OK) {
            if (FileUtils.getPath(getActivity(), data.getData()) == null) {
                imageCapture.onImageCaptured(data.getData().toString(), true);
            } else {
                imageCapture.onImageCaptured(FileUtils.getPath(getActivity(), data.getData()), false);
            }
        }

        this.dismissAllowingStateLoss();
    }

Also, I didn't found how to get URI using file provider.

if(SDK_INT >= Build.VERSION_CODES.Q)
                photoURI = FileProvider.getUriForFile(requireActivity(), requireActivity().getPackageName(), fileUri);

Solution

  • After seeing multiple answers, developer docs, and many more. I ended up with this below working solution, Hope this will help someone.

    AndroidManifest

     <uses-permission android:name="android.permission.CAMERA" />
     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
            android:maxSdkVersion="29"/>
    
    android:requestLegacyExternalStorage="true"
    
     <provider
         android:name=".util.GenericFileProvider"
         android:authorities="${applicationId}.provider.profile"
         android:exported="false"
         android:grantUriPermissions="true">
         <meta-data
              android:name="android.support.FILE_PROVIDER_PATHS"
              android:resource="@xml/provider_paths"/>
     </provider>
    

    PictureSelectorDialog.java

    public static final int REQUEST_CODE_CAMERA_PICTURE = 1232;
    public static final int REQUEST_CODE_GALLERY_PICTURE = 1233;
    private File fileUri;
    private ImageCapture imageCapture;
    private boolean isDenied = false;
    
    private void openGallery() {
            Intent intent;
            intent = new Intent(Intent.ACTION_PICK,
                    android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
            startActivityForResult(Intent.createChooser(intent, getString(R.string.choose_from_gallery)), REQUEST_CODE_GALLERY_PICTURE);
        }
    
        private void openCamera() {
            Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
                Uri photoURI = null;
                try {
                    fileUri = Utils.createImageFile(requireContext());
                    photoURI = FileProvider.getUriForFile(requireContext(), BuildConfig.APPLICATION_ID + ".provider.profile", fileUri);
                } catch (IOException e) {
                    e.printStackTrace();
                }
                intent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI);
                startActivityForResult(intent, REQUEST_CODE_CAMERA_PICTURE);
        }
    
    
    
      @Override
        public void onActivityResult(int requestCode, int resultCode, Intent data) {
            super.onActivityResult(requestCode, resultCode, data);
            if (requestCode == PictureSelectorDialog.REQUEST_CODE_CAMERA_PICTURE && resultCode == Activity.RESULT_OK) {
                    imageCapture.onImageCaptured(fileUri.getAbsolutePath(), false);
            } else if (requestCode == PictureSelectorDialog.REQUEST_CODE_GALLERY_PICTURE && resultCode == Activity.RESULT_OK) {
                if (FileUtils.getPath(getActivity(), data.getData()) == null) {
                    Uri uri = data.getData();
                    ParcelFileDescriptor parcelFileDescriptor;
                    try {
                        parcelFileDescriptor = requireContext().getContentResolver().openFileDescriptor(uri, "r");
                        FileDescriptor fileDescriptor = parcelFileDescriptor.getFileDescriptor();
                        Bitmap image = BitmapFactory.decodeFileDescriptor(fileDescriptor);
                        parcelFileDescriptor.close();
    
                        File tempFile = createImageFile(requireContext());
    
                        ByteArrayOutputStream bos = new ByteArrayOutputStream();
                        image.compress(Bitmap.CompressFormat.JPEG, 100 , bos);
                        byte[] bitmapData = bos.toByteArray();
    
                        FileOutputStream fos = new FileOutputStream(tempFile);
                        fos.write(bitmapData);
    
                        imageCapture.onImageCaptured( tempFile.getAbsolutePath(), true);
    
                        fos.flush();
                        fos.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                } else {
                    imageCapture.onImageCaptured(FileUtils.getPath(getActivity(), data.getData()), false);
                }
            }
    
            this.dismissAllowingStateLoss();
        }
    
    public interface ImageCapture {
            void onImageCaptured(String path, boolean isGooglePhotoURI);
        }
    

    Utils.java

    public static File createImageFile(Context context) throws IOException {
            String timeStamp = new SimpleDateFormat(YYYY_MM_DD_HH_MM_SS_FOR_IMAGE_NAMING, Locale.getDefault()).format(new Date());
            String imageFileName = "PROFILE_PICTURE_" + timeStamp;
            File image, storageDir;
    
            if (SDK_INT < Build.VERSION_CODES.Q) {
                storageDir = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + YOUR_FOLDER_NAME);
                if (!storageDir.exists()) {
                    storageDir.mkdirs();
                }
                image = new File(storageDir, imageFileName + ".jpg");
                image.createNewFile();
            } else {
                storageDir = context.getExternalFilesDir(Environment.DIRECTORY_PICTURES + File.separator + YOUR_FOLDER_NAME);
                image = File.createTempFile(imageFileName, ".jpg", storageDir);
                String currentPhotoPath = image.getAbsolutePath();
            }
    
            return image;
        }