Я хочу сохранить изображение, снятое камерой из моего приложения, прямо на USB-накопитель, подключенный к моему телефону. Есть ли способ сделать это, не прося пользователя выбрать каталог из SAF? Я хочу использовать хранилище с ограниченным доступом, поскольку я ориентируюсь на Android 11 и более поздние версии.
К устройствам не подключена sd карта.
Я могу хранить файлы на USB-накопителе на Android 10 с этим кодом, но не на Android 11
// I pass the image taken from the camera by parameter
private void legacyToUsb(File image){
File[] externalStorageVolumes = ContextCompat.getExternalFilesDirs(getApplicationContext(), null);
String path = null;
for (File externalDir : externalStorageVolumes) {
Log.d(TAG, "Found dir at : " + externalDir);
path = externalDir.getPath();
}
if (path == null) {
showToast("Failed to found mounted device");
return;
}
String fileName = mDateFormat.format(System.currentTimeMillis()) + ".jpg";
File destFile = new File(path, fileName);
showToast("Going to save data to " + destFile.getPath());
if (destFile == null)
showToast("Failed to open file");
FileOutputStream os;
String msg = "Successfully saved to " + destFile.getPath();
try{
byte[] imageData = getBytesFromFile(image);
os = new FileOutputStream(destFile);
os.write(imageData);
} catch (IOException e) {
e.printStackTrace();
msg = "Failed to save file : " + e.getMessage();
}
showToast(msg);
}
Однако на Android 11 это не работает (я не могу создать файл на USB-накопителе), потому что getExternalFilesDirs()
не сообщает мне путь к usb otg.
ContextCompat.getExternalFilesDirs(<context>)
возвращает:
Android 10
Found dir at : /storage/emulated/10/Android/data/com.example.MyApp/files
Found dir at : /storage/4406-15E5/Android/data/com.example.MyApp/files //I'm using this one
Android 11
Found dir at : /storage/emulated/0/Android/data/com.example.MyApp/files
Насколько я понимаю, хранилище с ограниченным объемом удалено возможность доступа к съемному хранилищу с помощью этих функций. Так что я пытаюсь по-другому
private void scopedToUsb(File image){
ContentResolver resolver = getContentResolver();
String fileName = mDateFormat.format(System.currentTimeMillis());
ContentValues fileDetails = new ContentValues();
fileDetails.put(MediaStore.Images.Media.DISPLAY_NAME, fileName);
fileDetails.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg");
fileDetails.put(MediaStore.Images.Media.RELATIVE_PATH, Environment.DIRECTORY_PICTURES);
fileDetails.put(MediaStore.Images.Media.IS_PENDING, 1);
Set<String> volumeNames = MediaStore.getExternalVolumeNames(getApplicationContext());
String storageVolume = null;
// Get the first volume found here, it returns the hex with which the usb stick is identified
// in my case 4406-15e5
for (String volumeName : volumeNames){
storageVolume = volumeName;
Log.d(TAG, "Found volumeName : "+ volumeName);
break;
}
// I have tried here MediaStore.VOLUME_EXTERNAL and MediaStore.VOLUME_EXTERNAL_PRIMARY
// They both point to the same directory not in the usb stick
Uri collection = MediaStore.Images.Media.getContentUri(storageVolume);
Uri imageUri = resolver.insert(collection, fileDetails);
if(imageUri == null) {
showToast("Failed to insert image row to ContentResolver");
return;
}
Log.d(TAG, "Inserted, going to create ouput stream");
OutputStream out = null;
try {
out = resolver.openOutputStream(imageUri);
Bitmap bm = BitmapFactory.decodeFile(image.getAbsolutePath());
bm.compress(Bitmap.CompressFormat.JPEG, 100, out);
out.close();
} catch (IOException e) {
e.printStackTrace();
showToast("Failed to sqve picture to Usb");
return;
}
showToast("Successfully saved to " + collection.getPath());
}
но я получаю исключение в этой строке
Uri imageUri = resolver.insert(collection, fileDetails);
исключение
java.lang.IllegalStateException: Failed to create directory: /mnt/media_rw/4406-15E5/Pictures/.pending-1621349186-2021-05-11-16-46-26-671.jpg
at android.os.Parcel.createExceptionOrNull(Parcel.java:2384)
at android.os.Parcel.createException(Parcel.java:2360)
at android.os.Parcel.readException(Parcel.java:2343)
at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:190)
at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:142)
at android.content.ContentProviderProxy.insert(ContentProviderNative.java:549)
at android.content.ContentResolver.insert(ContentResolver.java:2177)
at android.content.ContentResolver.insert(ContentResolver.java:2138)
at com.example.MyApp.MainActivity.scopedToUsb(MainActivity.java:368)
at com.example.MyApp.MainActivity.saveToUsb(MainActivity.java:294)
at com.example.MyApp.MainActivity.access$000(MainActivity.java:72)
at com.example.MyApp.MainActivity$1.onImageSaved(MainActivity.java:273)
at androidx.camera.core.ImageCapture$2.onImageSaved(ImageCapture.java:844)
at androidx.camera.core.ImageSaver.lambda$postSuccess$1$ImageSaver(ImageSaver.java:308)
at androidx.camera.core.-$$Lambda$ImageSaver$29vxg6qyjKwPRXgWrIwgYVInWKE.run(Unknown Source:4)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:923)
Является ли это возможным ? У меня нет разрешения? я должен обязательно использовать Storage Acess Framework? Спасибо
on Android 11 this doesn't work as I cannot get the file inside the usb
Что ты имеешь в виду? Я не могу следовать за тобой. - person blackapps   schedule 11.05.2021On Android 10, I can do this
Почему ты не можешь сделать это 11, я хотел спросить. Ты не сказал - person blackapps   schedule 11.05.2021legacyToUsb()
функцию с телефоном Android 11, он сохраняет изображение в/storage/emulated/0/Android/data/com.example.MyApp/files
, что не соответствует USB-накопителю. Я думаю, что вопрос был неясным, поэтому я немного изменил фразу. Спасибо ! - person afvmil   schedule 12.05.2021However, on Android 11 that doesn't work
. Таким образом, код выше этого предложения не работает на Android 11. Хорошо. Но почему нет? Вы еще не сказали. Теперь я спрашиваю в третий раз: почему этот код не работает на Android 11? А почему на Android 10 работает? - person blackapps   schedule 12.05.2021I cannot get the file inside the usb
Очень непонятное предложение. Вы имеете в виду:I cannot create a file on the usb-stick.
? Пожалуйста, будьте ясны. - person blackapps   schedule 12.05.2021Apparently ContextCompat.getExternalFilesDirs(<context>) returns the path to /storage/emulated/0/Android/data/com.example.MyApp/files which is located internally on the phone
Хорошо, если это работает на Android 10 и 11, тогда в чем разница? И эта функция возвращает массив. Расскажите, пожалуйста, об этом массиве для Android 10 и об этом массиве для Android11. - person blackapps   schedule 12.05.2021And that function returns an array. So please tell something about that array for Android 10 and about that array for Android 11.
В чем разница? И в оба использованных устройства вставлена карта micro sd? - person blackapps   schedule 12.05.2021for (File externalDir : externalStorageVolumes) { Log.d(TAG, "Found dir at : " + externalDir); }
Скажите, пожалуйста, что зарегистрировано на устройстве Android 10. После этого расскажите, что зарегистрировано на устройстве Android 11. Поместите все в свой пост там, где вы объясняете, что это не работает для Android 11. - person blackapps   schedule 12.05.2021However, on Android 11 that doesn't work as I cannot see the file inside the usb stick after calling the legacyToUsb() function.
Но ... причина не в этом. Лучше скажи настоящую причину. Я спрашиваю об этом с момента моего первого комментария. - person blackapps   schedule 12.05.2021getExternalFilesDirs() doesn't give me the path to the removable storage.
Ну .. да и нет. Это даст путь к съемной карте micro sd (в основном как второй элемент), если вы вставили ее в свое устройство. На Android 10 он также часто указывал путь к USB-накопителю. Но на Android 11 последнего больше нет. И это ваша проблема, и она имеет мало общего с вашим неправильным кодом, а только с тем, как ведет себя getExternalFilesDir (). И это вы должны были сообщить из первого предложения вашего сообщения. - person blackapps   schedule 12.05.2021getExternalFilesDirs()
не возвращает путь к usb otg на нем, который совпадает с здесь. Вы предлагаете использовать SAF, но есть ли способ получить доступ к USB-накопителю без него? - person afvmil   schedule 12.05.2021