Fix crash when attempting to save octet-stream data to a media directory.
This commit is contained in:
parent
874067909d
commit
6164152b15
1 changed files with 66 additions and 37 deletions
|
@ -87,12 +87,17 @@ public class SaveAttachmentTask extends ProgressDialogAsyncTask<SaveAttachmentTa
|
||||||
for (Attachment attachment : attachments) {
|
for (Attachment attachment : attachments) {
|
||||||
if (attachment != null) {
|
if (attachment != null) {
|
||||||
directory = saveAttachment(context, attachment);
|
directory = saveAttachment(context, attachment);
|
||||||
if (directory == null) return new Pair<>(FAILURE, null);
|
if (directory == null) {
|
||||||
|
return new Pair<>(FAILURE, null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (attachments.length > 1) return new Pair<>(SUCCESS, null);
|
if (attachments.length > 1) {
|
||||||
else return new Pair<>(SUCCESS, directory);
|
return new Pair<>(SUCCESS, null);
|
||||||
|
} else {
|
||||||
|
return new Pair<>(SUCCESS, directory);
|
||||||
|
}
|
||||||
} catch (IOException ioe) {
|
} catch (IOException ioe) {
|
||||||
Log.w(TAG, ioe);
|
Log.w(TAG, ioe);
|
||||||
return new Pair<>(FAILURE, null);
|
return new Pair<>(FAILURE, null);
|
||||||
|
@ -110,28 +115,22 @@ public class SaveAttachmentTask extends ProgressDialogAsyncTask<SaveAttachmentTa
|
||||||
|
|
||||||
fileName = sanitizeOutputFileName(fileName);
|
fileName = sanitizeOutputFileName(fileName);
|
||||||
|
|
||||||
Uri outputUri = getMediaStoreContentUriForType(contentType);
|
CreateMediaUriResult result = createMediaUri(getMediaStoreContentUriForType(contentType), contentType, fileName);
|
||||||
Uri mediaUri = createOutputUri(outputUri, contentType, fileName);
|
|
||||||
ContentValues updateValues = new ContentValues();
|
ContentValues updateValues = new ContentValues();
|
||||||
|
|
||||||
if (mediaUri == null) {
|
|
||||||
Log.w(TAG, "Failed to create mediaUri for " + contentType);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
try (InputStream inputStream = PartAuthority.getAttachmentStream(context, attachment.uri)) {
|
try (InputStream inputStream = PartAuthority.getAttachmentStream(context, attachment.uri)) {
|
||||||
|
|
||||||
if (inputStream == null) {
|
if (inputStream == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Objects.equals(outputUri.getScheme(), ContentResolver.SCHEME_FILE)) {
|
if (Objects.equals(result.outputUri.getScheme(), ContentResolver.SCHEME_FILE)) {
|
||||||
try (OutputStream outputStream = new FileOutputStream(mediaUri.getPath())) {
|
try (OutputStream outputStream = new FileOutputStream(result.mediaUri.getPath())) {
|
||||||
StreamUtil.copy(inputStream, outputStream);
|
StreamUtil.copy(inputStream, outputStream);
|
||||||
MediaScannerConnection.scanFile(context, new String[]{mediaUri.getPath()}, new String[]{contentType}, null);
|
MediaScannerConnection.scanFile(context, new String[] { result.mediaUri.getPath() }, new String[] { contentType }, null);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
try (OutputStream outputStream = context.getContentResolver().openOutputStream(mediaUri, "w")) {
|
try (OutputStream outputStream = context.getContentResolver().openOutputStream(result.mediaUri, "w")) {
|
||||||
long total = StreamUtil.copy(inputStream, outputStream);
|
long total = StreamUtil.copy(inputStream, outputStream);
|
||||||
if (total > 0) {
|
if (total > 0) {
|
||||||
updateValues.put(MediaStore.MediaColumns.SIZE, total);
|
updateValues.put(MediaStore.MediaColumns.SIZE, total);
|
||||||
|
@ -145,10 +144,10 @@ public class SaveAttachmentTask extends ProgressDialogAsyncTask<SaveAttachmentTa
|
||||||
}
|
}
|
||||||
|
|
||||||
if (updateValues.size() > 0) {
|
if (updateValues.size() > 0) {
|
||||||
getContext().getContentResolver().update(mediaUri, updateValues, null, null);
|
getContext().getContentResolver().update(result.mediaUri, updateValues, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
return outputUri.getLastPathSegment();
|
return result.outputUri.getLastPathSegment();
|
||||||
}
|
}
|
||||||
|
|
||||||
private @NonNull Uri getMediaStoreContentUriForType(@NonNull String contentType) {
|
private @NonNull Uri getMediaStoreContentUriForType(@NonNull String contentType) {
|
||||||
|
@ -186,7 +185,7 @@ public class SaveAttachmentTask extends ProgressDialogAsyncTask<SaveAttachmentTa
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a path to a shared media (or documents) directory for the type of the file.
|
* Returns a path to a shared media (or documents) directory for the type of the file.
|
||||||
*
|
* <p>
|
||||||
* Note that this method attempts to create a directory if the path returned from
|
* Note that this method attempts to create a directory if the path returned from
|
||||||
* Environment object does not exist yet. The attempt may fail in which case it attempts
|
* Environment object does not exist yet. The attempt may fail in which case it attempts
|
||||||
* to return the default "Document" path. It finally returns null if it also fails.
|
* to return the default "Document" path. It finally returns null if it also fails.
|
||||||
|
@ -228,7 +227,7 @@ public class SaveAttachmentTask extends ProgressDialogAsyncTask<SaveAttachmentTa
|
||||||
return new File(fileName).getName();
|
return new File(fileName).getName();
|
||||||
}
|
}
|
||||||
|
|
||||||
private @Nullable Uri createOutputUri(@NonNull Uri outputUri, @NonNull String contentType, @NonNull String fileName)
|
private @NonNull CreateMediaUriResult createMediaUri(@NonNull Uri outputUri, @NonNull String contentType, @NonNull String fileName)
|
||||||
throws IOException
|
throws IOException
|
||||||
{
|
{
|
||||||
String[] fileParts = getFileNameParts(fileName);
|
String[] fileParts = getFileNameParts(fileName);
|
||||||
|
@ -241,6 +240,16 @@ public class SaveAttachmentTask extends ProgressDialogAsyncTask<SaveAttachmentTa
|
||||||
mimeType = contentType;
|
mimeType = contentType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (MediaUtil.isOctetStream(mimeType)) {
|
||||||
|
if (outputUri.equals(StorageUtil.getAudioUri())) {
|
||||||
|
mimeType = "audio/*";
|
||||||
|
} else if (outputUri.equals(StorageUtil.getVideoUri())) {
|
||||||
|
mimeType = "video/*";
|
||||||
|
} else if (outputUri.equals(StorageUtil.getImageUri())) {
|
||||||
|
mimeType = "image/*";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ContentValues contentValues = new ContentValues();
|
ContentValues contentValues = new ContentValues();
|
||||||
contentValues.put(MediaStore.MediaColumns.DISPLAY_NAME, fileName);
|
contentValues.put(MediaStore.MediaColumns.DISPLAY_NAME, fileName);
|
||||||
contentValues.put(MediaStore.MediaColumns.MIME_TYPE, mimeType);
|
contentValues.put(MediaStore.MediaColumns.MIME_TYPE, mimeType);
|
||||||
|
@ -250,6 +259,7 @@ public class SaveAttachmentTask extends ProgressDialogAsyncTask<SaveAttachmentTa
|
||||||
if (Build.VERSION.SDK_INT > 28) {
|
if (Build.VERSION.SDK_INT > 28) {
|
||||||
int i = 0;
|
int i = 0;
|
||||||
String displayName = fileName;
|
String displayName = fileName;
|
||||||
|
|
||||||
while (pathInCache(outputUri, displayName) || displayNameTaken(outputUri, displayName)) {
|
while (pathInCache(outputUri, displayName) || displayNameTaken(outputUri, displayName)) {
|
||||||
displayName = base + "-" + (++i) + "." + extension;
|
displayName = base + "-" + (++i) + "." + extension;
|
||||||
}
|
}
|
||||||
|
@ -271,7 +281,7 @@ public class SaveAttachmentTask extends ProgressDialogAsyncTask<SaveAttachmentTa
|
||||||
}
|
}
|
||||||
|
|
||||||
putInCache(outputUri, outputFile.getPath());
|
putInCache(outputUri, outputFile.getPath());
|
||||||
return Uri.fromFile(outputFile);
|
return new CreateMediaUriResult(outputUri, Uri.fromFile(outputFile));
|
||||||
} else {
|
} else {
|
||||||
String dir = getExternalPathForType(contentType);
|
String dir = getExternalPathForType(contentType);
|
||||||
if (dir == null) {
|
if (dir == null) {
|
||||||
|
@ -290,7 +300,16 @@ public class SaveAttachmentTask extends ProgressDialogAsyncTask<SaveAttachmentTa
|
||||||
contentValues.put(MediaStore.MediaColumns.DATA, dataPath);
|
contentValues.put(MediaStore.MediaColumns.DATA, dataPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
return getContext().getContentResolver().insert(outputUri, contentValues);
|
try {
|
||||||
|
return new CreateMediaUriResult(outputUri, getContext().getContentResolver().insert(outputUri, contentValues));
|
||||||
|
} catch (RuntimeException e) {
|
||||||
|
if (e instanceof IllegalArgumentException || e.getCause() instanceof IllegalArgumentException) {
|
||||||
|
Log.w(TAG, "Unable to create uri in " + outputUri + " with mimeType [" + mimeType + "]");
|
||||||
|
return new CreateMediaUriResult(StorageUtil.getDownloadUri(), getContext().getContentResolver().insert(StorageUtil.getDownloadUri(), contentValues));
|
||||||
|
} else {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void putInCache(@NonNull Uri outputUri, @NonNull String dataPath) {
|
private void putInCache(@NonNull Uri outputUri, @NonNull String dataPath) {
|
||||||
|
@ -346,8 +365,11 @@ public class SaveAttachmentTask extends ProgressDialogAsyncTask<SaveAttachmentTa
|
||||||
|
|
||||||
result[0] = tokens[0];
|
result[0] = tokens[0];
|
||||||
|
|
||||||
if (tokens.length > 1) result[1] = tokens[1];
|
if (tokens.length > 1) {
|
||||||
else result[1] = "";
|
result[1] = tokens[1];
|
||||||
|
} else {
|
||||||
|
result[1] = "";
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -361,18 +383,15 @@ public class SaveAttachmentTask extends ProgressDialogAsyncTask<SaveAttachmentTa
|
||||||
switch (result.first()) {
|
switch (result.first()) {
|
||||||
case FAILURE:
|
case FAILURE:
|
||||||
Toast.makeText(context,
|
Toast.makeText(context,
|
||||||
context.getResources().getQuantityText(R.plurals.ConversationFragment_error_while_saving_attachments_to_sd_card,
|
context.getResources().getQuantityText(R.plurals.ConversationFragment_error_while_saving_attachments_to_sd_card, attachmentCount),
|
||||||
attachmentCount),
|
|
||||||
Toast.LENGTH_LONG).show();
|
Toast.LENGTH_LONG).show();
|
||||||
break;
|
break;
|
||||||
case SUCCESS:
|
case SUCCESS:
|
||||||
String message = !TextUtils.isEmpty(result.second()) ? context.getResources().getString(R.string.SaveAttachmentTask_saved_to, result.second())
|
String message = !TextUtils.isEmpty(result.second()) ? context.getResources().getString(R.string.SaveAttachmentTask_saved_to, result.second()) : context.getResources().getString(R.string.SaveAttachmentTask_saved);
|
||||||
: context.getResources().getString(R.string.SaveAttachmentTask_saved);
|
|
||||||
Toast.makeText(context, message, Toast.LENGTH_LONG).show();
|
Toast.makeText(context, message, Toast.LENGTH_LONG).show();
|
||||||
break;
|
break;
|
||||||
case WRITE_ACCESS_FAILURE:
|
case WRITE_ACCESS_FAILURE:
|
||||||
Toast.makeText(context, R.string.ConversationFragment_unable_to_write_to_sd_card_exclamation,
|
Toast.makeText(context, R.string.ConversationFragment_unable_to_write_to_sd_card_exclamation, Toast.LENGTH_LONG).show();
|
||||||
Toast.LENGTH_LONG).show();
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -396,6 +415,16 @@ public class SaveAttachmentTask extends ProgressDialogAsyncTask<SaveAttachmentTa
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static class CreateMediaUriResult {
|
||||||
|
final Uri outputUri;
|
||||||
|
final Uri mediaUri;
|
||||||
|
|
||||||
|
private CreateMediaUriResult(Uri outputUri, Uri mediaUri) {
|
||||||
|
this.outputUri = outputUri;
|
||||||
|
this.mediaUri = mediaUri;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static void showWarningDialog(Context context, OnClickListener onAcceptListener) {
|
public static void showWarningDialog(Context context, OnClickListener onAcceptListener) {
|
||||||
showWarningDialog(context, onAcceptListener, 1);
|
showWarningDialog(context, onAcceptListener, 1);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue