mirror of
https://github.com/moparisthebest/k-9
synced 2024-08-13 17:03:48 -04:00
370 lines
13 KiB
Java
370 lines
13 KiB
Java
package com.fsck.k9.ui.messageview;
|
|
|
|
|
|
import java.io.File;
|
|
import java.io.FileOutputStream;
|
|
import java.io.IOException;
|
|
import java.io.InputStream;
|
|
import java.io.OutputStream;
|
|
import java.util.List;
|
|
|
|
import android.content.ActivityNotFoundException;
|
|
import android.content.Context;
|
|
import android.content.Intent;
|
|
import android.content.pm.PackageManager;
|
|
import android.content.pm.ResolveInfo;
|
|
import android.net.Uri;
|
|
import android.os.AsyncTask;
|
|
import android.os.Environment;
|
|
import android.util.Log;
|
|
import android.widget.Toast;
|
|
|
|
import com.fsck.k9.Account;
|
|
import com.fsck.k9.K9;
|
|
import com.fsck.k9.Preferences;
|
|
import com.fsck.k9.R;
|
|
import com.fsck.k9.cache.TemporaryAttachmentStore;
|
|
import com.fsck.k9.controller.MessagingController;
|
|
import com.fsck.k9.controller.MessagingListener;
|
|
import com.fsck.k9.helper.FileHelper;
|
|
import com.fsck.k9.helper.MediaScannerNotifier;
|
|
import com.fsck.k9.mail.Message;
|
|
import com.fsck.k9.mail.Part;
|
|
import com.fsck.k9.mail.internet.MimeUtility;
|
|
import com.fsck.k9.mailstore.AttachmentViewInfo;
|
|
import com.fsck.k9.mailstore.LocalMessage;
|
|
import com.fsck.k9.mailstore.LocalPart;
|
|
import org.apache.commons.io.IOUtils;
|
|
|
|
|
|
public class AttachmentController {
|
|
private final Context context;
|
|
private final MessagingController controller;
|
|
private final MessageViewFragment messageViewFragment;
|
|
private final AttachmentViewInfo attachment;
|
|
|
|
AttachmentController(MessagingController controller, MessageViewFragment messageViewFragment,
|
|
AttachmentViewInfo attachment) {
|
|
this.context = messageViewFragment.getContext();
|
|
this.controller = controller;
|
|
this.messageViewFragment = messageViewFragment;
|
|
this.attachment = attachment;
|
|
}
|
|
|
|
public void viewAttachment() {
|
|
if (needsDownloading()) {
|
|
downloadAndViewAttachment((LocalPart) attachment.part);
|
|
} else {
|
|
viewLocalAttachment();
|
|
}
|
|
}
|
|
|
|
public void saveAttachment() {
|
|
saveAttachmentTo(K9.getAttachmentDefaultPath());
|
|
}
|
|
|
|
public void saveAttachmentTo(String directory) {
|
|
saveAttachmentTo(new File(directory));
|
|
}
|
|
|
|
private boolean needsDownloading() {
|
|
return isPartMissing() && isLocalPart();
|
|
}
|
|
|
|
private boolean isPartMissing() {
|
|
return attachment.part.getBody() == null;
|
|
}
|
|
|
|
private boolean isLocalPart() {
|
|
return attachment.part instanceof LocalPart;
|
|
}
|
|
|
|
private void downloadAndViewAttachment(LocalPart localPart) {
|
|
downloadAttachment(localPart, new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
viewLocalAttachment();
|
|
}
|
|
});
|
|
}
|
|
|
|
private void downloadAndSaveAttachmentTo(LocalPart localPart, final File directory) {
|
|
downloadAttachment(localPart, new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
messageViewFragment.refreshAttachmentThumbnail(attachment);
|
|
saveAttachmentTo(directory);
|
|
}
|
|
});
|
|
}
|
|
|
|
private void downloadAttachment(LocalPart localPart, final Runnable attachmentDownloadedCallback) {
|
|
String accountUuid = localPart.getAccountUuid();
|
|
Account account = Preferences.getPreferences(context).getAccount(accountUuid);
|
|
LocalMessage message = localPart.getMessage();
|
|
|
|
messageViewFragment.showAttachmentLoadingDialog();
|
|
controller.loadAttachment(account, message, attachment.part, new MessagingListener() {
|
|
@Override
|
|
public void loadAttachmentFinished(Account account, Message message, Part part) {
|
|
messageViewFragment.hideAttachmentLoadingDialogOnMainThread();
|
|
messageViewFragment.runOnMainThread(attachmentDownloadedCallback);
|
|
}
|
|
|
|
@Override
|
|
public void loadAttachmentFailed(Account account, Message message, Part part, String reason) {
|
|
messageViewFragment.hideAttachmentLoadingDialogOnMainThread();
|
|
}
|
|
});
|
|
}
|
|
|
|
private void viewLocalAttachment() {
|
|
new ViewAttachmentAsyncTask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
|
}
|
|
|
|
private void saveAttachmentTo(File directory) {
|
|
boolean isExternalStorageMounted = Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED);
|
|
if (!isExternalStorageMounted) {
|
|
String message = context.getString(R.string.message_view_status_attachment_not_saved);
|
|
displayMessageToUser(message);
|
|
return;
|
|
}
|
|
|
|
if (needsDownloading()) {
|
|
downloadAndSaveAttachmentTo((LocalPart) attachment.part, directory);
|
|
} else {
|
|
saveLocalAttachmentTo(directory);
|
|
}
|
|
}
|
|
|
|
private void saveLocalAttachmentTo(File directory) {
|
|
new SaveAttachmentAsyncTask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, directory);
|
|
}
|
|
|
|
private File saveAttachmentWithUniqueFileName(File directory) throws IOException {
|
|
String filename = FileHelper.sanitizeFilename(attachment.displayName);
|
|
File file = FileHelper.createUniqueFile(directory, filename);
|
|
|
|
writeAttachmentToStorage(file);
|
|
|
|
return file;
|
|
}
|
|
|
|
private void writeAttachmentToStorage(File file) throws IOException {
|
|
InputStream in = context.getContentResolver().openInputStream(attachment.uri);
|
|
try {
|
|
OutputStream out = new FileOutputStream(file);
|
|
try {
|
|
IOUtils.copy(in, out);
|
|
out.flush();
|
|
} finally {
|
|
out.close();
|
|
}
|
|
} finally {
|
|
in.close();
|
|
}
|
|
}
|
|
|
|
private Intent getBestViewIntentAndSaveFileIfNecessary() {
|
|
String displayName = attachment.displayName;
|
|
String inferredMimeType = MimeUtility.getMimeTypeByExtension(displayName);
|
|
|
|
IntentAndResolvedActivitiesCount resolvedIntentInfo;
|
|
String mimeType = attachment.mimeType;
|
|
if (MimeUtility.isDefaultMimeType(mimeType)) {
|
|
resolvedIntentInfo = getBestViewIntentForMimeType(inferredMimeType);
|
|
} else {
|
|
resolvedIntentInfo = getBestViewIntentForMimeType(mimeType);
|
|
if (!resolvedIntentInfo.hasResolvedActivities() && !inferredMimeType.equals(mimeType)) {
|
|
resolvedIntentInfo = getBestViewIntentForMimeType(inferredMimeType);
|
|
}
|
|
}
|
|
|
|
if (!resolvedIntentInfo.hasResolvedActivities()) {
|
|
resolvedIntentInfo = getBestViewIntentForMimeType(MimeUtility.DEFAULT_ATTACHMENT_MIME_TYPE);
|
|
}
|
|
|
|
Intent viewIntent;
|
|
if (resolvedIntentInfo.hasResolvedActivities() && resolvedIntentInfo.containsFileUri()) {
|
|
try {
|
|
File tempFile = TemporaryAttachmentStore.getFileForWriting(context, displayName);
|
|
writeAttachmentToStorage(tempFile);
|
|
viewIntent = createViewIntentForFileUri(resolvedIntentInfo.getMimeType(), Uri.fromFile(tempFile));
|
|
} catch (IOException e) {
|
|
if (K9.DEBUG) {
|
|
Log.e(K9.LOG_TAG, "Error while saving attachment to use file:// URI with ACTION_VIEW Intent", e);
|
|
}
|
|
viewIntent = createViewIntentForAttachmentProviderUri(MimeUtility.DEFAULT_ATTACHMENT_MIME_TYPE);
|
|
}
|
|
} else {
|
|
viewIntent = resolvedIntentInfo.getIntent();
|
|
}
|
|
|
|
return viewIntent;
|
|
}
|
|
|
|
private IntentAndResolvedActivitiesCount getBestViewIntentForMimeType(String mimeType) {
|
|
Intent contentUriIntent = createViewIntentForAttachmentProviderUri(mimeType);
|
|
int contentUriActivitiesCount = getResolvedIntentActivitiesCount(contentUriIntent);
|
|
|
|
if (contentUriActivitiesCount > 0) {
|
|
return new IntentAndResolvedActivitiesCount(contentUriIntent, contentUriActivitiesCount);
|
|
}
|
|
|
|
File tempFile = TemporaryAttachmentStore.getFile(context, attachment.displayName);
|
|
Uri tempFileUri = Uri.fromFile(tempFile);
|
|
Intent fileUriIntent = createViewIntentForFileUri(mimeType, tempFileUri);
|
|
int fileUriActivitiesCount = getResolvedIntentActivitiesCount(fileUriIntent);
|
|
|
|
if (fileUriActivitiesCount > 0) {
|
|
return new IntentAndResolvedActivitiesCount(fileUriIntent, fileUriActivitiesCount);
|
|
}
|
|
|
|
return new IntentAndResolvedActivitiesCount(contentUriIntent, contentUriActivitiesCount);
|
|
}
|
|
|
|
private Intent createViewIntentForAttachmentProviderUri(String mimeType) {
|
|
Uri uri = getAttachmentUriForMimeType(attachment, mimeType);
|
|
|
|
Intent intent = new Intent(Intent.ACTION_VIEW);
|
|
intent.setDataAndType(uri, mimeType);
|
|
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
|
addUiIntentFlags(intent);
|
|
|
|
return intent;
|
|
}
|
|
|
|
private Uri getAttachmentUriForMimeType(AttachmentViewInfo attachment, String mimeType) {
|
|
if (attachment.mimeType.equals(mimeType)) {
|
|
return attachment.uri;
|
|
}
|
|
|
|
return attachment.uri.buildUpon()
|
|
.appendPath(mimeType)
|
|
.build();
|
|
}
|
|
|
|
private Intent createViewIntentForFileUri(String mimeType, Uri uri) {
|
|
Intent intent = new Intent(Intent.ACTION_VIEW);
|
|
intent.setDataAndType(uri, mimeType);
|
|
addUiIntentFlags(intent);
|
|
|
|
return intent;
|
|
}
|
|
|
|
private void addUiIntentFlags(Intent intent) {
|
|
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
|
|
}
|
|
|
|
private int getResolvedIntentActivitiesCount(Intent intent) {
|
|
PackageManager packageManager = context.getPackageManager();
|
|
|
|
List<ResolveInfo> resolveInfos =
|
|
packageManager.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
|
|
|
|
return resolveInfos.size();
|
|
}
|
|
|
|
private void displayAttachmentSavedMessage(final String filename) {
|
|
String message = context.getString(R.string.message_view_status_attachment_saved, filename);
|
|
displayMessageToUser(message);
|
|
}
|
|
|
|
private void displayAttachmentNotSavedMessage() {
|
|
String message = context.getString(R.string.message_view_status_attachment_not_saved);
|
|
displayMessageToUser(message);
|
|
}
|
|
|
|
private void displayMessageToUser(String message) {
|
|
Toast.makeText(context, message, Toast.LENGTH_LONG).show();
|
|
}
|
|
|
|
private static class IntentAndResolvedActivitiesCount {
|
|
private Intent intent;
|
|
private int activitiesCount;
|
|
|
|
IntentAndResolvedActivitiesCount(Intent intent, int activitiesCount) {
|
|
this.intent = intent;
|
|
this.activitiesCount = activitiesCount;
|
|
}
|
|
|
|
public Intent getIntent() {
|
|
return intent;
|
|
}
|
|
|
|
public boolean hasResolvedActivities() {
|
|
return activitiesCount > 0;
|
|
}
|
|
|
|
public String getMimeType() {
|
|
return intent.getType();
|
|
}
|
|
|
|
public boolean containsFileUri() {
|
|
return "file".equals(intent.getData().getScheme());
|
|
}
|
|
}
|
|
|
|
private class ViewAttachmentAsyncTask extends AsyncTask<Void, Void, Intent> {
|
|
|
|
@Override
|
|
protected void onPreExecute() {
|
|
messageViewFragment.disableAttachmentButtons(attachment);
|
|
}
|
|
|
|
@Override
|
|
protected Intent doInBackground(Void... params) {
|
|
return getBestViewIntentAndSaveFileIfNecessary();
|
|
}
|
|
|
|
@Override
|
|
protected void onPostExecute(Intent intent) {
|
|
viewAttachment(intent);
|
|
messageViewFragment.enableAttachmentButtons(attachment);
|
|
}
|
|
|
|
private void viewAttachment(Intent intent) {
|
|
try {
|
|
context.startActivity(intent);
|
|
} catch (ActivityNotFoundException e) {
|
|
Log.e(K9.LOG_TAG, "Could not display attachment of type " + attachment.mimeType, e);
|
|
|
|
String message = context.getString(R.string.message_view_no_viewer, attachment.mimeType);
|
|
displayMessageToUser(message);
|
|
}
|
|
}
|
|
}
|
|
|
|
private class SaveAttachmentAsyncTask extends AsyncTask<File, Void, File> {
|
|
|
|
@Override
|
|
protected void onPreExecute() {
|
|
messageViewFragment.disableAttachmentButtons(attachment);
|
|
}
|
|
|
|
@Override
|
|
protected File doInBackground(File... params) {
|
|
try {
|
|
File directory = params[0];
|
|
return saveAttachmentWithUniqueFileName(directory);
|
|
} catch (IOException e) {
|
|
if (K9.DEBUG) {
|
|
Log.e(K9.LOG_TAG, "Error saving attachment", e);
|
|
}
|
|
return null;
|
|
}
|
|
}
|
|
|
|
@Override
|
|
protected void onPostExecute(File file) {
|
|
messageViewFragment.enableAttachmentButtons(attachment);
|
|
if (file != null) {
|
|
displayAttachmentSavedMessage(file.toString());
|
|
MediaScannerNotifier.notify(context, file);
|
|
} else {
|
|
displayAttachmentNotSavedMessage();
|
|
}
|
|
}
|
|
}
|
|
}
|