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
|
@ -48,7 +48,7 @@ public class SaveAttachmentTask extends ProgressDialogAsyncTask<SaveAttachmentTa
|
|||
private static final int FAILURE = 1;
|
||||
private static final int WRITE_ACCESS_FAILURE = 2;
|
||||
|
||||
private final WeakReference<Context> contextReference;
|
||||
private final WeakReference<Context> contextReference;
|
||||
|
||||
private final int attachmentCount;
|
||||
|
||||
|
@ -62,8 +62,8 @@ public class SaveAttachmentTask extends ProgressDialogAsyncTask<SaveAttachmentTa
|
|||
super(context,
|
||||
context.getResources().getQuantityString(R.plurals.ConversationFragment_saving_n_attachments, count, count),
|
||||
context.getResources().getQuantityString(R.plurals.ConversationFragment_saving_n_attachments_to_sd_card, count, count));
|
||||
this.contextReference = new WeakReference<>(context);
|
||||
this.attachmentCount = count;
|
||||
this.contextReference = new WeakReference<>(context);
|
||||
this.attachmentCount = count;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -73,8 +73,8 @@ public class SaveAttachmentTask extends ProgressDialogAsyncTask<SaveAttachmentTa
|
|||
}
|
||||
|
||||
try {
|
||||
Context context = contextReference.get();
|
||||
String directory = null;
|
||||
Context context = contextReference.get();
|
||||
String directory = null;
|
||||
|
||||
if (!StorageUtil.canWriteToMediaStore()) {
|
||||
return new Pair<>(WRITE_ACCESS_FAILURE, null);
|
||||
|
@ -87,12 +87,17 @@ public class SaveAttachmentTask extends ProgressDialogAsyncTask<SaveAttachmentTa
|
|||
for (Attachment attachment : attachments) {
|
||||
if (attachment != null) {
|
||||
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);
|
||||
else return new Pair<>(SUCCESS, directory);
|
||||
if (attachments.length > 1) {
|
||||
return new Pair<>(SUCCESS, null);
|
||||
} else {
|
||||
return new Pair<>(SUCCESS, directory);
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
Log.w(TAG, ioe);
|
||||
return new Pair<>(FAILURE, null);
|
||||
|
@ -101,8 +106,8 @@ public class SaveAttachmentTask extends ProgressDialogAsyncTask<SaveAttachmentTa
|
|||
|
||||
private @Nullable String saveAttachment(Context context, Attachment attachment) throws IOException
|
||||
{
|
||||
String contentType = Objects.requireNonNull(MediaUtil.getCorrectedMimeType(attachment.contentType));
|
||||
String fileName = attachment.fileName;
|
||||
String contentType = Objects.requireNonNull(MediaUtil.getCorrectedMimeType(attachment.contentType));
|
||||
String fileName = attachment.fileName;
|
||||
|
||||
if (fileName == null) {
|
||||
fileName = generateOutputFileName(contentType, attachment.date);
|
||||
|
@ -110,14 +115,8 @@ public class SaveAttachmentTask extends ProgressDialogAsyncTask<SaveAttachmentTa
|
|||
|
||||
fileName = sanitizeOutputFileName(fileName);
|
||||
|
||||
Uri outputUri = getMediaStoreContentUriForType(contentType);
|
||||
Uri mediaUri = createOutputUri(outputUri, contentType, fileName);
|
||||
ContentValues updateValues = new ContentValues();
|
||||
|
||||
if (mediaUri == null) {
|
||||
Log.w(TAG, "Failed to create mediaUri for " + contentType);
|
||||
return null;
|
||||
}
|
||||
CreateMediaUriResult result = createMediaUri(getMediaStoreContentUriForType(contentType), contentType, fileName);
|
||||
ContentValues updateValues = new ContentValues();
|
||||
|
||||
try (InputStream inputStream = PartAuthority.getAttachmentStream(context, attachment.uri)) {
|
||||
|
||||
|
@ -125,13 +124,13 @@ public class SaveAttachmentTask extends ProgressDialogAsyncTask<SaveAttachmentTa
|
|||
return null;
|
||||
}
|
||||
|
||||
if (Objects.equals(outputUri.getScheme(), ContentResolver.SCHEME_FILE)) {
|
||||
try (OutputStream outputStream = new FileOutputStream(mediaUri.getPath())) {
|
||||
if (Objects.equals(result.outputUri.getScheme(), ContentResolver.SCHEME_FILE)) {
|
||||
try (OutputStream outputStream = new FileOutputStream(result.mediaUri.getPath())) {
|
||||
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 {
|
||||
try (OutputStream outputStream = context.getContentResolver().openOutputStream(mediaUri, "w")) {
|
||||
try (OutputStream outputStream = context.getContentResolver().openOutputStream(result.mediaUri, "w")) {
|
||||
long total = StreamUtil.copy(inputStream, outputStream);
|
||||
if (total > 0) {
|
||||
updateValues.put(MediaStore.MediaColumns.SIZE, total);
|
||||
|
@ -145,10 +144,10 @@ public class SaveAttachmentTask extends ProgressDialogAsyncTask<SaveAttachmentTa
|
|||
}
|
||||
|
||||
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) {
|
||||
|
@ -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.
|
||||
*
|
||||
* <p>
|
||||
* 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
|
||||
* 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();
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
String[] fileParts = getFileNameParts(fileName);
|
||||
|
@ -241,6 +240,16 @@ public class SaveAttachmentTask extends ProgressDialogAsyncTask<SaveAttachmentTa
|
|||
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.put(MediaStore.MediaColumns.DISPLAY_NAME, fileName);
|
||||
contentValues.put(MediaStore.MediaColumns.MIME_TYPE, mimeType);
|
||||
|
@ -248,8 +257,9 @@ public class SaveAttachmentTask extends ProgressDialogAsyncTask<SaveAttachmentTa
|
|||
contentValues.put(MediaStore.MediaColumns.DATE_MODIFIED, TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis()));
|
||||
|
||||
if (Build.VERSION.SDK_INT > 28) {
|
||||
int i = 0;
|
||||
int i = 0;
|
||||
String displayName = fileName;
|
||||
|
||||
while (pathInCache(outputUri, displayName) || displayNameTaken(outputUri, displayName)) {
|
||||
displayName = base + "-" + (++i) + "." + extension;
|
||||
}
|
||||
|
@ -271,7 +281,7 @@ public class SaveAttachmentTask extends ProgressDialogAsyncTask<SaveAttachmentTa
|
|||
}
|
||||
|
||||
putInCache(outputUri, outputFile.getPath());
|
||||
return Uri.fromFile(outputFile);
|
||||
return new CreateMediaUriResult(outputUri, Uri.fromFile(outputFile));
|
||||
} else {
|
||||
String dir = getExternalPathForType(contentType);
|
||||
if (dir == null) {
|
||||
|
@ -290,7 +300,16 @@ public class SaveAttachmentTask extends ProgressDialogAsyncTask<SaveAttachmentTa
|
|||
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) {
|
||||
|
@ -346,8 +365,11 @@ public class SaveAttachmentTask extends ProgressDialogAsyncTask<SaveAttachmentTa
|
|||
|
||||
result[0] = tokens[0];
|
||||
|
||||
if (tokens.length > 1) result[1] = tokens[1];
|
||||
else result[1] = "";
|
||||
if (tokens.length > 1) {
|
||||
result[1] = tokens[1];
|
||||
} else {
|
||||
result[1] = "";
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
@ -361,18 +383,15 @@ public class SaveAttachmentTask extends ProgressDialogAsyncTask<SaveAttachmentTa
|
|||
switch (result.first()) {
|
||||
case FAILURE:
|
||||
Toast.makeText(context,
|
||||
context.getResources().getQuantityText(R.plurals.ConversationFragment_error_while_saving_attachments_to_sd_card,
|
||||
attachmentCount),
|
||||
context.getResources().getQuantityText(R.plurals.ConversationFragment_error_while_saving_attachments_to_sd_card, attachmentCount),
|
||||
Toast.LENGTH_LONG).show();
|
||||
break;
|
||||
case SUCCESS:
|
||||
String message = !TextUtils.isEmpty(result.second()) ? context.getResources().getString(R.string.SaveAttachmentTask_saved_to, result.second())
|
||||
: context.getResources().getString(R.string.SaveAttachmentTask_saved);
|
||||
String message = !TextUtils.isEmpty(result.second()) ? context.getResources().getString(R.string.SaveAttachmentTask_saved_to, result.second()) : context.getResources().getString(R.string.SaveAttachmentTask_saved);
|
||||
Toast.makeText(context, message, Toast.LENGTH_LONG).show();
|
||||
break;
|
||||
case WRITE_ACCESS_FAILURE:
|
||||
Toast.makeText(context, R.string.ConversationFragment_unable_to_write_to_sd_card_exclamation,
|
||||
Toast.LENGTH_LONG).show();
|
||||
Toast.makeText(context, R.string.ConversationFragment_unable_to_write_to_sd_card_exclamation, Toast.LENGTH_LONG).show();
|
||||
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) {
|
||||
showWarningDialog(context, onAcceptListener, 1);
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue