From 4c53f9b5b13477938454b49c4a02af256a427e0f Mon Sep 17 00:00:00 2001 From: M66B Date: Sun, 6 Jan 2019 17:44:03 +0000 Subject: [PATCH] Load inline images async, named tasks --- app/src/main/java/eu/faircode/email/DB.java | 4 - .../eu/faircode/email/FragmentCompose.java | 105 +++++++++++++----- .../java/eu/faircode/email/SimpleTask.java | 25 ++++- 3 files changed, 94 insertions(+), 40 deletions(-) diff --git a/app/src/main/java/eu/faircode/email/DB.java b/app/src/main/java/eu/faircode/email/DB.java index a91d6be402..a637b84197 100644 --- a/app/src/main/java/eu/faircode/email/DB.java +++ b/app/src/main/java/eu/faircode/email/DB.java @@ -97,10 +97,6 @@ public abstract class DB extends RoomDatabase { return sInstance; } - public static synchronized DB getInstanceMainThread(Context context) { - return migrate(context, getBuilder(context).allowMainThreadQueries()); - } - private static RoomDatabase.Builder getBuilder(Context context) { return Room .databaseBuilder(context.getApplicationContext(), DB.class, DB_NAME) diff --git a/app/src/main/java/eu/faircode/email/FragmentCompose.java b/app/src/main/java/eu/faircode/email/FragmentCompose.java index d1755b866a..af0c0b6315 100644 --- a/app/src/main/java/eu/faircode/email/FragmentCompose.java +++ b/app/src/main/java/eu/faircode/email/FragmentCompose.java @@ -30,9 +30,11 @@ import android.content.Intent; import android.content.IntentSender; import android.content.SharedPreferences; import android.content.pm.PackageManager; +import android.content.res.Resources; import android.database.Cursor; import android.graphics.Typeface; import android.graphics.drawable.Drawable; +import android.graphics.drawable.LevelListDrawable; import android.net.ConnectivityManager; import android.net.Network; import android.net.NetworkCapabilities; @@ -40,6 +42,7 @@ import android.net.NetworkRequest; import android.net.Uri; import android.os.Bundle; import android.os.Handler; +import android.os.Looper; import android.preference.PreferenceManager; import android.provider.ContactsContract; import android.provider.OpenableColumns; @@ -493,7 +496,7 @@ public class FragmentCompose extends FragmentEx { args.putString("subject", getArguments().getString("subject")); args.putString("body", getArguments().getString("body")); args.putParcelableArrayList("attachments", getArguments().getParcelableArrayList("attachments")); - draftLoader.execute(this, args); + draftLoader.execute(this, args, "draft:new"); } else { Bundle args = new Bundle(); args.putString("action", "edit"); @@ -501,7 +504,7 @@ public class FragmentCompose extends FragmentEx { args.putLong("account", -1); args.putLong("reference", -1); args.putLong("answer", -1); - draftLoader.execute(this, args); + draftLoader.execute(this, args, "draft:edit"); } } else { working = savedInstanceState.getLong("working"); @@ -511,7 +514,7 @@ public class FragmentCompose extends FragmentEx { args.putLong("account", -1); args.putLong("reference", -1); args.putLong("answer", -1); - draftLoader.execute(this, args); + draftLoader.execute(this, args, "draft:instance"); } } @@ -912,7 +915,7 @@ public class FragmentCompose extends FragmentEx { else Helper.unexpectedError(getContext(), getViewLifecycleOwner(), ex); } - }.execute(this, args); + }.execute(this, args, "encrypt"); } @Override @@ -1040,7 +1043,7 @@ public class FragmentCompose extends FragmentEx { else Helper.unexpectedError(getContext(), getViewLifecycleOwner(), ex); } - }.execute(this, args); + }.execute(this, args, "add:attachment"); } private void handleExit() { @@ -1098,7 +1101,7 @@ public class FragmentCompose extends FragmentEx { dirty = false; Log.i("Run execute id=" + working); - actionLoader.execute(this, args); + actionLoader.execute(this, args, "action:" + action); } private boolean isEmpty() { @@ -1655,7 +1658,7 @@ public class FragmentCompose extends FragmentEx { protected void onException(Bundle args, Throwable ex) { Helper.unexpectedError(getContext(), getViewLifecycleOwner(), ex); } - }.execute(this, args); + }.execute(this, args, "draft:check"); } private void showDraft(EntityMessage draft) { @@ -1667,11 +1670,6 @@ public class FragmentCompose extends FragmentEx { args.putLong("reference", draft.forwarding); new SimpleTask() { - @Override - protected void onPreExecute(Bundle args) { - state = State.LOADING; - } - @Override protected void onPostExecute(Bundle args) { state = State.LOADED; @@ -1731,7 +1729,7 @@ public class FragmentCompose extends FragmentEx { protected void onException(Bundle args, Throwable ex) { Helper.unexpectedError(getContext(), getViewLifecycleOwner(), ex); } - }.execute(FragmentCompose.this, args); + }.execute(FragmentCompose.this, args, "draft:show"); } private SimpleTask actionLoader = new SimpleTask() { @@ -1989,25 +1987,72 @@ public class FragmentCompose extends FragmentEx { private Html.ImageGetter cidGetter = new Html.ImageGetter() { @Override - public Drawable getDrawable(String source) { - if (source != null && source.startsWith("cid:")) { - DB db = DB.getInstanceMainThread(getContext()); - String cid = "<" + source.substring(4) + ">"; - EntityAttachment attachment = db.attachment().getAttachment(working, cid); - if (attachment != null) { - File file = EntityAttachment.getFile(getContext(), attachment.id); - Drawable d = Drawable.createFromPath(file.getAbsolutePath()); - if (d != null) { - d.setBounds(0, 0, d.getIntrinsicWidth(), d.getIntrinsicHeight()); - return d; - } - } - } + public Drawable getDrawable(final String source) { + final LevelListDrawable lld = new LevelListDrawable(); + Resources res = getContext().getResources(); int px = Helper.dp2pixels(getContext(), 48); - Drawable d = getContext().getResources().getDrawable(R.drawable.baseline_broken_image_24, getContext().getTheme()); - d.setBounds(0, 0, px, px); - return d; + + // Level 0: broken image + Drawable broken = res.getDrawable(R.drawable.baseline_broken_image_24, getContext().getTheme()); + broken.setBounds(0, 0, px, px); + lld.addLevel(0, 0, broken); + + // Level 1: place holder + Drawable placeholder = res.getDrawable(R.drawable.baseline_image_24, getContext().getTheme()); + placeholder.setBounds(0, 0, px, px); + lld.addLevel(1, 1, placeholder); + + lld.setBounds(0, 0, px, px); + + if (source != null && source.startsWith("cid:")) { + lld.setLevel(1); // placeholder + + new Handler(Looper.getMainLooper()).post(new Runnable() { + @Override + public void run() { + Bundle args = new Bundle(); + args.putLong("id", working); + args.putString("cid", "<" + source.substring(4) + ">"); + + new SimpleTask() { + @Override + protected Drawable onExecute(Context context, Bundle args) { + long id = args.getLong("id"); + String cid = args.getString("cid"); + + DB db = DB.getInstance(context); + EntityAttachment attachment = db.attachment().getAttachment(id, cid); + if (attachment == null) + return null; + + File file = EntityAttachment.getFile(getContext(), attachment.id); + return Drawable.createFromPath(file.getAbsolutePath()); + } + + @Override + protected void onExecuted(Bundle args, Drawable image) { + if (image == null) + lld.setLevel(0); // broken + else { + lld.addLevel(2, 2, image); + lld.setLevel(2); // image + lld.setBounds(0, 0, image.getIntrinsicWidth(), image.getIntrinsicHeight()); + } + etBody.requestLayout(); + } + + @Override + protected void onException(Bundle args, Throwable ex) { + Helper.unexpectedError(getContext(), getViewLifecycleOwner(), ex); + } + }.execute(FragmentCompose.this, args, source); + } + }); + } else + lld.setLevel(0); // broken + + return lld; } }; diff --git a/app/src/main/java/eu/faircode/email/SimpleTask.java b/app/src/main/java/eu/faircode/email/SimpleTask.java index 4ace2a795c..55f7813fa8 100644 --- a/app/src/main/java/eu/faircode/email/SimpleTask.java +++ b/app/src/main/java/eu/faircode/email/SimpleTask.java @@ -26,6 +26,7 @@ import android.os.Handler; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import androidx.annotation.NonNull; import androidx.appcompat.app.AppCompatActivity; import androidx.fragment.app.Fragment; import androidx.lifecycle.Lifecycle; @@ -45,25 +46,30 @@ public abstract class SimpleTask implements LifecycleObserver { private boolean paused; private boolean destroyed; private Bundle args; + private String name; private Result stored; private static ExecutorService executor = Executors.newCachedThreadPool(Helper.backgroundThreadFactory); public void execute(Context context, LifecycleOwner owner, Bundle args) { - run(context, owner, args); + run(context, owner, args, null); } public void execute(LifecycleService service, Bundle args) { - run(service, service, args); + run(service, service, args, null); } public void execute(AppCompatActivity activity, Bundle args) { - run(activity, activity, args); + run(activity, activity, args, null); } - public void execute(final Fragment fragment, Bundle args) { + public void execute(Fragment fragment, Bundle args) { + execute(fragment, args, null); + } + + public void execute(final Fragment fragment, Bundle args, String name) { try { - run(fragment.getContext(), fragment.getViewLifecycleOwner(), args); + run(fragment.getContext(), fragment.getViewLifecycleOwner(), args, name); } catch (IllegalStateException ex) { Log.w(ex); } @@ -111,11 +117,12 @@ public abstract class SimpleTask implements LifecycleObserver { stored = null; } - private void run(final Context context, LifecycleOwner owner, final Bundle args) { + private void run(final Context context, LifecycleOwner owner, final Bundle args, String name) { this.owner = owner; this.paused = false; this.destroyed = false; this.args = null; + this.name = name; this.stored = null; owner.getLifecycle().addObserver(this); @@ -198,4 +205,10 @@ public abstract class SimpleTask implements LifecycleObserver { Throwable ex; Object data; } + + @NonNull + @Override + public String toString() { + return (name == null ? super.toString() : name); + } }