196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project/* 296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * Copyright (C) 2008 The Android Open Source Project 396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * 496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); 596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * you may not use this file except in compliance with the License. 696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * You may obtain a copy of the License at 796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * 896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * 1096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * Unless required by applicable law or agreed to in writing, software 1196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, 1296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * See the License for the specific language governing permissions and 1496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * limitations under the License. 1596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project */ 1696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 1796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Projectpackage com.android.email.provider; 1896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 199ef6f645f57d869a600113f555389b5d5e368c21Mihai Predaimport com.android.email.Email; 20c0033f24a26a08c47aa38d957f42cf63cfa3c345Andrew Stadlerimport com.android.email.mail.internet.MimeUtility; 213d25a519abf676f050b546d34401a277aea5de40Andrew Stadlerimport com.android.email.provider.EmailContent.Attachment; 223d25a519abf676f050b546d34401a277aea5de40Andrew Stadlerimport com.android.email.provider.EmailContent.AttachmentColumns; 2371754d3f940fe82e251c274e3e56781e702cfd6fAndrew Stadlerimport com.android.email.provider.EmailContent.Message; 2471754d3f940fe82e251c274e3e56781e702cfd6fAndrew Stadlerimport com.android.email.provider.EmailContent.MessageColumns; 2596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 2696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Projectimport android.content.ContentProvider; 277436601fae756e8bc1f916560a1c2d1f8ce576fcMihai Predaimport android.content.ContentResolver; 283d25a519abf676f050b546d34401a277aea5de40Andrew Stadlerimport android.content.ContentUris; 2996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Projectimport android.content.ContentValues; 30a98de7e55e91229c35352b496fad3fbb108a9609Andrew Stadlerimport android.content.Context; 3196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Projectimport android.database.Cursor; 3296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Projectimport android.database.MatrixCursor; 3396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Projectimport android.graphics.Bitmap; 3496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Projectimport android.graphics.BitmapFactory; 3596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Projectimport android.net.Uri; 3696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Projectimport android.os.ParcelFileDescriptor; 3780ebde2897dced46a0f24efb7c15a997b660a8feAndrew Stadlerimport android.text.TextUtils; 3880ebde2897dced46a0f24efb7c15a997b660a8feAndrew Stadlerimport android.webkit.MimeTypeMap; 3996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 40c0033f24a26a08c47aa38d957f42cf63cfa3c345Andrew Stadlerimport java.io.File; 41c0033f24a26a08c47aa38d957f42cf63cfa3c345Andrew Stadlerimport java.io.FileNotFoundException; 42c0033f24a26a08c47aa38d957f42cf63cfa3c345Andrew Stadlerimport java.io.FileOutputStream; 43c0033f24a26a08c47aa38d957f42cf63cfa3c345Andrew Stadlerimport java.io.IOException; 44c0033f24a26a08c47aa38d957f42cf63cfa3c345Andrew Stadlerimport java.io.InputStream; 45c0033f24a26a08c47aa38d957f42cf63cfa3c345Andrew Stadlerimport java.util.List; 4696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 4796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project/* 4896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * A simple ContentProvider that allows file access to Email's attachments. 493d25a519abf676f050b546d34401a277aea5de40Andrew Stadler * 503d25a519abf676f050b546d34401a277aea5de40Andrew Stadler * The URI scheme is as follows. For raw file access: 513d25a519abf676f050b546d34401a277aea5de40Andrew Stadler * content://com.android.email.attachmentprovider/acct#/attach#/RAW 523d25a519abf676f050b546d34401a277aea5de40Andrew Stadler * 533d25a519abf676f050b546d34401a277aea5de40Andrew Stadler * And for access to thumbnails: 543d25a519abf676f050b546d34401a277aea5de40Andrew Stadler * content://com.android.email.attachmentprovider/acct#/attach#/THUMBNAIL/width#/height# 55a98de7e55e91229c35352b496fad3fbb108a9609Andrew Stadler * 56a98de7e55e91229c35352b496fad3fbb108a9609Andrew Stadler * The on-disk (storage) schema is as follows. 57a98de7e55e91229c35352b496fad3fbb108a9609Andrew Stadler * 58a98de7e55e91229c35352b496fad3fbb108a9609Andrew Stadler * Attachments are stored at: <database-path>/account#.db_att/item# 59a98de7e55e91229c35352b496fad3fbb108a9609Andrew Stadler * Thumbnails are stored at: <cache-path>/thmb_account#_item# 60a98de7e55e91229c35352b496fad3fbb108a9609Andrew Stadler * 61a98de7e55e91229c35352b496fad3fbb108a9609Andrew Stadler * Using the standard application context, account #10 and attachment # 20, this would be: 62a98de7e55e91229c35352b496fad3fbb108a9609Andrew Stadler * /data/data/com.android.email/databases/10.db_att/20 63a98de7e55e91229c35352b496fad3fbb108a9609Andrew Stadler * /data/data/com.android.email/cache/thmb_10_20 6496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project */ 6596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Projectpublic class AttachmentProvider extends ContentProvider { 66301ac18bb7f211b473c4f6fa6ec9bb276bbc6c10Andrew Stadler 67301ac18bb7f211b473c4f6fa6ec9bb276bbc6c10Andrew Stadler public static final String AUTHORITY = "com.android.email.attachmentprovider"; 68301ac18bb7f211b473c4f6fa6ec9bb276bbc6c10Andrew Stadler public static final Uri CONTENT_URI = Uri.parse( "content://" + AUTHORITY); 6996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 7096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project private static final String FORMAT_RAW = "RAW"; 7196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project private static final String FORMAT_THUMBNAIL = "THUMBNAIL"; 7296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 7396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public static class AttachmentProviderColumns { 7496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public static final String _ID = "_id"; 7596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public static final String DATA = "_data"; 7696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public static final String DISPLAY_NAME = "_display_name"; 7796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public static final String SIZE = "_size"; 7896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 7996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 8080ebde2897dced46a0f24efb7c15a997b660a8feAndrew Stadler private static final String[] MIME_TYPE_PROJECTION = new String[] { 8180ebde2897dced46a0f24efb7c15a997b660a8feAndrew Stadler AttachmentColumns.MIME_TYPE, AttachmentColumns.FILENAME }; 8280ebde2897dced46a0f24efb7c15a997b660a8feAndrew Stadler private static final int MIME_TYPE_COLUMN_MIME_TYPE = 0; 8380ebde2897dced46a0f24efb7c15a997b660a8feAndrew Stadler private static final int MIME_TYPE_COLUMN_FILENAME = 1; 8480ebde2897dced46a0f24efb7c15a997b660a8feAndrew Stadler 8580ebde2897dced46a0f24efb7c15a997b660a8feAndrew Stadler private static final String[] PROJECTION_QUERY = new String[] { AttachmentColumns.FILENAME, 863d25a519abf676f050b546d34401a277aea5de40Andrew Stadler AttachmentColumns.SIZE, AttachmentColumns.CONTENT_URI }; 873d25a519abf676f050b546d34401a277aea5de40Andrew Stadler 883d25a519abf676f050b546d34401a277aea5de40Andrew Stadler public static Uri getAttachmentUri(long accountId, long id) { 8996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return CONTENT_URI.buildUpon() 903d25a519abf676f050b546d34401a277aea5de40Andrew Stadler .appendPath(Long.toString(accountId)) 9196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project .appendPath(Long.toString(id)) 9296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project .appendPath(FORMAT_RAW) 9396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project .build(); 9496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 9596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 96a98de7e55e91229c35352b496fad3fbb108a9609Andrew Stadler public static Uri getAttachmentThumbnailUri(long accountId, long id, 97c0033f24a26a08c47aa38d957f42cf63cfa3c345Andrew Stadler int width, int height) { 9896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return CONTENT_URI.buildUpon() 99a98de7e55e91229c35352b496fad3fbb108a9609Andrew Stadler .appendPath(Long.toString(accountId)) 10096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project .appendPath(Long.toString(id)) 10196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project .appendPath(FORMAT_THUMBNAIL) 10296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project .appendPath(Integer.toString(width)) 10396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project .appendPath(Integer.toString(height)) 10496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project .build(); 10596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 10696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 107a98de7e55e91229c35352b496fad3fbb108a9609Andrew Stadler /** 108a98de7e55e91229c35352b496fad3fbb108a9609Andrew Stadler * Return the filename for a given attachment. This should be used by any code that is 109a98de7e55e91229c35352b496fad3fbb108a9609Andrew Stadler * going to *write* attachments. 110a98de7e55e91229c35352b496fad3fbb108a9609Andrew Stadler * 111a98de7e55e91229c35352b496fad3fbb108a9609Andrew Stadler * This does not create or write the file, or even the directories. It simply builds 112a98de7e55e91229c35352b496fad3fbb108a9609Andrew Stadler * the filename that should be used. 113a98de7e55e91229c35352b496fad3fbb108a9609Andrew Stadler */ 114a98de7e55e91229c35352b496fad3fbb108a9609Andrew Stadler public static File getAttachmentFilename(Context context, long accountId, long attachmentId) { 1153f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadler return new File(getAttachmentDirectory(context, accountId), Long.toString(attachmentId)); 1163f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadler } 1173f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadler 1183f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadler /** 1193f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadler * Return the directory for a given attachment. This should be used by any code that is 1203f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadler * going to *write* attachments. 1213f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadler * 1223f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadler * This does not create or write the directory. It simply builds the pathname that should be 1233f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadler * used. 1243f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadler */ 1253f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadler public static File getAttachmentDirectory(Context context, long accountId) { 1263f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadler return context.getDatabasePath(accountId + ".db_att"); 127a98de7e55e91229c35352b496fad3fbb108a9609Andrew Stadler } 128a98de7e55e91229c35352b496fad3fbb108a9609Andrew Stadler 12996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project @Override 13096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public boolean onCreate() { 13196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project /* 13296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * We use the cache dir as a temporary directory (since Android doesn't give us one) so 13396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * on startup we'll clean up any .tmp files from the last run. 13496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project */ 13596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project File[] files = getContext().getCacheDir().listFiles(); 13696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project for (File file : files) { 137aeeefedb43c40e887850654ac88270755f5631c1Mihai Preda String filename = file.getName(); 138aeeefedb43c40e887850654ac88270755f5631c1Mihai Preda if (filename.endsWith(".tmp") || filename.startsWith("thmb_")) { 13996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project file.delete(); 14096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 14196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 14296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return true; 14396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 14496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 145301ac18bb7f211b473c4f6fa6ec9bb276bbc6c10Andrew Stadler /** 146301ac18bb7f211b473c4f6fa6ec9bb276bbc6c10Andrew Stadler * Returns the mime type for a given attachment. There are three possible results: 147301ac18bb7f211b473c4f6fa6ec9bb276bbc6c10Andrew Stadler * - If thumbnail Uri, always returns "image/png" (even if there's no attachment) 148301ac18bb7f211b473c4f6fa6ec9bb276bbc6c10Andrew Stadler * - If the attachment does not exist, returns null 149301ac18bb7f211b473c4f6fa6ec9bb276bbc6c10Andrew Stadler * - Returns the mime type of the attachment 150301ac18bb7f211b473c4f6fa6ec9bb276bbc6c10Andrew Stadler */ 15196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project @Override 15296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public String getType(Uri uri) { 15396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project List<String> segments = uri.getPathSegments(); 1543d25a519abf676f050b546d34401a277aea5de40Andrew Stadler String accountId = segments.get(0); 15596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project String id = segments.get(1); 15696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project String format = segments.get(2); 15796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (FORMAT_THUMBNAIL.equals(format)) { 15896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return "image/png"; 1593d25a519abf676f050b546d34401a277aea5de40Andrew Stadler } else { 1603d25a519abf676f050b546d34401a277aea5de40Andrew Stadler uri = ContentUris.withAppendedId(Attachment.CONTENT_URI, Long.parseLong(id)); 16180ebde2897dced46a0f24efb7c15a997b660a8feAndrew Stadler Cursor c = getContext().getContentResolver().query(uri, MIME_TYPE_PROJECTION, 1623d25a519abf676f050b546d34401a277aea5de40Andrew Stadler null, null, null); 16396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project try { 1643d25a519abf676f050b546d34401a277aea5de40Andrew Stadler if (c.moveToFirst()) { 16580ebde2897dced46a0f24efb7c15a997b660a8feAndrew Stadler String mimeType = c.getString(MIME_TYPE_COLUMN_MIME_TYPE); 16680ebde2897dced46a0f24efb7c15a997b660a8feAndrew Stadler String fileName = c.getString(MIME_TYPE_COLUMN_FILENAME); 16780ebde2897dced46a0f24efb7c15a997b660a8feAndrew Stadler mimeType = inferMimeType(fileName, mimeType); 16880ebde2897dced46a0f24efb7c15a997b660a8feAndrew Stadler return mimeType; 16996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 1703d25a519abf676f050b546d34401a277aea5de40Andrew Stadler } finally { 1713d25a519abf676f050b546d34401a277aea5de40Andrew Stadler c.close(); 17296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 1733d25a519abf676f050b546d34401a277aea5de40Andrew Stadler return null; 17496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 17596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 17696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 177301ac18bb7f211b473c4f6fa6ec9bb276bbc6c10Andrew Stadler /** 17880ebde2897dced46a0f24efb7c15a997b660a8feAndrew Stadler * Helper to convert unknown or unmapped attachments to something useful based on filename 17980ebde2897dced46a0f24efb7c15a997b660a8feAndrew Stadler * extensions. Imperfect, but helps. 18080ebde2897dced46a0f24efb7c15a997b660a8feAndrew Stadler * 18180ebde2897dced46a0f24efb7c15a997b660a8feAndrew Stadler * If the given mime type is non-empty and anything other than "application/octet-stream", 18280ebde2897dced46a0f24efb7c15a997b660a8feAndrew Stadler * just return it. (This is the most common case.) 18380ebde2897dced46a0f24efb7c15a997b660a8feAndrew Stadler * If the filename has a recognizable extension and it converts to a mime type, return that. 18480ebde2897dced46a0f24efb7c15a997b660a8feAndrew Stadler * If the filename has an unrecognized extension, return "application/extension" 18580ebde2897dced46a0f24efb7c15a997b660a8feAndrew Stadler * Otherwise return "application/octet-stream". 18680ebde2897dced46a0f24efb7c15a997b660a8feAndrew Stadler * 18780ebde2897dced46a0f24efb7c15a997b660a8feAndrew Stadler * @param fileName The given filename 18880ebde2897dced46a0f24efb7c15a997b660a8feAndrew Stadler * @param mimeType The given mime type 18980ebde2897dced46a0f24efb7c15a997b660a8feAndrew Stadler * @return A likely mime type for the attachment 19080ebde2897dced46a0f24efb7c15a997b660a8feAndrew Stadler */ 19180ebde2897dced46a0f24efb7c15a997b660a8feAndrew Stadler public static String inferMimeType(String fileName, String mimeType) { 19280ebde2897dced46a0f24efb7c15a997b660a8feAndrew Stadler // If the given mime type appears to be non-empty and non-generic - return it 19380ebde2897dced46a0f24efb7c15a997b660a8feAndrew Stadler if (!TextUtils.isEmpty(mimeType) && 19480ebde2897dced46a0f24efb7c15a997b660a8feAndrew Stadler !"application/octet-stream".equalsIgnoreCase(mimeType)) { 19580ebde2897dced46a0f24efb7c15a997b660a8feAndrew Stadler return mimeType; 19680ebde2897dced46a0f24efb7c15a997b660a8feAndrew Stadler } 19780ebde2897dced46a0f24efb7c15a997b660a8feAndrew Stadler 19880ebde2897dced46a0f24efb7c15a997b660a8feAndrew Stadler // Try to find an extension in the filename 19980ebde2897dced46a0f24efb7c15a997b660a8feAndrew Stadler if (!TextUtils.isEmpty(fileName)) { 20080ebde2897dced46a0f24efb7c15a997b660a8feAndrew Stadler int lastDot = fileName.lastIndexOf('.'); 20180ebde2897dced46a0f24efb7c15a997b660a8feAndrew Stadler String extension = null; 20280ebde2897dced46a0f24efb7c15a997b660a8feAndrew Stadler if ((lastDot > 0) && (lastDot < fileName.length() - 1)) { 20380ebde2897dced46a0f24efb7c15a997b660a8feAndrew Stadler extension = fileName.substring(lastDot + 1).toLowerCase(); 20480ebde2897dced46a0f24efb7c15a997b660a8feAndrew Stadler } 20580ebde2897dced46a0f24efb7c15a997b660a8feAndrew Stadler if (!TextUtils.isEmpty(extension)) { 20680ebde2897dced46a0f24efb7c15a997b660a8feAndrew Stadler // Extension found. Look up mime type, or synthesize if none found. 20780ebde2897dced46a0f24efb7c15a997b660a8feAndrew Stadler mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension); 20880ebde2897dced46a0f24efb7c15a997b660a8feAndrew Stadler if (mimeType == null) { 20980ebde2897dced46a0f24efb7c15a997b660a8feAndrew Stadler mimeType = "application/" + extension; 21080ebde2897dced46a0f24efb7c15a997b660a8feAndrew Stadler } 21180ebde2897dced46a0f24efb7c15a997b660a8feAndrew Stadler return mimeType; 21280ebde2897dced46a0f24efb7c15a997b660a8feAndrew Stadler } 21380ebde2897dced46a0f24efb7c15a997b660a8feAndrew Stadler } 21480ebde2897dced46a0f24efb7c15a997b660a8feAndrew Stadler 21580ebde2897dced46a0f24efb7c15a997b660a8feAndrew Stadler // Fallback case - no good guess could be made. 21680ebde2897dced46a0f24efb7c15a997b660a8feAndrew Stadler return "application/octet-stream"; 21780ebde2897dced46a0f24efb7c15a997b660a8feAndrew Stadler } 21880ebde2897dced46a0f24efb7c15a997b660a8feAndrew Stadler 21980ebde2897dced46a0f24efb7c15a997b660a8feAndrew Stadler /** 220301ac18bb7f211b473c4f6fa6ec9bb276bbc6c10Andrew Stadler * Open an attachment file. There are two "modes" - "raw", which returns an actual file, 221301ac18bb7f211b473c4f6fa6ec9bb276bbc6c10Andrew Stadler * and "thumbnail", which attempts to generate a thumbnail image. 222301ac18bb7f211b473c4f6fa6ec9bb276bbc6c10Andrew Stadler * 223301ac18bb7f211b473c4f6fa6ec9bb276bbc6c10Andrew Stadler * Thumbnails are cached for easy space recovery and cleanup. 224301ac18bb7f211b473c4f6fa6ec9bb276bbc6c10Andrew Stadler * 225301ac18bb7f211b473c4f6fa6ec9bb276bbc6c10Andrew Stadler * TODO: The thumbnail mode returns null for its failure cases, instead of throwing 226301ac18bb7f211b473c4f6fa6ec9bb276bbc6c10Andrew Stadler * FileNotFoundException, and should be fixed for consistency. 227301ac18bb7f211b473c4f6fa6ec9bb276bbc6c10Andrew Stadler * 228301ac18bb7f211b473c4f6fa6ec9bb276bbc6c10Andrew Stadler * @throws FileNotFoundException 229301ac18bb7f211b473c4f6fa6ec9bb276bbc6c10Andrew Stadler */ 23096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project @Override 23196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException { 23296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project List<String> segments = uri.getPathSegments(); 2333d25a519abf676f050b546d34401a277aea5de40Andrew Stadler String accountId = segments.get(0); 23496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project String id = segments.get(1); 23596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project String format = segments.get(2); 23696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (FORMAT_THUMBNAIL.equals(format)) { 23796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project int width = Integer.parseInt(segments.get(3)); 23896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project int height = Integer.parseInt(segments.get(4)); 2393d25a519abf676f050b546d34401a277aea5de40Andrew Stadler String filename = "thmb_" + accountId + "_" + id; 24096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project File dir = getContext().getCacheDir(); 24196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project File file = new File(dir, filename); 24296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (!file.exists()) { 2433d25a519abf676f050b546d34401a277aea5de40Andrew Stadler Uri attachmentUri = getAttachmentUri(Long.parseLong(accountId), Long.parseLong(id)); 2445182d80674a1ef90586f52355a21a82e8265c10aMihai Preda Cursor c = query(attachmentUri, 2455182d80674a1ef90586f52355a21a82e8265c10aMihai Preda new String[] { AttachmentProviderColumns.DATA }, null, null, null); 2465182d80674a1ef90586f52355a21a82e8265c10aMihai Preda if (c != null) { 2475182d80674a1ef90586f52355a21a82e8265c10aMihai Preda try { 2485182d80674a1ef90586f52355a21a82e8265c10aMihai Preda if (c.moveToFirst()) { 2495182d80674a1ef90586f52355a21a82e8265c10aMihai Preda attachmentUri = Uri.parse(c.getString(0)); 2503d25a519abf676f050b546d34401a277aea5de40Andrew Stadler } else { 2513d25a519abf676f050b546d34401a277aea5de40Andrew Stadler return null; 2525182d80674a1ef90586f52355a21a82e8265c10aMihai Preda } 2535182d80674a1ef90586f52355a21a82e8265c10aMihai Preda } finally { 2545182d80674a1ef90586f52355a21a82e8265c10aMihai Preda c.close(); 2555182d80674a1ef90586f52355a21a82e8265c10aMihai Preda } 2565182d80674a1ef90586f52355a21a82e8265c10aMihai Preda } 2575182d80674a1ef90586f52355a21a82e8265c10aMihai Preda String type = getContext().getContentResolver().getType(attachmentUri); 25896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project try { 2595182d80674a1ef90586f52355a21a82e8265c10aMihai Preda InputStream in = 2605182d80674a1ef90586f52355a21a82e8265c10aMihai Preda getContext().getContentResolver().openInputStream(attachmentUri); 26196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project Bitmap thumbnail = createThumbnail(type, in); 2625182d80674a1ef90586f52355a21a82e8265c10aMihai Preda thumbnail = Bitmap.createScaledBitmap(thumbnail, width, height, true); 26396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project FileOutputStream out = new FileOutputStream(file); 26496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project thumbnail.compress(Bitmap.CompressFormat.PNG, 100, out); 26596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project out.close(); 26696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project in.close(); 26796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 26896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project catch (IOException ioe) { 26996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return null; 27096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 27196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 27296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY); 27396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 27496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project else { 27596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return ParcelFileDescriptor.open( 2763d25a519abf676f050b546d34401a277aea5de40Andrew Stadler new File(getContext().getDatabasePath(accountId + ".db_att"), id), 27796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project ParcelFileDescriptor.MODE_READ_ONLY); 27896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 27996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 28096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 28196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project @Override 28296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public int delete(Uri uri, String arg1, String[] arg2) { 28396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return 0; 28496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 28596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 28696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project @Override 28796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public Uri insert(Uri uri, ContentValues values) { 28896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return null; 28996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 29096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 291301ac18bb7f211b473c4f6fa6ec9bb276bbc6c10Andrew Stadler /** 292301ac18bb7f211b473c4f6fa6ec9bb276bbc6c10Andrew Stadler * Returns a cursor based on the data in the attachments table, or null if the attachment 293301ac18bb7f211b473c4f6fa6ec9bb276bbc6c10Andrew Stadler * is not recorded in the table. 294301ac18bb7f211b473c4f6fa6ec9bb276bbc6c10Andrew Stadler * 295301ac18bb7f211b473c4f6fa6ec9bb276bbc6c10Andrew Stadler * Supports REST Uri only, for a single row - selection, selection args, and sortOrder are 296301ac18bb7f211b473c4f6fa6ec9bb276bbc6c10Andrew Stadler * ignored (non-null values should probably throw an exception....) 297301ac18bb7f211b473c4f6fa6ec9bb276bbc6c10Andrew Stadler */ 29896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project @Override 29996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, 30096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project String sortOrder) { 30196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (projection == null) { 30296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project projection = 30396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project new String[] { 30496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project AttachmentProviderColumns._ID, 30596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project AttachmentProviderColumns.DATA, 30696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project }; 30796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 30896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 30996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project List<String> segments = uri.getPathSegments(); 3103d25a519abf676f050b546d34401a277aea5de40Andrew Stadler String accountId = segments.get(0); 31196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project String id = segments.get(1); 31296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project String format = segments.get(2); 31396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project String name = null; 31496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project int size = -1; 3155182d80674a1ef90586f52355a21a82e8265c10aMihai Preda String contentUri = null; 3163d25a519abf676f050b546d34401a277aea5de40Andrew Stadler 3173d25a519abf676f050b546d34401a277aea5de40Andrew Stadler uri = ContentUris.withAppendedId(Attachment.CONTENT_URI, Long.parseLong(id)); 3183d25a519abf676f050b546d34401a277aea5de40Andrew Stadler Cursor c = getContext().getContentResolver().query(uri, PROJECTION_QUERY, 3193d25a519abf676f050b546d34401a277aea5de40Andrew Stadler null, null, null); 32096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project try { 3213d25a519abf676f050b546d34401a277aea5de40Andrew Stadler if (c.moveToFirst()) { 3223d25a519abf676f050b546d34401a277aea5de40Andrew Stadler name = c.getString(0); 3233d25a519abf676f050b546d34401a277aea5de40Andrew Stadler size = c.getInt(1); 3243d25a519abf676f050b546d34401a277aea5de40Andrew Stadler contentUri = c.getString(2); 3253d25a519abf676f050b546d34401a277aea5de40Andrew Stadler } else { 32696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return null; 32796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 3283d25a519abf676f050b546d34401a277aea5de40Andrew Stadler } finally { 3293d25a519abf676f050b546d34401a277aea5de40Andrew Stadler c.close(); 33096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 33196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 33296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project MatrixCursor ret = new MatrixCursor(projection); 33396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project Object[] values = new Object[projection.length]; 33496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project for (int i = 0, count = projection.length; i < count; i++) { 33596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project String column = projection[i]; 33696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if (AttachmentProviderColumns._ID.equals(column)) { 33796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project values[i] = id; 33896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 33996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project else if (AttachmentProviderColumns.DATA.equals(column)) { 3405182d80674a1ef90586f52355a21a82e8265c10aMihai Preda values[i] = contentUri; 34196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 34296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project else if (AttachmentProviderColumns.DISPLAY_NAME.equals(column)) { 34396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project values[i] = name; 34496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 34596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project else if (AttachmentProviderColumns.SIZE.equals(column)) { 34696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project values[i] = size; 34796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 34896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 34996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project ret.addRow(values); 35096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return ret; 35196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 35296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 35396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project @Override 35496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { 35596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return 0; 35696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 35796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 35896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project private Bitmap createThumbnail(String type, InputStream data) { 35996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project if(MimeUtility.mimeTypeMatches(type, "image/*")) { 36096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return createImageThumbnail(data); 36196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 36296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return null; 36396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 36496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project 36596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project private Bitmap createImageThumbnail(InputStream data) { 36696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project try { 36796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project Bitmap bitmap = BitmapFactory.decodeStream(data); 36896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return bitmap; 36996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 37096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project catch (OutOfMemoryError oome) { 37196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project /* 37296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * Improperly downloaded images, corrupt bitmaps and the like can commonly 37396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * cause OOME due to invalid allocation sizes. We're happy with a null bitmap in 37496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * that case. If the system is really out of memory we'll know about it soon 37596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * enough. 37696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project */ 37796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return null; 37896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 37996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project catch (Exception e) { 38096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project return null; 38196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 38296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project } 3837436601fae756e8bc1f916560a1c2d1f8ce576fcMihai Preda /** 384301ac18bb7f211b473c4f6fa6ec9bb276bbc6c10Andrew Stadler * Resolve attachment id to content URI. Returns the resolved content URI (from the attachment 385301ac18bb7f211b473c4f6fa6ec9bb276bbc6c10Andrew Stadler * DB) or, if not found, simply returns the incoming value. 3867436601fae756e8bc1f916560a1c2d1f8ce576fcMihai Preda * 3877436601fae756e8bc1f916560a1c2d1f8ce576fcMihai Preda * @param attachmentUri 3887436601fae756e8bc1f916560a1c2d1f8ce576fcMihai Preda * @return resolved content URI 389301ac18bb7f211b473c4f6fa6ec9bb276bbc6c10Andrew Stadler * 390301ac18bb7f211b473c4f6fa6ec9bb276bbc6c10Andrew Stadler * TODO: Throws an SQLite exception on a missing DB file (e.g. unknown URI) instead of just 391301ac18bb7f211b473c4f6fa6ec9bb276bbc6c10Andrew Stadler * returning the incoming uri, as it should. 3927436601fae756e8bc1f916560a1c2d1f8ce576fcMihai Preda */ 3937436601fae756e8bc1f916560a1c2d1f8ce576fcMihai Preda public static Uri resolveAttachmentIdToContentUri(ContentResolver resolver, Uri attachmentUri) { 3947436601fae756e8bc1f916560a1c2d1f8ce576fcMihai Preda Cursor c = resolver.query(attachmentUri, 3957436601fae756e8bc1f916560a1c2d1f8ce576fcMihai Preda new String[] { AttachmentProvider.AttachmentProviderColumns.DATA }, 3967436601fae756e8bc1f916560a1c2d1f8ce576fcMihai Preda null, null, null); 3977436601fae756e8bc1f916560a1c2d1f8ce576fcMihai Preda if (c != null) { 3987436601fae756e8bc1f916560a1c2d1f8ce576fcMihai Preda try { 3997436601fae756e8bc1f916560a1c2d1f8ce576fcMihai Preda if (c.moveToFirst()) { 4009ef6f645f57d869a600113f555389b5d5e368c21Mihai Preda final String strUri = c.getString(0); 4019ef6f645f57d869a600113f555389b5d5e368c21Mihai Preda if (strUri != null) { 4029ef6f645f57d869a600113f555389b5d5e368c21Mihai Preda return Uri.parse(strUri); 4039ef6f645f57d869a600113f555389b5d5e368c21Mihai Preda } else { 4049ef6f645f57d869a600113f555389b5d5e368c21Mihai Preda Email.log("AttachmentProvider: attachment with null contentUri"); 4059ef6f645f57d869a600113f555389b5d5e368c21Mihai Preda } 4067436601fae756e8bc1f916560a1c2d1f8ce576fcMihai Preda } 4077436601fae756e8bc1f916560a1c2d1f8ce576fcMihai Preda } finally { 4087436601fae756e8bc1f916560a1c2d1f8ce576fcMihai Preda c.close(); 4097436601fae756e8bc1f916560a1c2d1f8ce576fcMihai Preda } 4107436601fae756e8bc1f916560a1c2d1f8ce576fcMihai Preda } 4117436601fae756e8bc1f916560a1c2d1f8ce576fcMihai Preda return attachmentUri; 4127436601fae756e8bc1f916560a1c2d1f8ce576fcMihai Preda } 4134b41bae270ea4c49ec8403084db43ee9b37cdda4Andrew Stadler 4144b41bae270ea4c49ec8403084db43ee9b37cdda4Andrew Stadler /** 4154b41bae270ea4c49ec8403084db43ee9b37cdda4Andrew Stadler * In support of deleting a message, find all attachments and delete associated attachment 4164b41bae270ea4c49ec8403084db43ee9b37cdda4Andrew Stadler * files. 4174b41bae270ea4c49ec8403084db43ee9b37cdda4Andrew Stadler * @param context 4184b41bae270ea4c49ec8403084db43ee9b37cdda4Andrew Stadler * @param accountId the account for the message 4194b41bae270ea4c49ec8403084db43ee9b37cdda4Andrew Stadler * @param messageId the message 4204b41bae270ea4c49ec8403084db43ee9b37cdda4Andrew Stadler */ 4214b41bae270ea4c49ec8403084db43ee9b37cdda4Andrew Stadler public static void deleteAllAttachmentFiles(Context context, long accountId, long messageId) { 4224b41bae270ea4c49ec8403084db43ee9b37cdda4Andrew Stadler Uri uri = ContentUris.withAppendedId(Attachment.MESSAGE_ID_URI, messageId); 4234b41bae270ea4c49ec8403084db43ee9b37cdda4Andrew Stadler Cursor c = context.getContentResolver().query(uri, Attachment.ID_PROJECTION, 4244b41bae270ea4c49ec8403084db43ee9b37cdda4Andrew Stadler null, null, null); 4254b41bae270ea4c49ec8403084db43ee9b37cdda4Andrew Stadler try { 4264b41bae270ea4c49ec8403084db43ee9b37cdda4Andrew Stadler while (c.moveToNext()) { 4274b41bae270ea4c49ec8403084db43ee9b37cdda4Andrew Stadler long attachmentId = c.getLong(Attachment.ID_PROJECTION_COLUMN); 4284b41bae270ea4c49ec8403084db43ee9b37cdda4Andrew Stadler File attachmentFile = getAttachmentFilename(context, accountId, attachmentId); 4294b41bae270ea4c49ec8403084db43ee9b37cdda4Andrew Stadler // Note, delete() throws no exceptions for basic FS errors (e.g. file not found) 4304b41bae270ea4c49ec8403084db43ee9b37cdda4Andrew Stadler // it just returns false, which we ignore, and proceed to the next file. 4314b41bae270ea4c49ec8403084db43ee9b37cdda4Andrew Stadler // This entire loop is best-effort only. 4324b41bae270ea4c49ec8403084db43ee9b37cdda4Andrew Stadler attachmentFile.delete(); 4334b41bae270ea4c49ec8403084db43ee9b37cdda4Andrew Stadler } 4344b41bae270ea4c49ec8403084db43ee9b37cdda4Andrew Stadler } finally { 4354b41bae270ea4c49ec8403084db43ee9b37cdda4Andrew Stadler c.close(); 4364b41bae270ea4c49ec8403084db43ee9b37cdda4Andrew Stadler } 4374b41bae270ea4c49ec8403084db43ee9b37cdda4Andrew Stadler } 43871754d3f940fe82e251c274e3e56781e702cfd6fAndrew Stadler 43971754d3f940fe82e251c274e3e56781e702cfd6fAndrew Stadler /** 44071754d3f940fe82e251c274e3e56781e702cfd6fAndrew Stadler * In support of deleting a mailbox, find all messages and delete their attachments. 44171754d3f940fe82e251c274e3e56781e702cfd6fAndrew Stadler * 44271754d3f940fe82e251c274e3e56781e702cfd6fAndrew Stadler * @param context 44371754d3f940fe82e251c274e3e56781e702cfd6fAndrew Stadler * @param accountId the account for the mailbox 44471754d3f940fe82e251c274e3e56781e702cfd6fAndrew Stadler * @param mailboxId the mailbox for the messages 44571754d3f940fe82e251c274e3e56781e702cfd6fAndrew Stadler */ 44671754d3f940fe82e251c274e3e56781e702cfd6fAndrew Stadler public static void deleteAllMailboxAttachmentFiles(Context context, long accountId, 44771754d3f940fe82e251c274e3e56781e702cfd6fAndrew Stadler long mailboxId) { 44871754d3f940fe82e251c274e3e56781e702cfd6fAndrew Stadler Cursor c = context.getContentResolver().query(Message.CONTENT_URI, 44971754d3f940fe82e251c274e3e56781e702cfd6fAndrew Stadler Message.ID_COLUMN_PROJECTION, MessageColumns.MAILBOX_KEY + "=?", 45071754d3f940fe82e251c274e3e56781e702cfd6fAndrew Stadler new String[] { Long.toString(mailboxId) }, null); 45171754d3f940fe82e251c274e3e56781e702cfd6fAndrew Stadler try { 45271754d3f940fe82e251c274e3e56781e702cfd6fAndrew Stadler while (c.moveToNext()) { 45371754d3f940fe82e251c274e3e56781e702cfd6fAndrew Stadler long messageId = c.getLong(Message.ID_PROJECTION_COLUMN); 45471754d3f940fe82e251c274e3e56781e702cfd6fAndrew Stadler deleteAllAttachmentFiles(context, accountId, messageId); 45571754d3f940fe82e251c274e3e56781e702cfd6fAndrew Stadler } 45671754d3f940fe82e251c274e3e56781e702cfd6fAndrew Stadler } finally { 45771754d3f940fe82e251c274e3e56781e702cfd6fAndrew Stadler c.close(); 45871754d3f940fe82e251c274e3e56781e702cfd6fAndrew Stadler } 45971754d3f940fe82e251c274e3e56781e702cfd6fAndrew Stadler } 46096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project} 461