17434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein/* 27434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein * Copyright (C) 2013 Google Inc. 37434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein * Licensed to The Android Open Source Project. 47434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein * 57434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein * Licensed under the Apache License, Version 2.0 (the "License"); 67434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein * you may not use this file except in compliance with the License. 77434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein * You may obtain a copy of the License at 87434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein * 97434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein * http://www.apache.org/licenses/LICENSE-2.0 107434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein * 117434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein * Unless required by applicable law or agreed to in writing, software 127434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein * distributed under the License is distributed on an "AS IS" BASIS, 137434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 147434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein * See the License for the specific language governing permissions and 157434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein * limitations under the License. 167434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein */ 177434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein 187434e800d4313a227120ca36bd95683752a7879fAndrew Sappersteinpackage com.android.mail.providers; 197434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein 207434e800d4313a227120ca36bd95683752a7879fAndrew Sappersteinimport android.app.DownloadManager; 217434e800d4313a227120ca36bd95683752a7879fAndrew Sappersteinimport android.content.ContentProvider; 22934b1f470a646a4ca64fc63eeb823d4c5c12698eJames Lemieuximport android.content.ContentResolver; 237434e800d4313a227120ca36bd95683752a7879fAndrew Sappersteinimport android.content.ContentValues; 247434e800d4313a227120ca36bd95683752a7879fAndrew Sappersteinimport android.content.Context; 257434e800d4313a227120ca36bd95683752a7879fAndrew Sappersteinimport android.content.Intent; 267434e800d4313a227120ca36bd95683752a7879fAndrew Sappersteinimport android.content.UriMatcher; 277434e800d4313a227120ca36bd95683752a7879fAndrew Sappersteinimport android.database.Cursor; 287434e800d4313a227120ca36bd95683752a7879fAndrew Sappersteinimport android.database.MatrixCursor; 297434e800d4313a227120ca36bd95683752a7879fAndrew Sappersteinimport android.net.Uri; 307434e800d4313a227120ca36bd95683752a7879fAndrew Sappersteinimport android.os.Environment; 317434e800d4313a227120ca36bd95683752a7879fAndrew Sappersteinimport android.os.ParcelFileDescriptor; 327434e800d4313a227120ca36bd95683752a7879fAndrew Sappersteinimport android.os.SystemClock; 33934b1f470a646a4ca64fc63eeb823d4c5c12698eJames Lemieuximport android.text.TextUtils; 347434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein 357434e800d4313a227120ca36bd95683752a7879fAndrew Sappersteinimport com.android.ex.photo.provider.PhotoContract; 367434e800d4313a227120ca36bd95683752a7879fAndrew Sappersteinimport com.android.mail.R; 377434e800d4313a227120ca36bd95683752a7879fAndrew Sappersteinimport com.android.mail.utils.LogTag; 387434e800d4313a227120ca36bd95683752a7879fAndrew Sappersteinimport com.android.mail.utils.LogUtils; 391317896352698e41d2053d6f83175c181c6e39f0Andrew Sappersteinimport com.android.mail.utils.MimeType; 407434e800d4313a227120ca36bd95683752a7879fAndrew Sappersteinimport com.google.common.collect.Lists; 417434e800d4313a227120ca36bd95683752a7879fAndrew Sappersteinimport com.google.common.collect.Maps; 427434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein 437434e800d4313a227120ca36bd95683752a7879fAndrew Sappersteinimport java.io.File; 447434e800d4313a227120ca36bd95683752a7879fAndrew Sappersteinimport java.io.FileInputStream; 457434e800d4313a227120ca36bd95683752a7879fAndrew Sappersteinimport java.io.FileNotFoundException; 467434e800d4313a227120ca36bd95683752a7879fAndrew Sappersteinimport java.io.FileOutputStream; 477434e800d4313a227120ca36bd95683752a7879fAndrew Sappersteinimport java.io.IOException; 487434e800d4313a227120ca36bd95683752a7879fAndrew Sappersteinimport java.io.InputStream; 497434e800d4313a227120ca36bd95683752a7879fAndrew Sappersteinimport java.io.OutputStream; 507434e800d4313a227120ca36bd95683752a7879fAndrew Sappersteinimport java.util.List; 517434e800d4313a227120ca36bd95683752a7879fAndrew Sappersteinimport java.util.Map; 527434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein 537434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein/** 547434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein * A {@link ContentProvider} for attachments created from eml files. 557434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein * Supports all of the semantics (query/insert/update/delete/openFile) 567434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein * of the regular attachment provider. 577434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein * 587434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein * One major difference is that all attachment info is stored in memory (with the 597434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein * exception of the attachment raw data which is stored in the cache). When 607434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein * the process is killed, all of the attachments disappear if they still 617434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein * exist. 627434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein */ 637434e800d4313a227120ca36bd95683752a7879fAndrew Sappersteinpublic class EmlAttachmentProvider extends ContentProvider { 647434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein private static final String LOG_TAG = LogTag.getLogTag(); 657434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein 667434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein private static final UriMatcher sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH); 677434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein private static boolean sUrisAddedToMatcher = false; 687434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein 697434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein private static final int ATTACHMENT_LIST = 0; 707434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein private static final int ATTACHMENT = 1; 71934b1f470a646a4ca64fc63eeb823d4c5c12698eJames Lemieux private static final int ATTACHMENT_BY_CID = 2; 727434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein 737434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein /** 747434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein * The buffer size used to copy data from cache to sd card. 757434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein */ 767434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein private static final int BUFFER_SIZE = 4096; 777434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein 787434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein /** Any IO reads should be limited to this timeout */ 797434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein private static final long READ_TIMEOUT = 3600 * 1000; 807434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein 817434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein private static Uri BASE_URI; 827434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein 837434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein private DownloadManager mDownloadManager; 847434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein 857434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein /** 867434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein * Map that contains a mapping from an attachment list uri to a list of uris. 877434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein */ 887434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein private Map<Uri, List<Uri>> mUriListMap; 897434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein 907434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein /** 917434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein * Map that contains a mapping from an attachment uri to an {@link Attachment} object. 927434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein */ 937434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein private Map<Uri, Attachment> mUriAttachmentMap; 947434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein 957434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein 967434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein @Override 977434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein public boolean onCreate() { 987434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein final String authority = 997434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein getContext().getResources().getString(R.string.eml_attachment_provider); 1007434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein BASE_URI = new Uri.Builder().scheme("content").authority(authority).build(); 1017434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein 1027434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein if (!sUrisAddedToMatcher) { 1037434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein sUrisAddedToMatcher = true; 104934b1f470a646a4ca64fc63eeb823d4c5c12698eJames Lemieux sUriMatcher.addURI(authority, "attachments/*/*", ATTACHMENT_LIST); 105934b1f470a646a4ca64fc63eeb823d4c5c12698eJames Lemieux sUriMatcher.addURI(authority, "attachment/*/*/#", ATTACHMENT); 106934b1f470a646a4ca64fc63eeb823d4c5c12698eJames Lemieux sUriMatcher.addURI(authority, "attachmentByCid/*/*/*", ATTACHMENT_BY_CID); 1077434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein } 1087434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein 1097434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein mDownloadManager = 1107434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein (DownloadManager) getContext().getSystemService(Context.DOWNLOAD_SERVICE); 1117434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein 1127434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein mUriListMap = Maps.newHashMap(); 1137434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein mUriAttachmentMap = Maps.newHashMap(); 1147434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein return true; 1157434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein } 1167434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein 1177434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein @Override 1187434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, 1197434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein String sortOrder) { 1207434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein final int match = sUriMatcher.match(uri); 1217434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein // ignore other projections 1227434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein final MatrixCursor cursor = new MatrixCursor(UIProvider.ATTACHMENT_PROJECTION); 123934b1f470a646a4ca64fc63eeb823d4c5c12698eJames Lemieux final ContentResolver cr = getContext().getContentResolver(); 1247434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein 1257434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein switch (match) { 126934b1f470a646a4ca64fc63eeb823d4c5c12698eJames Lemieux case ATTACHMENT_LIST: { 1277434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein final List<String> contentTypeQueryParameters = 1287434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein uri.getQueryParameters(PhotoContract.ContentTypeParameters.CONTENT_TYPE); 1297434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein uri = uri.buildUpon().clearQuery().build(); 1307434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein final List<Uri> attachmentUris = mUriListMap.get(uri); 1317434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein for (final Uri attachmentUri : attachmentUris) { 1327434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein addRow(cursor, attachmentUri, contentTypeQueryParameters); 1337434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein } 134934b1f470a646a4ca64fc63eeb823d4c5c12698eJames Lemieux cursor.setNotificationUri(cr, uri); 1357434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein break; 136934b1f470a646a4ca64fc63eeb823d4c5c12698eJames Lemieux } 137934b1f470a646a4ca64fc63eeb823d4c5c12698eJames Lemieux case ATTACHMENT: { 1387434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein addRow(cursor, mUriAttachmentMap.get(uri)); 139934b1f470a646a4ca64fc63eeb823d4c5c12698eJames Lemieux cursor.setNotificationUri(cr, getListUriFromAttachmentUri(uri)); 140934b1f470a646a4ca64fc63eeb823d4c5c12698eJames Lemieux break; 141934b1f470a646a4ca64fc63eeb823d4c5c12698eJames Lemieux } 142934b1f470a646a4ca64fc63eeb823d4c5c12698eJames Lemieux case ATTACHMENT_BY_CID: { 143934b1f470a646a4ca64fc63eeb823d4c5c12698eJames Lemieux // form the attachment lists uri by clipping off the cid from the given uri 144934b1f470a646a4ca64fc63eeb823d4c5c12698eJames Lemieux final Uri attachmentsListUri = getListUriFromAttachmentUri(uri); 145934b1f470a646a4ca64fc63eeb823d4c5c12698eJames Lemieux final String cid = uri.getPathSegments().get(3); 146934b1f470a646a4ca64fc63eeb823d4c5c12698eJames Lemieux 147934b1f470a646a4ca64fc63eeb823d4c5c12698eJames Lemieux // find all uris for the parent message 148934b1f470a646a4ca64fc63eeb823d4c5c12698eJames Lemieux final List<Uri> attachmentUris = mUriListMap.get(attachmentsListUri); 149934b1f470a646a4ca64fc63eeb823d4c5c12698eJames Lemieux 150934b1f470a646a4ca64fc63eeb823d4c5c12698eJames Lemieux if (attachmentUris != null) { 151934b1f470a646a4ca64fc63eeb823d4c5c12698eJames Lemieux // find the attachment that contains the given cid 152934b1f470a646a4ca64fc63eeb823d4c5c12698eJames Lemieux for (Uri attachmentsUri : attachmentUris) { 153934b1f470a646a4ca64fc63eeb823d4c5c12698eJames Lemieux final Attachment attachment = mUriAttachmentMap.get(attachmentsUri); 154934b1f470a646a4ca64fc63eeb823d4c5c12698eJames Lemieux if (TextUtils.equals(cid, attachment.partId)) { 155934b1f470a646a4ca64fc63eeb823d4c5c12698eJames Lemieux addRow(cursor, attachment); 156934b1f470a646a4ca64fc63eeb823d4c5c12698eJames Lemieux cursor.setNotificationUri(cr, attachmentsListUri); 157934b1f470a646a4ca64fc63eeb823d4c5c12698eJames Lemieux break; 158934b1f470a646a4ca64fc63eeb823d4c5c12698eJames Lemieux } 159934b1f470a646a4ca64fc63eeb823d4c5c12698eJames Lemieux } 160934b1f470a646a4ca64fc63eeb823d4c5c12698eJames Lemieux } 1617434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein break; 162934b1f470a646a4ca64fc63eeb823d4c5c12698eJames Lemieux } 1637434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein default: 1647434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein break; 1657434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein } 1667434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein 1677434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein return cursor; 1687434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein } 1697434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein 1707434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein @Override 1717434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein public String getType(Uri uri) { 1727434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein final int match = sUriMatcher.match(uri); 1737434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein switch (match) { 1747434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein case ATTACHMENT: 1757434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein return mUriAttachmentMap.get(uri).getContentType(); 1767434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein default: 1777434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein return null; 1787434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein } 1797434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein } 1807434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein 1817434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein @Override 1827434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein public Uri insert(Uri uri, ContentValues values) { 1837434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein final Uri listUri = getListUriFromAttachmentUri(uri); 1847434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein 1857434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein // add mapping from uri to attachment 1867434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein if (mUriAttachmentMap.put(uri, new Attachment(values)) == null) { 1877434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein // only add uri to list if the list 1887434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein // get list of attachment uris, creating if necessary 1897434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein List<Uri> list = mUriListMap.get(listUri); 1907434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein if (list == null) { 1917434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein list = Lists.newArrayList(); 1927434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein mUriListMap.put(listUri, list); 1937434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein } 1947434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein 1957434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein list.add(uri); 1967434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein } 1977434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein 1987434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein return uri; 1997434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein } 2007434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein 2017434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein @Override 2027434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein public int delete(Uri uri, String selection, String[] selectionArgs) { 2037434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein final int match = sUriMatcher.match(uri); 2047434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein switch (match) { 2057434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein case ATTACHMENT_LIST: 2067434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein // remove from list mapping 2077434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein final List<Uri> attachmentUris = mUriListMap.remove(uri); 2087434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein 2097434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein // delete each file and remove each element from the mapping 2107434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein for (final Uri attachmentUri : attachmentUris) { 2117434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein mUriAttachmentMap.remove(attachmentUri); 2127434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein } 2137434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein 2147434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein deleteDirectory(getCacheFileDirectory(uri)); 2157434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein // return rows affected 2167434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein return attachmentUris.size(); 2177434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein default: 2187434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein return 0; 2197434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein } 2207434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein } 2217434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein 2227434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein @Override 2237434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { 2247434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein final int match = sUriMatcher.match(uri); 2257434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein switch (match) { 2267434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein case ATTACHMENT: 2277434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein return copyAttachment(uri, values); 2287434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein default: 2297434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein return 0; 2307434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein } 2317434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein } 2327434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein 2337434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein /** 2347434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein * Adds a row to the cursor for the attachment at the specific attachment {@link Uri} 2357434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein * if the attachment's mime type matches one of the query parameters. 2367434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein * 2377434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein * Matching is defined to be starting with one of the query parameters. If no 2387434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein * parameters exist, all rows are added. 2397434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein */ 2407434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein private void addRow(MatrixCursor cursor, Uri uri, 2417434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein List<String> contentTypeQueryParameters) { 2427434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein final Attachment attachment = mUriAttachmentMap.get(uri); 2437434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein 2447434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein if (contentTypeQueryParameters != null && !contentTypeQueryParameters.isEmpty()) { 2457434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein for (final String type : contentTypeQueryParameters) { 2467434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein if (attachment.getContentType().startsWith(type)) { 2477434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein addRow(cursor, attachment); 2487434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein return; 2497434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein } 2507434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein } 2517434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein } else { 2527434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein addRow(cursor, attachment); 2537434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein } 2547434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein } 2557434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein 2567434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein /** 2577434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein * Adds a new row to the cursor for the specific attachment. 2587434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein */ 2593b965d78774a42358ce6bbdcc43b4c8df130a60eScott Kennedy private static void addRow(MatrixCursor cursor, Attachment attachment) { 2607434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein cursor.newRow() 2617434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein .add(attachment.getName()) // displayName 2627434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein .add(attachment.size) // size 2637434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein .add(attachment.uri) // uri 2647434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein .add(attachment.getContentType()) // contentType 2657434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein .add(attachment.state) // state 2667434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein .add(attachment.destination) // destination 2677434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein .add(attachment.downloadedSize) // downloadedSize 2687434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein .add(attachment.contentUri) // contentUri 2697434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein .add(attachment.thumbnailUri) // thumbnailUri 2707434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein .add(attachment.previewIntentUri) // previewIntentUri 2717434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein .add(attachment.providerData) // providerData 272e307785b44deec1eb2aad5ecf83ea4b581779baaAndrew Sapperstein .add(attachment.supportsDownloadAgain() ? 1 : 0) // supportsDownloadAgain 273e307785b44deec1eb2aad5ecf83ea4b581779baaAndrew Sapperstein .add(attachment.type) // type 274934b1f470a646a4ca64fc63eeb823d4c5c12698eJames Lemieux .add(attachment.flags) // flags 275934b1f470a646a4ca64fc63eeb823d4c5c12698eJames Lemieux .add(attachment.partId); // partId (same as RFC822 cid) 2767434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein } 2777434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein 2787434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein /** 2797434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein * Copies an attachment at the specified {@link Uri} 2807434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein * from cache to the external downloads directory (usually the sd card). 2817434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein * @return the number of attachments affected. Should be 1 or 0. 2827434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein */ 2837434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein private int copyAttachment(Uri uri, ContentValues values) { 2847434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein final Integer newState = values.getAsInteger(UIProvider.AttachmentColumns.STATE); 2857434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein final Integer newDestination = 2867434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein values.getAsInteger(UIProvider.AttachmentColumns.DESTINATION); 2877434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein if (newState == null && newDestination == null) { 2887434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein return 0; 2897434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein } 2907434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein 2917434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein final int destination = newDestination != null ? 2927434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein newDestination.intValue() : UIProvider.AttachmentDestination.CACHE; 2937434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein final boolean saveToSd = 2947434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein destination == UIProvider.AttachmentDestination.EXTERNAL; 2957434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein 2967434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein final Attachment attachment = mUriAttachmentMap.get(uri); 2977434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein 2987434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein // 1. check if already saved to sd (via uri save to sd) 2997434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein // and return if so (we shouldn't ever be here) 3007434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein 3017434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein // if the call was not to save to sd or already saved to sd, just bail out 3027434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein if (!saveToSd || attachment.isSavedToExternal()) { 3037434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein return 0; 3047434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein } 3057434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein 3067434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein 3077434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein // 2. copy file 3087434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein final String oldFilePath = getFilePath(uri); 3097434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein 3107434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein // update the destination before getting the new file path 3117434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein // otherwise it will just point to the old location. 3127434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein attachment.destination = UIProvider.AttachmentDestination.EXTERNAL; 3137434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein final String newFilePath = getFilePath(uri); 3147434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein 3157434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein InputStream inputStream = null; 3167434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein OutputStream outputStream = null; 3177434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein 3187434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein try { 3197434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein try { 3207434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein inputStream = new FileInputStream(oldFilePath); 3217434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein } catch (FileNotFoundException e) { 3227434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein LogUtils.e(LOG_TAG, "File not found for file %s", oldFilePath); 3237434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein return 0; 3247434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein } 3257434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein try { 3267434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein outputStream = new FileOutputStream(newFilePath); 3277434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein } catch (FileNotFoundException e) { 3287434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein LogUtils.e(LOG_TAG, "File not found for file %s", newFilePath); 3297434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein return 0; 3307434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein } 3317434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein try { 3327434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein final long now = SystemClock.elapsedRealtime(); 3337434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein final byte data[] = new byte[BUFFER_SIZE]; 3347434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein int size = 0; 3357434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein while (true) { 3367434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein final int len = inputStream.read(data); 3377434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein if (len != -1) { 3387434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein outputStream.write(data, 0, len); 3397434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein 3407434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein size += len; 3417434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein } else { 3427434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein break; 3437434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein } 3447434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein if (SystemClock.elapsedRealtime() - now > READ_TIMEOUT) { 3457434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein throw new IOException("Timed out copying attachment."); 3467434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein } 3477434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein } 3487434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein 3491317896352698e41d2053d6f83175c181c6e39f0Andrew Sapperstein // if the attachment is an APK, change contentUri to be a direct file uri 3501317896352698e41d2053d6f83175c181c6e39f0Andrew Sapperstein if (MimeType.isInstallable(attachment.getContentType())) { 3511317896352698e41d2053d6f83175c181c6e39f0Andrew Sapperstein attachment.contentUri = Uri.parse("file://" + newFilePath); 3521317896352698e41d2053d6f83175c181c6e39f0Andrew Sapperstein } 3531317896352698e41d2053d6f83175c181c6e39f0Andrew Sapperstein 3547434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein // 3. add file to download manager 3557434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein 3567434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein try { 3577434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein // TODO - make a better description 3587434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein final String description = attachment.getName(); 3597434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein mDownloadManager.addCompletedDownload(attachment.getName(), 3607434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein description, true, attachment.getContentType(), 3617434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein newFilePath, size, false); 3627434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein } 3637434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein catch (IllegalArgumentException e) { 3647434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein // Even if we cannot save the download to the downloads app, 3657434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein // (likely due to a bad mimeType), we still want to save it. 3667434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein LogUtils.e(LOG_TAG, e, "Failed to save download to Downloads app."); 3677434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein } 3687434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein final Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE); 3697434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein intent.setData(Uri.parse("file://" + newFilePath)); 3707434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein getContext().sendBroadcast(intent); 3717434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein 3727434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein // 4. delete old file 3737434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein new File(oldFilePath).delete(); 3747434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein } catch (IOException e) { 3757434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein // Error writing file, delete partial file 3767434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein LogUtils.e(LOG_TAG, e, "Cannot write to file %s", newFilePath); 3777434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein new File(newFilePath).delete(); 3787434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein } 3797434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein } finally { 3807434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein try { 3817434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein if (inputStream != null) { 3827434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein inputStream.close(); 3837434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein } 3847434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein } catch (IOException e) { 3857434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein } 3867434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein try { 3877434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein if (outputStream != null) { 3887434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein outputStream.close(); 3897434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein } 3907434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein } catch (IOException e) { 3917434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein } 3927434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein } 3937434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein 3947434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein // 5. notify that the list of attachments has changed so the UI will update 3957434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein getContext().getContentResolver().notifyChange( 3967434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein getListUriFromAttachmentUri(uri), null, false); 3977434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein return 1; 3987434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein } 3997434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein 4007434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein @Override 4017434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException { 4027434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein final String filePath = getFilePath(uri); 4037434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein 4047434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein final int fileMode; 4057434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein 4067434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein if ("rwt".equals(mode)) { 4077434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein fileMode = ParcelFileDescriptor.MODE_READ_WRITE | 4087434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein ParcelFileDescriptor.MODE_TRUNCATE | 4097434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein ParcelFileDescriptor.MODE_CREATE; 4107434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein } else if ("rw".equals(mode)) { 4117434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein fileMode = ParcelFileDescriptor.MODE_READ_WRITE | ParcelFileDescriptor.MODE_CREATE; 4127434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein } else { 4137434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein fileMode = ParcelFileDescriptor.MODE_READ_ONLY; 4147434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein } 4157434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein 4167434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein return ParcelFileDescriptor.open(new File(filePath), fileMode); 4177434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein } 4187434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein 4197434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein /** 420934b1f470a646a4ca64fc63eeb823d4c5c12698eJames Lemieux * Returns an attachment list uri for the specific attachment uri passed. 421934b1f470a646a4ca64fc63eeb823d4c5c12698eJames Lemieux */ 422934b1f470a646a4ca64fc63eeb823d4c5c12698eJames Lemieux private static Uri getListUriFromAttachmentUri(Uri uri) { 423934b1f470a646a4ca64fc63eeb823d4c5c12698eJames Lemieux final List<String> segments = uri.getPathSegments(); 424934b1f470a646a4ca64fc63eeb823d4c5c12698eJames Lemieux return BASE_URI.buildUpon() 425934b1f470a646a4ca64fc63eeb823d4c5c12698eJames Lemieux .appendPath("attachments") 426934b1f470a646a4ca64fc63eeb823d4c5c12698eJames Lemieux .appendPath(segments.get(1)) 427934b1f470a646a4ca64fc63eeb823d4c5c12698eJames Lemieux .appendPath(segments.get(2)) 428934b1f470a646a4ca64fc63eeb823d4c5c12698eJames Lemieux .build(); 429934b1f470a646a4ca64fc63eeb823d4c5c12698eJames Lemieux } 430934b1f470a646a4ca64fc63eeb823d4c5c12698eJames Lemieux 431934b1f470a646a4ca64fc63eeb823d4c5c12698eJames Lemieux /** 432934b1f470a646a4ca64fc63eeb823d4c5c12698eJames Lemieux * Returns an attachment list uri for an eml file at the given uri with the given message id. 4337434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein */ 4347434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein public static Uri getAttachmentsListUri(Uri emlFileUri, String messageId) { 435934b1f470a646a4ca64fc63eeb823d4c5c12698eJames Lemieux return BASE_URI.buildUpon() 436934b1f470a646a4ca64fc63eeb823d4c5c12698eJames Lemieux .appendPath("attachments") 437934b1f470a646a4ca64fc63eeb823d4c5c12698eJames Lemieux .appendPath(Integer.toString(emlFileUri.hashCode())) 438934b1f470a646a4ca64fc63eeb823d4c5c12698eJames Lemieux .appendPath(messageId) 439934b1f470a646a4ca64fc63eeb823d4c5c12698eJames Lemieux .build(); 4407434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein } 4417434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein 4427434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein /** 443934b1f470a646a4ca64fc63eeb823d4c5c12698eJames Lemieux * Returns an attachment uri for an eml file at the given uri with the given message id. 444934b1f470a646a4ca64fc63eeb823d4c5c12698eJames Lemieux * The consumer of this uri must append a specific CID to it to complete the uri. 4457434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein */ 446934b1f470a646a4ca64fc63eeb823d4c5c12698eJames Lemieux public static Uri getAttachmentByCidUri(Uri emlFileUri, String messageId) { 4477434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein return BASE_URI.buildUpon() 448934b1f470a646a4ca64fc63eeb823d4c5c12698eJames Lemieux .appendPath("attachmentByCid") 449934b1f470a646a4ca64fc63eeb823d4c5c12698eJames Lemieux .appendPath(Integer.toString(emlFileUri.hashCode())) 450934b1f470a646a4ca64fc63eeb823d4c5c12698eJames Lemieux .appendPath(messageId) 451934b1f470a646a4ca64fc63eeb823d4c5c12698eJames Lemieux .build(); 4527434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein } 4537434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein 4547434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein /** 4557434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein * Returns an attachment uri for an attachment from the given eml file uri with 4567434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein * the given message id and part id. 4577434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein */ 4587434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein public static Uri getAttachmentUri(Uri emlFileUri, String messageId, String partId) { 459934b1f470a646a4ca64fc63eeb823d4c5c12698eJames Lemieux return BASE_URI.buildUpon() 460934b1f470a646a4ca64fc63eeb823d4c5c12698eJames Lemieux .appendPath("attachment") 461934b1f470a646a4ca64fc63eeb823d4c5c12698eJames Lemieux .appendPath(Integer.toString(emlFileUri.hashCode())) 462934b1f470a646a4ca64fc63eeb823d4c5c12698eJames Lemieux .appendPath(messageId) 463934b1f470a646a4ca64fc63eeb823d4c5c12698eJames Lemieux .appendPath(partId) 464934b1f470a646a4ca64fc63eeb823d4c5c12698eJames Lemieux .build(); 4657434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein } 4667434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein 4677434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein /** 4687434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein * Returns the absolute file path for the attachment at the given uri. 4697434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein */ 4707434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein private String getFilePath(Uri uri) { 4717434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein final Attachment attachment = mUriAttachmentMap.get(uri); 4727434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein final boolean saveToSd = 4737434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein attachment.destination == UIProvider.AttachmentDestination.EXTERNAL; 4747434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein final String pathStart = (saveToSd) ? 4757434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein Environment.getExternalStoragePublicDirectory( 4767434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein Environment.DIRECTORY_DOWNLOADS).getAbsolutePath() : getCacheDir(); 4777434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein 4787434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein // we want the root of the downloads directory if the attachment is 4797434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein // saved to external (or we're saving to external) 4807434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein final String directoryPath = (saveToSd) ? pathStart : pathStart + uri.getEncodedPath(); 4817434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein 4827434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein final File directory = new File(directoryPath); 4837434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein if (!directory.exists()) { 4847434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein directory.mkdirs(); 4857434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein } 4867434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein return directoryPath + "/" + attachment.getName(); 4877434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein } 4887434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein 4897434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein /** 4907434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein * Returns the root directory for the attachments for the specific uri. 4917434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein */ 4927434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein private String getCacheFileDirectory(Uri uri) { 493934b1f470a646a4ca64fc63eeb823d4c5c12698eJames Lemieux return getCacheDir() + "/" + Uri.encode(uri.getPathSegments().get(1)); 4947434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein } 4957434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein 4967434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein /** 4977434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein * Returns the cache directory for eml attachment files. 4987434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein */ 4997434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein private String getCacheDir() { 5007434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein return getContext().getCacheDir().getAbsolutePath().concat("/eml"); 5017434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein } 5027434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein 5037434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein /** 5047434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein * Recursively delete the directory at the passed file path. 5057434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein */ 5067434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein private void deleteDirectory(String cacheFileDirectory) { 5077434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein recursiveDelete(new File(cacheFileDirectory)); 5087434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein } 5097434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein 5107434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein /** 5117434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein * Recursively deletes a file or directory. 5127434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein */ 5137434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein private void recursiveDelete(File file) { 5147434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein if (file.isDirectory()) { 5157434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein final File[] children = file.listFiles(); 5167434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein for (final File child : children) { 5177434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein recursiveDelete(child); 5187434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein } 5197434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein } 5207434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein 5217434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein file.delete(); 5227434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein } 5237434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein} 524