Merge "Update file type acceptance rules" into honeycomb
This commit is contained in:
commit
071274f078
@ -112,7 +112,7 @@ public class Email extends Application {
|
||||
* The MIME type(s) of attachments we're willing to download to SD.
|
||||
*/
|
||||
public static final String[] ACCEPTABLE_ATTACHMENT_DOWNLOAD_TYPES = new String[] {
|
||||
"image/*",
|
||||
"*/*",
|
||||
};
|
||||
|
||||
/**
|
||||
@ -121,6 +121,21 @@ public class Email extends Application {
|
||||
public static final String[] UNACCEPTABLE_ATTACHMENT_DOWNLOAD_TYPES = new String[] {
|
||||
};
|
||||
|
||||
/**
|
||||
* Filename extensions of attachments we're never willing to download (potential malware).
|
||||
* Entries in this list are compared to the end of the lower-cased filename, so they must
|
||||
* be lower case, and should not include a "."
|
||||
*/
|
||||
public static final String[] UNACCEPTABLE_ATTACHMENT_EXTENSIONS = new String[] {
|
||||
// File types that contain malware
|
||||
"ade", "adp", "bat", "chm", "cmd", "com", "cpl", "dll", "exe",
|
||||
"hta", "ins", "isp", "jse", "lib", "mde", "msc", "msp",
|
||||
"mst", "pif", "scr", "sct", "shb", "sys", "vb", "vbe",
|
||||
"vbs", "vxd", "wsc", "wsf", "wsh",
|
||||
// File types of common compression/container formats (again, to avoid malware)
|
||||
"zip", "gz", "z", "tar", "tgz", "bz2",
|
||||
};
|
||||
|
||||
/**
|
||||
* Specifies how many messages will be shown in a folder by default. This number is set
|
||||
* on each new folder and can be incremented with "Load more messages..." by the
|
||||
|
@ -49,6 +49,8 @@ import android.content.res.Resources;
|
||||
import android.database.ContentObserver;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.net.ConnectivityManager;
|
||||
import android.net.NetworkInfo;
|
||||
import android.net.Uri;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
@ -201,6 +203,9 @@ public abstract class MessageViewFragmentBase extends Fragment implements View.O
|
||||
|
||||
/**
|
||||
* Encapsulates known information about a single attachment.
|
||||
*
|
||||
* TODO: This should have methods to encapsulate the entire state graph of loading, canceling,
|
||||
* viewing, and saving.
|
||||
*/
|
||||
private static class AttachmentInfo {
|
||||
public String name;
|
||||
@ -213,6 +218,9 @@ public abstract class MessageViewFragmentBase extends Fragment implements View.O
|
||||
public Button cancelButton;
|
||||
public ImageView iconView;
|
||||
public ProgressBar progressView;
|
||||
public boolean allowView;
|
||||
public boolean allowSave;
|
||||
public boolean isLoaded;
|
||||
}
|
||||
|
||||
public interface Callback {
|
||||
@ -738,10 +746,8 @@ public abstract class MessageViewFragmentBase extends Fragment implements View.O
|
||||
}
|
||||
@Override
|
||||
protected void onPostExecute(Void result) {
|
||||
// If the load buttons is shown, it's already loaded -- don't show the stop
|
||||
// button.
|
||||
if (attachment.cancelButton.getVisibility() != View.VISIBLE
|
||||
&& attachment.loadButton.getVisibility() != View.VISIBLE) {
|
||||
// If the timeout completes and the attachment has not loaded, show cancel
|
||||
if (!attachment.isLoaded) {
|
||||
attachment.cancelButton.setVisibility(View.VISIBLE);
|
||||
}
|
||||
}
|
||||
@ -773,10 +779,15 @@ public abstract class MessageViewFragmentBase extends Fragment implements View.O
|
||||
private void doFinishLoadAttachment(long attachmentId) {
|
||||
AttachmentInfo info = findAttachmentInfo(attachmentId);
|
||||
if (info != null) {
|
||||
info.isLoaded = true;
|
||||
|
||||
info.loadButton.setVisibility(View.GONE);
|
||||
info.cancelButton.setVisibility(View.GONE);
|
||||
info.saveButton.setVisibility(TextUtils.isEmpty(info.name) ? View.GONE : View.VISIBLE);
|
||||
info.viewButton.setVisibility(View.VISIBLE);
|
||||
|
||||
boolean showSave = info.allowSave && !TextUtils.isEmpty(info.name);
|
||||
boolean showView = info.allowView;
|
||||
info.saveButton.setVisibility(showSave ? View.VISIBLE : View.GONE);
|
||||
info.viewButton.setVisibility(showView ? View.VISIBLE : View.GONE);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1108,6 +1119,9 @@ public abstract class MessageViewFragmentBase extends Fragment implements View.O
|
||||
AttachmentProvider.inferMimeType(attachment.mFileName, attachment.mMimeType);
|
||||
attachmentInfo.name = attachment.mFileName;
|
||||
attachmentInfo.attachmentId = attachment.mId;
|
||||
attachmentInfo.allowView = true;
|
||||
attachmentInfo.allowSave = true;
|
||||
attachmentInfo.isLoaded = false;
|
||||
|
||||
LayoutInflater inflater = getActivity().getLayoutInflater();
|
||||
View view = inflater.inflate(R.layout.message_view_attachment, null);
|
||||
@ -1121,16 +1135,42 @@ public abstract class MessageViewFragmentBase extends Fragment implements View.O
|
||||
Button attachmentCancel = (Button)view.findViewById(R.id.cancel);
|
||||
ProgressBar attachmentProgress = (ProgressBar)view.findViewById(R.id.progress);
|
||||
|
||||
// TODO: Remove this test (acceptable types = everything; unacceptable = nothing)
|
||||
if ((!MimeUtility.mimeTypeMatches(attachmentInfo.contentType,
|
||||
Email.ACCEPTABLE_ATTACHMENT_VIEW_TYPES))
|
||||
|| (MimeUtility.mimeTypeMatches(attachmentInfo.contentType,
|
||||
Email.UNACCEPTABLE_ATTACHMENT_VIEW_TYPES))) {
|
||||
attachmentView.setVisibility(View.GONE);
|
||||
// Check for acceptable / unacceptable attachments by MIME-type
|
||||
String contentType = attachmentInfo.contentType;
|
||||
if ((!MimeUtility.mimeTypeMatches(contentType, Email.ACCEPTABLE_ATTACHMENT_VIEW_TYPES)) ||
|
||||
(MimeUtility.mimeTypeMatches(contentType, Email.UNACCEPTABLE_ATTACHMENT_VIEW_TYPES))) {
|
||||
attachmentInfo.allowView = false;
|
||||
}
|
||||
|
||||
// Check for unacceptable attachments by filename extension; hide both buttons
|
||||
String extension = AttachmentProvider.getFilenameExtension(attachmentInfo.name);
|
||||
if (!TextUtils.isEmpty(extension) &&
|
||||
Utility.arrayContains(Email.UNACCEPTABLE_ATTACHMENT_EXTENSIONS, extension)) {
|
||||
attachmentInfo.allowView = false;
|
||||
attachmentInfo.allowSave = false;
|
||||
}
|
||||
|
||||
// File size exceeded; Hide both buttons
|
||||
// The size limit is overridden when on a wifi connection - any size is OK
|
||||
if (attachmentInfo.size > Email.MAX_ATTACHMENT_DOWNLOAD_SIZE) {
|
||||
ConnectivityManager cm = (ConnectivityManager)
|
||||
mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||
NetworkInfo network = cm.getActiveNetworkInfo();
|
||||
if (network == null || network.getType() != ConnectivityManager.TYPE_WIFI) {
|
||||
attachmentInfo.allowView = false;
|
||||
attachmentInfo.allowSave = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Don't enable the "save" button if we've got no place to save the file
|
||||
if (!Utility.isExternalStorageMounted()) {
|
||||
attachmentInfo.allowSave = false;
|
||||
}
|
||||
|
||||
if (!attachmentInfo.allowView) {
|
||||
attachmentView.setVisibility(View.GONE);
|
||||
}
|
||||
if (!attachmentInfo.allowSave) {
|
||||
attachmentSave.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
@ -1141,15 +1181,29 @@ public abstract class MessageViewFragmentBase extends Fragment implements View.O
|
||||
attachmentInfo.iconView = attachmentIcon;
|
||||
attachmentInfo.progressView = attachmentProgress;
|
||||
|
||||
// If the attachment is loaded, show 100% progress
|
||||
// Note that for POP3 messages, the user will only see "Open" and "Save" since the entire
|
||||
// message is loaded before being shown.
|
||||
if (Utility.attachmentExists(mContext, attachment)) {
|
||||
if (!attachmentInfo.allowView && !attachmentInfo.allowSave) {
|
||||
// This attachment may never be viewed or saved, so block everything
|
||||
attachmentProgress.setVisibility(View.GONE);
|
||||
attachmentView.setVisibility(View.GONE);
|
||||
attachmentSave.setVisibility(View.GONE);
|
||||
attachmentLoad.setVisibility(View.GONE);
|
||||
attachmentCancel.setVisibility(View.GONE);
|
||||
// TODO: Maybe show a little icon to denote blocked download
|
||||
} else if (Utility.attachmentExists(mContext, attachment)) {
|
||||
// If the attachment is loaded, show 100% progress
|
||||
// Note that for POP3 messages, the user will only see "Open" and "Save",
|
||||
// because the entire message is loaded before being shown.
|
||||
attachmentInfo.isLoaded = true;
|
||||
|
||||
// Hide "Load", show "View" and "Save"
|
||||
attachmentProgress.setVisibility(View.VISIBLE);
|
||||
attachmentProgress.setProgress(100);
|
||||
attachmentSave.setVisibility(View.VISIBLE);
|
||||
attachmentView.setVisibility(View.VISIBLE);
|
||||
if (attachmentInfo.allowSave) {
|
||||
attachmentSave.setVisibility(View.VISIBLE);
|
||||
}
|
||||
if (attachmentInfo.allowView) {
|
||||
attachmentView.setVisibility(View.VISIBLE);
|
||||
}
|
||||
attachmentLoad.setVisibility(View.GONE);
|
||||
attachmentCancel.setVisibility(View.GONE);
|
||||
|
||||
@ -1158,6 +1212,8 @@ public abstract class MessageViewFragmentBase extends Fragment implements View.O
|
||||
attachmentIcon.setImageBitmap(previewIcon);
|
||||
}
|
||||
} else {
|
||||
// The attachment is not loaded, so present UI to start downloading it
|
||||
|
||||
// Show "Load"; hide "View" and "Save"
|
||||
attachmentSave.setVisibility(View.GONE);
|
||||
attachmentView.setVisibility(View.GONE);
|
||||
@ -1175,11 +1231,6 @@ public abstract class MessageViewFragmentBase extends Fragment implements View.O
|
||||
}
|
||||
}
|
||||
|
||||
// Don't enable the "save" button if we've got no place to save the file
|
||||
if (!Utility.isExternalStorageMounted()) {
|
||||
attachmentSave.setEnabled(false);
|
||||
}
|
||||
|
||||
view.setTag(attachmentInfo);
|
||||
attachmentView.setOnClickListener(this);
|
||||
attachmentView.setTag(attachmentInfo);
|
||||
|
@ -208,11 +208,7 @@ public class AttachmentProvider extends ContentProvider {
|
||||
|
||||
// Try to find an extension in the filename
|
||||
if (!TextUtils.isEmpty(fileName)) {
|
||||
int lastDot = fileName.lastIndexOf('.');
|
||||
String extension = null;
|
||||
if ((lastDot > 0) && (lastDot < fileName.length() - 1)) {
|
||||
extension = fileName.substring(lastDot + 1).toLowerCase();
|
||||
}
|
||||
String extension = getFilenameExtension(fileName);
|
||||
if (!TextUtils.isEmpty(extension)) {
|
||||
// Extension found. Look up mime type, or synthesize if none found.
|
||||
mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
|
||||
@ -227,6 +223,22 @@ public class AttachmentProvider extends ContentProvider {
|
||||
return "application/octet-stream";
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract and return filename's extension, converted to lower case, and not including the "."
|
||||
*
|
||||
* @return extension, or null if not found (or null/empty filename)
|
||||
*/
|
||||
public static String getFilenameExtension(String fileName) {
|
||||
String extension = null;
|
||||
if (!TextUtils.isEmpty(fileName)) {
|
||||
int lastDot = fileName.lastIndexOf('.');
|
||||
if ((lastDot > 0) && (lastDot < fileName.length() - 1)) {
|
||||
extension = fileName.substring(lastDot + 1).toLowerCase();
|
||||
}
|
||||
}
|
||||
return extension;
|
||||
}
|
||||
|
||||
/**
|
||||
* Open an attachment file. There are two "modes" - "raw", which returns an actual file,
|
||||
* and "thumbnail", which attempts to generate a thumbnail image.
|
||||
|
@ -312,6 +312,27 @@ public class AttachmentProviderTests extends ProviderTestCase2<AttachmentProvide
|
||||
assertEquals("message/rfc822", AttachmentProvider.inferMimeType("a.eml", DEFAULT));
|
||||
}
|
||||
|
||||
/**
|
||||
* Text extension extractor
|
||||
*/
|
||||
public void testGetFilenameExtension() {
|
||||
final String FILE_NO_EXTENSION = "myfile";
|
||||
final String FILE_EXTENSION = "myfile.pDf";
|
||||
final String FILE_TWO_EXTENSIONS = "myfile.false.AbC";
|
||||
|
||||
assertNull(AttachmentProvider.getFilenameExtension(null));
|
||||
assertNull(AttachmentProvider.getFilenameExtension(""));
|
||||
assertNull(AttachmentProvider.getFilenameExtension(FILE_NO_EXTENSION));
|
||||
|
||||
assertEquals("pdf", AttachmentProvider.getFilenameExtension(FILE_EXTENSION));
|
||||
assertEquals("abc", AttachmentProvider.getFilenameExtension(FILE_TWO_EXTENSIONS));
|
||||
|
||||
// The API makes no claim as to how these are handled (it probably should),
|
||||
// but make sure that they don't crash.
|
||||
AttachmentProvider.getFilenameExtension("filename.");
|
||||
AttachmentProvider.getFilenameExtension(".extension");
|
||||
}
|
||||
|
||||
/**
|
||||
* test openFile()
|
||||
* - regular file
|
||||
|
Loading…
Reference in New Issue
Block a user