mirror of
https://github.com/moparisthebest/k-9
synced 2024-11-04 16:45:09 -05:00
Use Glide for thumbnail generation + image loading
This commit is contained in:
parent
cb94b5b192
commit
de2eb25446
@ -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'
|
||||
|
@ -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() {
|
||||
|
@ -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<LocalMessage> 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<LocalMessage> 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;
|
||||
|
@ -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
|
||||
|
@ -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<String> 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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<Void, Void, Bitmap> {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user