k-9/k9mail/src/main/java/com/fsck/k9/ui/messageview/SingleMessageView.java

884 lines
33 KiB
Java

package com.fsck.k9.ui.messageview;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
import java.util.HashMap;
import java.util.Map;
import android.app.Activity;
import android.app.Fragment;
import android.content.ActivityNotFoundException;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MenuItem.OnMenuItemClickListener;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnCreateContextMenuListener;
import android.webkit.WebView;
import android.webkit.WebView.HitTestResult;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.Toast;
import com.fsck.k9.Account;
import com.fsck.k9.K9;
import com.fsck.k9.R;
import com.fsck.k9.crypto.PgpData;
import com.fsck.k9.helper.ClipboardManager;
import com.fsck.k9.helper.Contacts;
import com.fsck.k9.helper.FileHelper;
import com.fsck.k9.helper.HtmlConverter;
import com.fsck.k9.helper.UrlEncodingHelper;
import com.fsck.k9.helper.Utility;
import com.fsck.k9.mail.Address;
import com.fsck.k9.mail.Flag;
import com.fsck.k9.mail.Message;
import com.fsck.k9.mail.MessagingException;
import com.fsck.k9.mail.internet.MimeUtility;
import com.fsck.k9.mailstore.AttachmentViewInfo;
import com.fsck.k9.mailstore.MessageViewInfo;
import com.fsck.k9.provider.AttachmentProvider.AttachmentProviderColumns;
import com.fsck.k9.view.MessageHeader;
import com.fsck.k9.view.MessageHeader.OnLayoutChangedListener;
import com.fsck.k9.view.MessageWebView;
import org.apache.commons.io.IOUtils;
public class SingleMessageView extends LinearLayout implements OnClickListener,
OnLayoutChangedListener, OnCreateContextMenuListener {
private static final int MENU_ITEM_LINK_VIEW = Menu.FIRST;
private static final int MENU_ITEM_LINK_SHARE = Menu.FIRST + 1;
private static final int MENU_ITEM_LINK_COPY = Menu.FIRST + 2;
private static final int MENU_ITEM_IMAGE_VIEW = Menu.FIRST;
private static final int MENU_ITEM_IMAGE_SAVE = Menu.FIRST + 1;
private static final int MENU_ITEM_IMAGE_COPY = Menu.FIRST + 2;
private static final int MENU_ITEM_PHONE_CALL = Menu.FIRST;
private static final int MENU_ITEM_PHONE_SAVE = Menu.FIRST + 1;
private static final int MENU_ITEM_PHONE_COPY = Menu.FIRST + 2;
private static final int MENU_ITEM_EMAIL_SEND = Menu.FIRST;
private static final int MENU_ITEM_EMAIL_SAVE = Menu.FIRST + 1;
private static final int MENU_ITEM_EMAIL_COPY = Menu.FIRST + 2;
private static final String[] ATTACHMENT_PROJECTION = new String[] {
AttachmentProviderColumns._ID,
AttachmentProviderColumns.DISPLAY_NAME
};
private static final int DISPLAY_NAME_INDEX = 1;
private MessageOpenPgpViewOld mOpenPgpView;
private MessageWebView mMessageContentView;
private MessageHeader mHeaderContainer;
private LinearLayout mAttachments;
private Button mShowHiddenAttachments;
private LinearLayout mHiddenAttachments;
private View mShowPicturesAction;
private View mShowMessageAction;
private View mShowAttachmentsAction;
private boolean mShowPictures;
private boolean mHasAttachments;
private Button mDownloadRemainder;
private LayoutInflater mInflater;
private Contacts mContacts;
private AttachmentViewCallback attachmentCallback;
private View mAttachmentsContainer;
private SavedState mSavedState;
private ClipboardManager mClipboardManager;
private String mText;
private Map<AttachmentViewInfo, AttachmentView> attachments = new HashMap<AttachmentViewInfo, AttachmentView>();
public void initialize(Fragment fragment) {
Activity activity = fragment.getActivity();
mMessageContentView = (MessageWebView) findViewById(R.id.message_content);
mMessageContentView.configure();
activity.registerForContextMenu(mMessageContentView);
mMessageContentView.setOnCreateContextMenuListener(this);
mHeaderContainer = (MessageHeader) findViewById(R.id.header_container);
mHeaderContainer.setOnLayoutChangedListener(this);
mAttachmentsContainer = findViewById(R.id.attachments_container);
mAttachments = (LinearLayout) findViewById(R.id.attachments);
mHiddenAttachments = (LinearLayout) findViewById(R.id.hidden_attachments);
mHiddenAttachments.setVisibility(View.GONE);
mShowHiddenAttachments = (Button) findViewById(R.id.show_hidden_attachments);
mShowHiddenAttachments.setVisibility(View.GONE);
mOpenPgpView = (MessageOpenPgpViewOld) findViewById(R.id.layout_decrypt_openpgp);
mOpenPgpView.setFragment(fragment);
mOpenPgpView.setupChildViews();
mShowPicturesAction = findViewById(R.id.show_pictures);
mShowMessageAction = findViewById(R.id.show_message);
mShowAttachmentsAction = findViewById(R.id.show_attachments);
mShowPictures = false;
mContacts = Contacts.getInstance(activity);
mInflater = ((MessageViewFragment) fragment).getFragmentLayoutInflater();
mDownloadRemainder = (Button) findViewById(R.id.download_remainder);
mDownloadRemainder.setVisibility(View.GONE);
mAttachmentsContainer.setVisibility(View.GONE);
mMessageContentView.setVisibility(View.VISIBLE);
// the HTC version of WebView tries to force the background of the
// titlebar, which is really unfair.
TypedValue outValue = new TypedValue();
getContext().getTheme().resolveAttribute(R.attr.messageViewHeaderBackgroundColor, outValue, true);
mHeaderContainer.setBackgroundColor(outValue.data);
// also set background of the whole view (including the attachments view)
setBackgroundColor(outValue.data);
mShowHiddenAttachments.setOnClickListener(this);
mShowMessageAction.setOnClickListener(this);
mShowAttachmentsAction.setOnClickListener(this);
mShowPicturesAction.setOnClickListener(this);
mClipboardManager = ClipboardManager.getInstance(activity);
}
@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu);
WebView webview = (WebView) v;
WebView.HitTestResult result = webview.getHitTestResult();
if (result == null) {
return;
}
int type = result.getType();
Context context = getContext();
switch (type) {
case HitTestResult.SRC_ANCHOR_TYPE: {
final String url = result.getExtra();
OnMenuItemClickListener listener = new OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
switch (item.getItemId()) {
case MENU_ITEM_LINK_VIEW: {
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
startActivityIfAvailable(getContext(), intent);
break;
}
case MENU_ITEM_LINK_SHARE: {
Intent intent = new Intent(Intent.ACTION_SEND);
intent.setType("text/plain");
intent.putExtra(Intent.EXTRA_TEXT, url);
startActivityIfAvailable(getContext(), intent);
break;
}
case MENU_ITEM_LINK_COPY: {
String label = getContext().getString(
R.string.webview_contextmenu_link_clipboard_label);
mClipboardManager.setText(label, url);
break;
}
}
return true;
}
};
menu.setHeaderTitle(url);
menu.add(Menu.NONE, MENU_ITEM_LINK_VIEW, 0,
context.getString(R.string.webview_contextmenu_link_view_action))
.setOnMenuItemClickListener(listener);
menu.add(Menu.NONE, MENU_ITEM_LINK_SHARE, 1,
context.getString(R.string.webview_contextmenu_link_share_action))
.setOnMenuItemClickListener(listener);
menu.add(Menu.NONE, MENU_ITEM_LINK_COPY, 2,
context.getString(R.string.webview_contextmenu_link_copy_action))
.setOnMenuItemClickListener(listener);
break;
}
case HitTestResult.IMAGE_TYPE:
case HitTestResult.SRC_IMAGE_ANCHOR_TYPE: {
final String url = result.getExtra();
final boolean externalImage = url.startsWith("http");
OnMenuItemClickListener listener = new OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
switch (item.getItemId()) {
case MENU_ITEM_IMAGE_VIEW: {
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
if (!externalImage) {
// Grant read permission if this points to our
// AttachmentProvider
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
}
startActivityIfAvailable(getContext(), intent);
break;
}
case MENU_ITEM_IMAGE_SAVE: {
new DownloadImageTask().execute(url);
break;
}
case MENU_ITEM_IMAGE_COPY: {
String label = getContext().getString(
R.string.webview_contextmenu_image_clipboard_label);
mClipboardManager.setText(label, url);
break;
}
}
return true;
}
};
menu.setHeaderTitle((externalImage) ?
url : context.getString(R.string.webview_contextmenu_image_title));
menu.add(Menu.NONE, MENU_ITEM_IMAGE_VIEW, 0,
context.getString(R.string.webview_contextmenu_image_view_action))
.setOnMenuItemClickListener(listener);
menu.add(Menu.NONE, MENU_ITEM_IMAGE_SAVE, 1,
(externalImage) ?
context.getString(R.string.webview_contextmenu_image_download_action) :
context.getString(R.string.webview_contextmenu_image_save_action))
.setOnMenuItemClickListener(listener);
if (externalImage) {
menu.add(Menu.NONE, MENU_ITEM_IMAGE_COPY, 2,
context.getString(R.string.webview_contextmenu_image_copy_action))
.setOnMenuItemClickListener(listener);
}
break;
}
case HitTestResult.PHONE_TYPE: {
final String phoneNumber = result.getExtra();
OnMenuItemClickListener listener = new OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
switch (item.getItemId()) {
case MENU_ITEM_PHONE_CALL: {
Uri uri = Uri.parse(WebView.SCHEME_TEL + phoneNumber);
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
startActivityIfAvailable(getContext(), intent);
break;
}
case MENU_ITEM_PHONE_SAVE: {
Contacts contacts = Contacts.getInstance(getContext());
contacts.addPhoneContact(phoneNumber);
break;
}
case MENU_ITEM_PHONE_COPY: {
String label = getContext().getString(
R.string.webview_contextmenu_phone_clipboard_label);
mClipboardManager.setText(label, phoneNumber);
break;
}
}
return true;
}
};
menu.setHeaderTitle(phoneNumber);
menu.add(Menu.NONE, MENU_ITEM_PHONE_CALL, 0,
context.getString(R.string.webview_contextmenu_phone_call_action))
.setOnMenuItemClickListener(listener);
menu.add(Menu.NONE, MENU_ITEM_PHONE_SAVE, 1,
context.getString(R.string.webview_contextmenu_phone_save_action))
.setOnMenuItemClickListener(listener);
menu.add(Menu.NONE, MENU_ITEM_PHONE_COPY, 2,
context.getString(R.string.webview_contextmenu_phone_copy_action))
.setOnMenuItemClickListener(listener);
break;
}
case WebView.HitTestResult.EMAIL_TYPE: {
final String email = result.getExtra();
OnMenuItemClickListener listener = new OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
switch (item.getItemId()) {
case MENU_ITEM_EMAIL_SEND: {
Uri uri = Uri.parse(WebView.SCHEME_MAILTO + email);
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
startActivityIfAvailable(getContext(), intent);
break;
}
case MENU_ITEM_EMAIL_SAVE: {
Contacts contacts = Contacts.getInstance(getContext());
contacts.createContact(new Address(email));
break;
}
case MENU_ITEM_EMAIL_COPY: {
String label = getContext().getString(
R.string.webview_contextmenu_email_clipboard_label);
mClipboardManager.setText(label, email);
break;
}
}
return true;
}
};
menu.setHeaderTitle(email);
menu.add(Menu.NONE, MENU_ITEM_EMAIL_SEND, 0,
context.getString(R.string.webview_contextmenu_email_send_action))
.setOnMenuItemClickListener(listener);
menu.add(Menu.NONE, MENU_ITEM_EMAIL_SAVE, 1,
context.getString(R.string.webview_contextmenu_email_save_action))
.setOnMenuItemClickListener(listener);
menu.add(Menu.NONE, MENU_ITEM_EMAIL_COPY, 2,
context.getString(R.string.webview_contextmenu_email_copy_action))
.setOnMenuItemClickListener(listener);
break;
}
}
}
private void startActivityIfAvailable(Context context, Intent intent) {
try {
context.startActivity(intent);
} catch (ActivityNotFoundException e) {
Toast.makeText(context, R.string.error_activity_not_found, Toast.LENGTH_LONG).show();
}
}
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.show_hidden_attachments: {
onShowHiddenAttachments();
break;
}
case R.id.show_message: {
onShowMessage();
break;
}
case R.id.show_attachments: {
onShowAttachments();
break;
}
case R.id.show_pictures: {
// Allow network access first...
setLoadPictures(true);
// ...then re-populate the WebView with the message text
loadBodyFromText(mText);
break;
}
}
}
private void onShowHiddenAttachments() {
mShowHiddenAttachments.setVisibility(View.GONE);
mHiddenAttachments.setVisibility(View.VISIBLE);
}
public void onShowMessage() {
showShowMessageAction(false);
showAttachments(false);
showShowAttachmentsAction(mHasAttachments);
showMessageWebView(true);
}
public void onShowAttachments() {
showMessageWebView(false);
showShowAttachmentsAction(false);
showShowMessageAction(true);
showAttachments(true);
}
public SingleMessageView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public boolean showPictures() {
return mShowPictures;
}
public void setShowPictures(Boolean show) {
mShowPictures = show;
}
/**
* Enable/disable image loading of the WebView. But always hide the
* "Show pictures" button!
*
* @param enable true, if (network) images should be loaded.
* false, otherwise.
*/
public void setLoadPictures(boolean enable) {
mMessageContentView.blockNetworkData(!enable);
setShowPictures(enable);
showShowPicturesAction(false);
}
public void showShowPicturesAction(boolean show) {
mShowPicturesAction.setVisibility(show ? View.VISIBLE : View.GONE);
}
public void showShowMessageAction(boolean show) {
mShowMessageAction.setVisibility(show ? View.VISIBLE : View.GONE);
}
public void showShowAttachmentsAction(boolean show) {
mShowAttachmentsAction.setVisibility(show ? View.VISIBLE : View.GONE);
}
/**
* Fetch the message header view. This is not the same as the message headers; this is the View shown at the top
* of messages.
* @return MessageHeader View.
*/
public MessageHeader getMessageHeaderView() {
return mHeaderContainer;
}
public void setHeaders(final Message message, Account account) {
try {
mHeaderContainer.populate(message, account);
mHeaderContainer.setVisibility(View.VISIBLE);
} catch (Exception me) {
Log.e(K9.LOG_TAG, "setHeaders - error", me);
}
}
public void setOnToggleFlagClickListener(OnClickListener listener) {
mHeaderContainer.setOnFlagListener(listener);
}
public void setOnDownloadButtonClickListener(OnClickListener listener) {
mDownloadRemainder.setOnClickListener(listener);
}
public void enableDownloadButton() {
mDownloadRemainder.setEnabled(true);
}
public void disableDownloadButton() {
mDownloadRemainder.setEnabled(false);
}
public void setShowDownloadButton(Message message) {
if (message.isSet(Flag.X_DOWNLOADED_FULL)) {
mDownloadRemainder.setVisibility(View.GONE);
} else {
mDownloadRemainder.setEnabled(true);
mDownloadRemainder.setVisibility(View.VISIBLE);
}
}
public void enableAttachmentButtons() {
for (AttachmentView attachmentView : attachments.values()) {
attachmentView.enableButtons();
}
}
public void disableAttachmentButtons() {
for (AttachmentView attachmentView : attachments.values()) {
attachmentView.disableButtons();
}
}
public void showAllHeaders() {
mHeaderContainer.onShowAdditionalHeaders();
}
public boolean additionalHeadersVisible() {
return mHeaderContainer.additionalHeadersVisible();
}
public void setMessage(Account account, MessageViewInfo messageViewInfo, PgpData pgpData)
throws MessagingException {
resetView();
String text = null;
if (pgpData != null) {
text = pgpData.getDecryptedData();
if (text != null) {
text = HtmlConverter.textToHtml(text);
}
}
if (text == null) {
text = messageViewInfo.text;
}
// Save the text so we can reset the WebView when the user clicks the "Show pictures" button
mText = text;
mHasAttachments = !messageViewInfo.attachments.isEmpty();
if (mHasAttachments) {
renderAttachments(messageViewInfo);
}
mHiddenAttachments.setVisibility(View.GONE);
boolean lookForImages = true;
if (mSavedState != null) {
if (mSavedState.showPictures) {
setLoadPictures(true);
lookForImages = false;
}
if (mSavedState.attachmentViewVisible) {
onShowAttachments();
} else {
onShowMessage();
}
if (mSavedState.hiddenAttachmentsVisible) {
onShowHiddenAttachments();
}
mSavedState = null;
} else {
onShowMessage();
}
if (text != null && lookForImages) {
// If the message contains external pictures and the "Show pictures"
// button wasn't already pressed, see if the user's preferences has us
// showing them anyway.
if (Utility.hasExternalImages(text) && !showPictures()) {
Address[] from = messageViewInfo.message.getFrom();
if ((account.getShowPictures() == Account.ShowPictures.ALWAYS) ||
((account.getShowPictures() == Account.ShowPictures.ONLY_FROM_CONTACTS) &&
// Make sure we have at least one from address
(from != null && from.length > 0) &&
mContacts.isInContacts(from[0].getAddress()))) {
setLoadPictures(true);
} else {
showShowPicturesAction(true);
}
}
}
if (text != null) {
loadBodyFromText(text);
mOpenPgpView.updateLayout(account, pgpData.getDecryptedData(),
pgpData.getSignatureResult(), messageViewInfo.message);
} else {
showStatusMessage(getContext().getString(R.string.webview_empty_message));
}
}
public void showStatusMessage(String status) {
String text = "<div style=\"text-align:center; color: grey;\">" + status + "</div>";
loadBodyFromText(text);
}
private void loadBodyFromText(String emailText) {
mMessageContentView.setText(emailText);
}
public void showAttachments(boolean show) {
mAttachmentsContainer.setVisibility(show ? View.VISIBLE : View.GONE);
boolean showHidden = (show && mHiddenAttachments.getVisibility() == View.GONE &&
mHiddenAttachments.getChildCount() > 0);
mShowHiddenAttachments.setVisibility(showHidden ? View.VISIBLE : View.GONE);
}
public void showMessageWebView(boolean show) {
mMessageContentView.setVisibility(show ? View.VISIBLE : View.GONE);
}
public void renderAttachments(MessageViewInfo messageContainer) throws MessagingException {
for (AttachmentViewInfo attachment : messageContainer.attachments) {
AttachmentView view = (AttachmentView) mInflater.inflate(R.layout.message_view_attachment, null);
view.setCallback(attachmentCallback);
view.setAttachment(attachment);
attachments.put(attachment, view);
if (attachment.firstClassAttachment) {
addAttachment(view);
} else {
addHiddenAttachment(view);
}
}
}
public void addAttachment(View attachmentView) {
mAttachments.addView(attachmentView);
}
public void addHiddenAttachment(View attachmentView) {
mHiddenAttachments.addView(attachmentView);
}
public void zoom(KeyEvent event) {
if (event.isShiftPressed()) {
mMessageContentView.zoomIn();
} else {
mMessageContentView.zoomOut();
}
}
public void beginSelectingText() {
mMessageContentView.emulateShiftHeld();
}
public void resetView() {
mDownloadRemainder.setVisibility(View.GONE);
setLoadPictures(false);
showShowAttachmentsAction(false);
showShowMessageAction(false);
showShowPicturesAction(false);
mAttachments.removeAllViews();
mHiddenAttachments.removeAllViews();
/*
* Clear the WebView content
*
* For some reason WebView.clearView() doesn't clear the contents when the WebView changes
* its size because the button to download the complete message was previously shown and
* is now hidden.
*/
loadBodyFromText("");
}
public void resetHeaderView() {
mHeaderContainer.setVisibility(View.GONE);
}
public void setAttachmentCallback(AttachmentViewCallback attachmentCallback) {
this.attachmentCallback = attachmentCallback;
}
@Override
public Parcelable onSaveInstanceState() {
Parcelable superState = super.onSaveInstanceState();
SavedState savedState = new SavedState(superState);
savedState.attachmentViewVisible = (mAttachmentsContainer != null &&
mAttachmentsContainer.getVisibility() == View.VISIBLE);
savedState.hiddenAttachmentsVisible = (mHiddenAttachments != null &&
mHiddenAttachments.getVisibility() == View.VISIBLE);
savedState.showPictures = mShowPictures;
return savedState;
}
@Override
public void onRestoreInstanceState(Parcelable state) {
if(!(state instanceof SavedState)) {
super.onRestoreInstanceState(state);
return;
}
SavedState savedState = (SavedState)state;
super.onRestoreInstanceState(savedState.getSuperState());
mSavedState = savedState;
}
@Override
public void onLayoutChanged() {
if (mMessageContentView != null) {
mMessageContentView.invalidate();
}
}
public void enableAttachmentButtons(AttachmentViewInfo attachment) {
getAttachmentView(attachment).enableButtons();
}
public void disableAttachmentButtons(AttachmentViewInfo attachment) {
getAttachmentView(attachment).disableButtons();
}
public void refreshAttachmentThumbnail(AttachmentViewInfo attachment) {
getAttachmentView(attachment).refreshThumbnail();
}
private AttachmentView getAttachmentView(AttachmentViewInfo attachment) {
return attachments.get(attachment);
}
static class SavedState extends BaseSavedState {
boolean attachmentViewVisible;
boolean hiddenAttachmentsVisible;
boolean showPictures;
public static final Parcelable.Creator<SavedState> CREATOR =
new Parcelable.Creator<SavedState>() {
@Override
public SavedState createFromParcel(Parcel in) {
return new SavedState(in);
}
@Override
public SavedState[] newArray(int size) {
return new SavedState[size];
}
};
SavedState(Parcelable superState) {
super(superState);
}
private SavedState(Parcel in) {
super(in);
this.attachmentViewVisible = (in.readInt() != 0);
this.hiddenAttachmentsVisible = (in.readInt() != 0);
this.showPictures = (in.readInt() != 0);
}
@Override
public void writeToParcel(Parcel out, int flags) {
super.writeToParcel(out, flags);
out.writeInt((this.attachmentViewVisible) ? 1 : 0);
out.writeInt((this.hiddenAttachmentsVisible) ? 1 : 0);
out.writeInt((this.showPictures) ? 1 : 0);
}
}
class DownloadImageTask extends AsyncTask<String, Void, String> {
@Override
protected String doInBackground(String... params) {
String urlString = params[0];
try {
boolean externalImage = urlString.startsWith("http");
String filename = null;
String mimeType = null;
InputStream in = null;
try {
if (externalImage) {
URL url = new URL(urlString);
URLConnection conn = url.openConnection();
in = conn.getInputStream();
String path = url.getPath();
// Try to get the filename from the URL
int start = path.lastIndexOf("/");
if (start != -1 && start + 1 < path.length()) {
filename = UrlEncodingHelper.decodeUtf8(path.substring(start + 1));
} else {
// Use a dummy filename if necessary
filename = "saved_image";
}
// Get the MIME type if we couldn't find a file extension
if (filename.indexOf('.') == -1) {
mimeType = conn.getContentType();
}
} else {
ContentResolver contentResolver = getContext().getContentResolver();
Uri uri = Uri.parse(urlString);
// Get the filename from AttachmentProvider
Cursor cursor = contentResolver.query(uri, ATTACHMENT_PROJECTION, null, null, null);
if (cursor != null) {
try {
if (cursor.moveToNext()) {
filename = cursor.getString(DISPLAY_NAME_INDEX);
}
} finally {
cursor.close();
}
}
// Use a dummy filename if necessary
if (filename == null) {
filename = "saved_image";
}
// Get the MIME type if we couldn't find a file extension
if (filename.indexOf('.') == -1) {
mimeType = contentResolver.getType(uri);
}
in = contentResolver.openInputStream(uri);
}
// Do we still need an extension?
if (filename.indexOf('.') == -1) {
// Use JPEG as fallback
String extension = "jpeg";
if (mimeType != null) {
// Try to find an extension for the given MIME type
String ext = MimeUtility.getExtensionByMimeType(mimeType);
if (ext != null) {
extension = ext;
}
}
filename += "." + extension;
}
String sanitized = FileHelper.sanitizeFilename(filename);
File directory = new File(K9.getAttachmentDefaultPath());
File file = FileHelper.createUniqueFile(directory, sanitized);
FileOutputStream out = new FileOutputStream(file);
try {
IOUtils.copy(in, out);
out.flush();
} finally {
out.close();
}
return file.getName();
} finally {
if (in != null) {
in.close();
}
}
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
@Override
protected void onPostExecute(String filename) {
String text;
if (filename == null) {
text = getContext().getString(R.string.image_saving_failed);
} else {
text = getContext().getString(R.string.image_saved_as, filename);
}
Toast.makeText(getContext(), text, Toast.LENGTH_LONG).show();
}
}
}