Захват и обрезка изображения в Android 11 (R)

#android #android-camera #android-11

Вопрос:

В соответствии с изменениями политики конфиденциальности Android R я хочу выполнить функцию захвата и обрезки изображений для устройств Android R. Я попробовал приведенный ниже метод, но он сохранил пустой файл (файл создается в указанной папке, но имеет размер 0 кб).

Я использую библиотеку обрезки изображений Android для обрезки изображений.

 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;
}
 

Ниже приведены функции открытия и захвата моей камеры:

  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 amp;amp; resultCode == Activity.RESULT_OK) {
            imageCapture.onImageCaptured(fileUri.getAbsolutePath(), false);
        } else if (requestCode == PictureSelectorDialog.REQUEST_CODE_GALLERY_PICTURE amp;amp; 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();
    }
 

Кроме того, я не нашел, как получить URI с помощью поставщика файлов.

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

Комментарии:

1. Пожалуйста, укажите полные пути. Как для старых, так и для новых.

2. @blackapps не понял. Не могли бы вы, пожалуйста, кратко изложить то, что вы хотите сказать?

3. storageDir = new File(Environment.DIRECTORY_PICTURES File.separator SD_FOLDER_NAME); Это бессмысленный код, который возится с классом файла, так как вы только что получили хороший uri от .insert(). Используйте этот uri для записи файла.

4. Были заданы полные пути storageDir.getAbsolutePath() и image.getAbsolutePath ().

5. @blackapps как я могу получить фото из файла в Sdk >= Q условие? что написать в авторитетном месте?

Ответ №1:

После просмотра нескольких ответов, документов разработчика и многого другого. Я закончил с этим ниже рабочим решением, надеюсь, это кому-нибудь поможет.

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 amp;amp; resultCode == Activity.RESULT_OK) {
                imageCapture.onImageCaptured(fileUri.getAbsolutePath(), false);
        } else if (requestCode == PictureSelectorDialog.REQUEST_CODE_GALLERY_PICTURE amp;amp; 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;
    }
 

Комментарии:

1. Единственная проблема в вашем подходе будет заключаться в том, что фотографии, снятые на <Android Q, будут храниться на устройстве даже после удаления приложения, но для >= Android Q они будут удалены, как только приложение будет удалено, так как вы используете getExternalFilesDir().