AttachmentInfo.java revision 3f60e9312b1bf1324dd0e343b07cb69c9f8d31fd
1/* 2 * Copyright (C) 2011 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.email; 18 19import com.android.emailcommon.internet.MimeUtility; 20import com.android.emailcommon.provider.EmailContent.Attachment; 21import com.android.emailcommon.utility.AttachmentUtilities; 22import com.android.emailcommon.utility.Utility; 23 24import android.content.Context; 25import android.content.Intent; 26import android.content.pm.PackageManager; 27import android.content.pm.ResolveInfo; 28import android.database.Cursor; 29import android.net.ConnectivityManager; 30import android.net.NetworkInfo; 31import android.net.Uri; 32import android.provider.Settings; 33import android.text.TextUtils; 34 35import java.util.List; 36 37/** 38 * Encapsulates commonly used attachment information related to suitability for viewing and saving, 39 * based on the attachment's filename and mime type. 40 */ 41public class AttachmentInfo { 42 // Projection which can be used with the constructor taking a Cursor argument 43 public static final String[] PROJECTION = new String[] {Attachment.RECORD_ID, Attachment.SIZE, 44 Attachment.FILENAME, Attachment.MIME_TYPE, Attachment.ACCOUNT_KEY}; 45 // Offsets into PROJECTION 46 public static final int COLUMN_ID = 0; 47 public static final int COLUMN_SIZE = 1; 48 public static final int COLUMN_FILENAME = 2; 49 public static final int COLUMN_MIME_TYPE = 3; 50 public static final int COLUMN_ACCOUNT_KEY = 4; 51 52 /** Attachment not denied */ 53 public static final int ALLOW = 0x00; 54 /** Attachment suspected of being malware */ 55 public static final int DENY_MALWARE = 0x01; 56 /** Attachment too large; must download over wi-fi */ 57 public static final int DENY_WIFIONLY = 0x02; 58 /** No receiving intent to handle attachment type */ 59 public static final int DENY_NOINTENT = 0x04; 60 /** Side load of applications is disabled */ 61 public static final int DENY_NOSIDELOAD = 0x08; 62 // TODO Remove DENY_APKINSTALL when we can install directly from the Email activity 63 /** Unable to install any APK */ 64 public static final int DENY_APKINSTALL = 0x10; 65 66 public final long mId; 67 public final long mSize; 68 public final String mName; 69 public final String mContentType; 70 public final long mAccountKey; 71 72 /** Whether or not this attachment can be viewed */ 73 public final boolean mAllowView; 74 /** Whether or not this attachment can be saved */ 75 public final boolean mAllowSave; 76 /** Whether or not this attachment can be installed [only true for APKs] */ 77 public final boolean mAllowInstall; 78 /** Reason(s) why this attachment is denied from being viewed */ 79 public final int mDenyFlags; 80 81 public AttachmentInfo(Context context, Attachment attachment) { 82 this(context, attachment.mId, attachment.mSize, attachment.mFileName, attachment.mMimeType, 83 attachment.mAccountKey); 84 } 85 86 public AttachmentInfo(Context context, Cursor c) { 87 this(context, c.getLong(COLUMN_ID), c.getLong(COLUMN_SIZE), c.getString(COLUMN_FILENAME), 88 c.getString(COLUMN_MIME_TYPE), c.getLong(COLUMN_ACCOUNT_KEY)); 89 } 90 91 public AttachmentInfo(Context context, AttachmentInfo info) { 92 this(context, info.mId, info.mSize, info.mName, info.mContentType, info.mAccountKey); 93 } 94 95 public AttachmentInfo(Context context, long id, long size, String fileName, String mimeType, 96 long accountKey) { 97 mSize = size; 98 mContentType = AttachmentUtilities.inferMimeType(fileName, mimeType); 99 mName = fileName; 100 mId = id; 101 mAccountKey = accountKey; 102 boolean canView = true; 103 boolean canSave = true; 104 boolean canInstall = false; 105 int denyFlags = ALLOW; 106 107 // Don't enable the "save" button if we've got no place to save the file 108 if (!Utility.isExternalStorageMounted()) { 109 canSave = false; 110 } 111 112 // Check for acceptable / unacceptable attachments by MIME-type 113 if ((!MimeUtility.mimeTypeMatches(mContentType, 114 AttachmentUtilities.ACCEPTABLE_ATTACHMENT_VIEW_TYPES)) || 115 (MimeUtility.mimeTypeMatches(mContentType, 116 AttachmentUtilities.UNACCEPTABLE_ATTACHMENT_VIEW_TYPES))) { 117 canView = false; 118 } 119 120 // Check for unacceptable attachments by filename extension 121 String extension = AttachmentUtilities.getFilenameExtension(mName); 122 if (!TextUtils.isEmpty(extension) && 123 Utility.arrayContains(AttachmentUtilities.UNACCEPTABLE_ATTACHMENT_EXTENSIONS, 124 extension)) { 125 canView = false; 126 canSave = false; 127 denyFlags |= DENY_MALWARE; 128 } 129 130 // Check for installable attachments by filename extension 131 extension = AttachmentUtilities.getFilenameExtension(mName); 132 if (!TextUtils.isEmpty(extension) && 133 Utility.arrayContains(AttachmentUtilities.INSTALLABLE_ATTACHMENT_EXTENSIONS, 134 extension)) { 135 boolean sideloadEnabled; 136 sideloadEnabled = Settings.Secure.getInt(context.getContentResolver(), 137 Settings.Secure.INSTALL_NON_MARKET_APPS, 0 /* sideload disabled */) == 1; 138 // NOTE: Currently we prevent viewing (or installing) any application attachment 139 // from within Email. When we support installing directly from view, save and 140 // install should all be following sideloadEnabled. 141 canView = false; 142 canSave &= sideloadEnabled; 143 if (!sideloadEnabled) { 144 denyFlags |= DENY_NOSIDELOAD; 145 } else { 146 denyFlags |= DENY_APKINSTALL; 147 } 148 canInstall = canView; 149 } 150 151 // Check for file size exceeded 152 // The size limit is overridden when on a wifi connection - any size is OK 153 if (mSize > AttachmentUtilities.MAX_ATTACHMENT_DOWNLOAD_SIZE) { 154 ConnectivityManager cm = (ConnectivityManager) 155 context.getSystemService(Context.CONNECTIVITY_SERVICE); 156 NetworkInfo network = cm.getActiveNetworkInfo(); 157 if (network == null || network.getType() != ConnectivityManager.TYPE_WIFI) { 158 canView = false; 159 canSave = false; 160 denyFlags |= DENY_WIFIONLY; 161 } 162 } 163 164 // Check to see if any activities can view this attachment; if none, we can't view it 165 Intent intent = getAttachmentIntent(context, 0); 166 PackageManager pm = context.getPackageManager(); 167 List<ResolveInfo> activityList = pm.queryIntentActivities(intent, 0 /*no account*/); 168 if (activityList.isEmpty()) { 169 canView = false; 170 canSave = false; 171 denyFlags |= DENY_NOINTENT; 172 } 173 174 mAllowView = canView; 175 mAllowSave = canSave; 176 mAllowInstall = canInstall; 177 mDenyFlags = denyFlags; 178 } 179 180 /** 181 * Returns an <code>Intent</code> to load the given attachment. 182 * @param context the caller's context 183 * @param accountId the account associated with the attachment (or 0 if we don't need to 184 * resolve from attachmentUri to contentUri) 185 * @return an Intent suitable for loading the attachment 186 */ 187 public Intent getAttachmentIntent(Context context, long accountId) { 188 Uri contentUri = AttachmentUtilities.getAttachmentUri(accountId, mId); 189 if (accountId > 0) { 190 contentUri = AttachmentUtilities.resolveAttachmentIdToContentUri( 191 context.getContentResolver(), contentUri); 192 } 193 Intent intent = new Intent(Intent.ACTION_VIEW); 194 intent.setData(contentUri); 195 intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION 196 | Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET); 197 return intent; 198 } 199 200 /** 201 * An attachment is eligible for download if it can either be viewed or saved (or both) 202 * @return whether the attachment is eligible for download 203 */ 204 public boolean isEligibleForDownload() { 205 return mAllowView || mAllowSave; 206 } 207 208 @Override 209 public String toString() { 210 return "{Attachment " + mId + ":" + mName + "," + mContentType + "," + mSize + "}"; 211 } 212} 213