diff --git a/k9mail/build.gradle b/k9mail/build.gradle index c99ed2f0c..66f07b201 100644 --- a/k9mail/build.gradle +++ b/k9mail/build.gradle @@ -17,6 +17,7 @@ dependencies { compile 'com.android.support:support-v13:21.0.2' compile 'net.sourceforge.htmlcleaner:htmlcleaner:2.10' compile 'de.cketti.library.changelog:ckchangelog:1.2.1' + compile 'com.github.bumptech.glide:glide:3.4.0' androidTestCompile 'com.android.support.test:testing-support-lib:0.1' androidTestCompile 'com.android.support.test.espresso:espresso-core:2.0' diff --git a/k9mail/src/main/java/com/fsck/k9/activity/Accounts.java b/k9mail/src/main/java/com/fsck/k9/activity/Accounts.java index f60311eea..0a83aa9ec 100644 --- a/k9mail/src/main/java/com/fsck/k9/activity/Accounts.java +++ b/k9mail/src/main/java/com/fsck/k9/activity/Accounts.java @@ -1284,7 +1284,8 @@ public class Accounts extends K9ListActivity implements OnItemClickListener { new String[] {"HtmlCleaner", "http://htmlcleaner.sourceforge.net/"}, new String[] {"Android-PullToRefresh", "https://github.com/chrisbanes/Android-PullToRefresh"}, new String[] {"ckChangeLog", "https://github.com/cketti/ckChangeLog"}, - new String[] {"HoloColorPicker", "https://github.com/LarsWerkman/HoloColorPicker"} + new String[] {"HoloColorPicker", "https://github.com/LarsWerkman/HoloColorPicker"}, + new String[] {"Glide", "https://github.com/bumptech/glide"} }; private void onAbout() { diff --git a/k9mail/src/main/java/com/fsck/k9/mailstore/LocalFolder.java b/k9mail/src/main/java/com/fsck/k9/mailstore/LocalFolder.java index 1d2b8c3b9..0d90f09a4 100644 --- a/k9mail/src/main/java/com/fsck/k9/mailstore/LocalFolder.java +++ b/k9mail/src/main/java/com/fsck/k9/mailstore/LocalFolder.java @@ -20,7 +20,6 @@ import java.util.Stack; import java.util.UUID; import android.content.ContentValues; -import android.content.Context; import android.content.SharedPreferences; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; @@ -48,7 +47,6 @@ import com.fsck.k9.mail.internet.MimeMessage; import com.fsck.k9.mail.internet.MimeMultipart; import com.fsck.k9.mailstore.LockableDatabase.DbCallback; import com.fsck.k9.mailstore.LockableDatabase.WrappedException; -import com.fsck.k9.provider.AttachmentProvider; import org.apache.james.mime4j.MimeException; import org.apache.james.mime4j.parser.ContentHandler; import org.apache.james.mime4j.parser.MimeStreamParser; @@ -1651,7 +1649,6 @@ public class LocalFolder extends Folder implements Serializable { @Override public Void doDbWork(final SQLiteDatabase db) throws WrappedException, UnavailableStorageException { deleteMessagePartsFromDisk(db, rootMessagePartId); - deleteAttachmentThumbnailsFromDisk(db, rootMessagePartId); return null; } }); @@ -1679,23 +1676,6 @@ public class LocalFolder extends Folder implements Serializable { } } - private void deleteAttachmentThumbnailsFromDisk(SQLiteDatabase db, long rootMessagePartId) { - Context context = localStore.context; - String accountUuid = getAccountUuid(); - - Cursor cursor = db.query("message_parts", new String[] { "id" }, - "root = ? AND type = " + MessagePartType.ATTACHMENT, - new String[] { Long.toString(rootMessagePartId) }, null, null, null); - try { - while (cursor.moveToNext()) { - String messagePartId = cursor.getString(0); - AttachmentProvider.deleteThumbnail(context, accountUuid, messagePartId); - } - } finally { - cursor.close(); - } - } - @Override public boolean isInTopGroup() { return mInTopGroup; diff --git a/k9mail/src/main/java/com/fsck/k9/mailstore/StoreSchemaDefinition.java b/k9mail/src/main/java/com/fsck/k9/mailstore/StoreSchemaDefinition.java index d8be088ee..e57930a65 100644 --- a/k9mail/src/main/java/com/fsck/k9/mailstore/StoreSchemaDefinition.java +++ b/k9mail/src/main/java/com/fsck/k9/mailstore/StoreSchemaDefinition.java @@ -53,8 +53,6 @@ class StoreSchemaDefinition implements LockableDatabase.SchemaDefinition { Log.i(K9.LOG_TAG, String.format(Locale.US, "Upgrading database from version %d to version %d", db.getVersion(), LocalStore.DB_VERSION)); - AttachmentProvider.clear(this.localStore.context); - db.beginTransaction(); try { // schema version 29 was when we moved to incremental updates diff --git a/k9mail/src/main/java/com/fsck/k9/provider/AttachmentProvider.java b/k9mail/src/main/java/com/fsck/k9/provider/AttachmentProvider.java index 8a996e729..0d1f0adad 100644 --- a/k9mail/src/main/java/com/fsck/k9/provider/AttachmentProvider.java +++ b/k9mail/src/main/java/com/fsck/k9/provider/AttachmentProvider.java @@ -1,13 +1,15 @@ package com.fsck.k9.provider; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.util.List; + import android.content.ContentProvider; import android.content.ContentValues; -import android.content.Context; import android.database.Cursor; import android.database.MatrixCursor; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; import android.net.Uri; import android.os.ParcelFileDescriptor; import android.util.Log; @@ -16,14 +18,10 @@ import com.fsck.k9.Account; import com.fsck.k9.K9; import com.fsck.k9.Preferences; import com.fsck.k9.mail.MessagingException; -import com.fsck.k9.mail.internet.MimeUtility; import com.fsck.k9.mailstore.LocalStore; import com.fsck.k9.mailstore.LocalStore.AttachmentInfo; import org.openintents.openpgp.util.ParcelFileDescriptorUtil; -import java.io.*; -import java.util.List; - /** * A simple ContentProvider that allows file access to attachments. @@ -37,7 +35,6 @@ public class AttachmentProvider extends ContentProvider { private static final String FORMAT_RAW = "RAW"; private static final String FORMAT_VIEW = "VIEW"; - private static final String FORMAT_THUMBNAIL = "THUMBNAIL"; private static final String[] DEFAULT_PROJECTION = new String[] { AttachmentProviderColumns._ID, @@ -60,86 +57,8 @@ public class AttachmentProvider extends ContentProvider { .build(); } - public static Uri getAttachmentUriForViewing(Account account, long id, String mimeType, String filename) { - return CONTENT_URI.buildUpon() - .appendPath(account.getUuid()) - .appendPath(Long.toString(id)) - .appendPath(FORMAT_VIEW) - .appendPath(mimeType) - .appendPath(filename) - .build(); - } - - public static Uri getAttachmentThumbnailUri(Account account, long id, int width, int height) { - return CONTENT_URI.buildUpon() - .appendPath(account.getUuid()) - .appendPath(Long.toString(id)) - .appendPath(FORMAT_THUMBNAIL) - .appendPath(Integer.toString(width)) - .appendPath(Integer.toString(height)) - .build(); - } - - public static void clear(Context context) { - /* - * We use the cache dir as a temporary directory (since Android doesn't give us one) so - * on startup we'll clean up any .tmp files from the last run. - */ - File[] files = context.getCacheDir().listFiles(); - for (File file : files) { - try { - if (K9.DEBUG) { - Log.d(K9.LOG_TAG, "Deleting file " + file.getCanonicalPath()); - } - } catch (IOException ioe) { /* No need to log failure to log */ } - file.delete(); - } - } - - /** - * Delete the thumbnail of an attachment. - * - * @param context - * The application context. - * @param accountUuid - * The UUID of the account the attachment belongs to. - * @param attachmentId - * The ID of the attachment the thumbnail was created for. - */ - public static void deleteThumbnail(Context context, String accountUuid, String attachmentId) { - File file = getThumbnailFile(context, accountUuid, attachmentId); - if (file.exists()) { - file.delete(); - } - } - - private static File getThumbnailFile(Context context, String accountUuid, String attachmentId) { - String filename = "thmb_" + accountUuid + "_" + attachmentId + ".tmp"; - File dir = context.getCacheDir(); - return new File(dir, filename); - } - - @Override public boolean onCreate() { - /* - * We use the cache dir as a temporary directory (since Android doesn't give us one) so - * on startup we'll clean up any .tmp files from the last run. - */ - final File cacheDir = getContext().getCacheDir(); - if (cacheDir == null) { - return true; - } - File[] files = cacheDir.listFiles(); - if (files == null) { - return true; - } - for (File file : files) { - if (file.getName().endsWith(".tmp")) { - file.delete(); - } - } - return true; } @@ -159,14 +78,6 @@ public class AttachmentProvider extends ContentProvider { List segments = uri.getPathSegments(); String accountUuid = segments.get(0); String attachmentId = segments.get(1); - String format = segments.get(2); - - if (FORMAT_THUMBNAIL.equals(format)) { - int width = Integer.parseInt(segments.get(3)); - int height = Integer.parseInt(segments.get(4)); - - return openThumbnail(accountUuid, attachmentId, width, height); - } return openAttachment(accountUuid, attachmentId); } @@ -231,66 +142,25 @@ public class AttachmentProvider extends ContentProvider { private String getType(String accountUuid, String id, String format, String mimeType) { String type; - if (FORMAT_THUMBNAIL.equals(format)) { - type = "image/png"; - } else { - final Account account = Preferences.getPreferences(getContext()).getAccount(accountUuid); + final Account account = Preferences.getPreferences(getContext()).getAccount(accountUuid); - try { - final LocalStore localStore = LocalStore.getInstance(account, getContext()); + try { + final LocalStore localStore = LocalStore.getInstance(account, getContext()); - AttachmentInfo attachmentInfo = localStore.getAttachmentInfo(id); - if (FORMAT_VIEW.equals(format) && mimeType != null) { - type = mimeType; - } else { - type = attachmentInfo.type; - } - } catch (MessagingException e) { - Log.e(K9.LOG_TAG, "Unable to retrieve LocalStore for " + account, e); - type = null; + AttachmentInfo attachmentInfo = localStore.getAttachmentInfo(id); + if (FORMAT_VIEW.equals(format) && mimeType != null) { + type = mimeType; + } else { + type = attachmentInfo.type; } + } catch (MessagingException e) { + Log.e(K9.LOG_TAG, "Unable to retrieve LocalStore for " + account, e); + type = null; } return type; } - private ParcelFileDescriptor openThumbnail(String accountUuid, String attachmentId, int width, int height) - throws FileNotFoundException { - - File file = getThumbnailFile(getContext(), accountUuid, attachmentId); - if (!file.exists()) { - String type = getType(accountUuid, attachmentId, FORMAT_VIEW, null); - try { - InputStream in = getAttachmentInputStream(accountUuid, attachmentId); - try { - Bitmap thumbnail = createThumbnail(type, in); - if (thumbnail != null) { - thumbnail = Bitmap.createScaledBitmap(thumbnail, width, height, true); - FileOutputStream out = new FileOutputStream(file); - try { - thumbnail.compress(Bitmap.CompressFormat.PNG, 100, out); - } finally { - try { - out.close(); - } catch (IOException e) { - Log.e(K9.LOG_TAG, "Error saving thumbnail", e); - } - } - } - } finally { - try { - in.close(); - } catch (Throwable ignore) { /* ignore */ } - } - } catch (MessagingException e) { - Log.e(K9.LOG_TAG, "Error getting InputStream for attachment", e); - return null; - } - } - - return ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY); - } - private ParcelFileDescriptor openAttachment(String accountUuid, String attachmentId) { try { InputStream inputStream = getAttachmentInputStream(accountUuid, attachmentId); @@ -309,27 +179,4 @@ public class AttachmentProvider extends ContentProvider { LocalStore localStore = LocalStore.getInstance(account, getContext()); return localStore.getAttachmentInputStream(attachmentId); } - - private Bitmap createThumbnail(String type, InputStream data) { - if (MimeUtility.mimeTypeMatches(type, "image/*")) { - return createImageThumbnail(data); - } - return null; - } - - private Bitmap createImageThumbnail(InputStream data) { - try { - return BitmapFactory.decodeStream(data); - } catch (OutOfMemoryError oome) { - /* - * Improperly downloaded images, corrupt bitmaps and the like can commonly - * cause OOME due to invalid allocation sizes. We're happy with a null bitmap in - * that case. If the system is really out of memory we'll know about it soon - * enough. - */ - return null; - } catch (Exception e) { - return null; - } - } } diff --git a/k9mail/src/main/java/com/fsck/k9/ui/messageview/AttachmentView.java b/k9mail/src/main/java/com/fsck/k9/ui/messageview/AttachmentView.java index ac2acb59b..b93bb453a 100644 --- a/k9mail/src/main/java/com/fsck/k9/ui/messageview/AttachmentView.java +++ b/k9mail/src/main/java/com/fsck/k9/ui/messageview/AttachmentView.java @@ -2,8 +2,6 @@ package com.fsck.k9.ui.messageview; import android.content.Context; -import android.graphics.Bitmap; -import android.os.AsyncTask; import android.util.AttributeSet; import android.view.View; import android.view.View.OnClickListener; @@ -13,6 +11,7 @@ import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.TextView; +import com.bumptech.glide.Glide; import com.fsck.k9.K9; import com.fsck.k9.R; import com.fsck.k9.helper.SizeFormatter; @@ -76,8 +75,12 @@ public class AttachmentView extends FrameLayout implements OnClickListener, OnLo attachmentName.setText(attachment.displayName); attachmentInfo.setText(SizeFormatter.formatSize(getContext(), attachment.size)); - ImageView thumbnail = (ImageView) findViewById(R.id.attachment_icon); - new LoadAndDisplayThumbnailAsyncTask(thumbnail).execute(); + ImageView thumbnailView = (ImageView) findViewById(R.id.attachment_icon); + Glide.with(getContext()) + .load(attachment.uri) + .placeholder(R.drawable.attached_image_placeholder) + .centerCrop() + .into(thumbnailView); } @Override @@ -119,43 +122,4 @@ public class AttachmentView extends FrameLayout implements OnClickListener, OnLo public void setCallback(AttachmentViewCallback callback) { this.callback = callback; } - - private class LoadAndDisplayThumbnailAsyncTask extends AsyncTask { - private final ImageView thumbnail; - - public LoadAndDisplayThumbnailAsyncTask(ImageView thumbnail) { - this.thumbnail = thumbnail; - } - - protected Bitmap doInBackground(Void... asyncTaskArgs) { - return getPreviewIcon(); - } - - private Bitmap getPreviewIcon() { - //FIXME - temporarily disabled - return null; -// Bitmap icon = null; -// try { -// InputStream input = context.getContentResolver().openInputStream( -// AttachmentProvider.getAttachmentThumbnailUri(account, -// part.getAttachmentId(), -// 62, -// 62)); -// icon = BitmapFactory.decodeStream(input); -// input.close(); -// } catch (Exception e) { -// // We don't care what happened, we just return null for the preview icon. -// } -// -// return icon; - } - - protected void onPostExecute(Bitmap previewIcon) { - if (previewIcon != null) { - thumbnail.setImageBitmap(previewIcon); - } else { - thumbnail.setImageResource(R.drawable.attached_image_placeholder); - } - } - } }