#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().