diff --git a/app/src/main/java/eu/faircode/email/AdapterMessage.java b/app/src/main/java/eu/faircode/email/AdapterMessage.java index 5b7e97beeb..05dcab3dfc 100644 --- a/app/src/main/java/eu/faircode/email/AdapterMessage.java +++ b/app/src/main/java/eu/faircode/email/AdapterMessage.java @@ -1419,179 +1419,185 @@ public class AdapterMessage extends RecyclerView.Adapter() { + // Run task after measure + new Handler().post(new Runnable() { @Override - protected Object onExecute(final Context context, final Bundle args) throws IOException { - TupleMessageEx message = (TupleMessageEx) args.getSerializable("message"); - boolean show_full = args.getBoolean("show_full"); - boolean show_images = args.getBoolean("show_images"); - boolean show_quotes = args.getBoolean("show_quotes"); - int zoom = args.getInt("zoom"); + public void run() { + new SimpleTask() { + @Override + protected Object onExecute(final Context context, final Bundle args) throws IOException { + TupleMessageEx message = (TupleMessageEx) args.getSerializable("message"); + boolean show_full = args.getBoolean("show_full"); + boolean show_images = args.getBoolean("show_images"); + boolean show_quotes = args.getBoolean("show_quotes"); + int zoom = args.getInt("zoom"); - if (message == null || !message.content) - return null; + if (message == null || !message.content) + return null; - File file = message.getFile(context); - if (!file.exists()) - return null; + File file = message.getFile(context); + if (!file.exists()) + return null; - String body = Helper.readText(file); - Document document = JsoupEx.parse(body); + String body = Helper.readText(file); + Document document = JsoupEx.parse(body); - // Check for inline encryption - int begin = body.indexOf(Helper.PGP_BEGIN_MESSAGE); - int end = body.indexOf(Helper.PGP_END_MESSAGE); - args.putBoolean("iencrypted", begin >= 0 && begin < end); + // Check for inline encryption + int begin = body.indexOf(Helper.PGP_BEGIN_MESSAGE); + int end = body.indexOf(Helper.PGP_END_MESSAGE); + args.putBoolean("iencrypted", begin >= 0 && begin < end); - // Check for images - boolean has_images = false; - for (Element img : document.select("img")) { - if (inline) { - String src = img.attr("src"); - if (!src.startsWith("cid:")) { - has_images = true; - break; + // Check for images + boolean has_images = false; + for (Element img : document.select("img")) { + if (inline) { + String src = img.attr("src"); + if (!src.startsWith("cid:")) { + has_images = true; + break; + } + } else { + has_images = true; + break; + } } - } else { - has_images = true; - break; - } - } - args.putBoolean("has_images", has_images); + args.putBoolean("has_images", has_images); - if (show_full) { - HtmlHelper.removeViewportLimitations(document); - if (inline || show_images) - HtmlHelper.embedInlineImages(context, message.id, document); + if (show_full) { + HtmlHelper.removeViewportLimitations(document); + if (inline || show_images) + HtmlHelper.embedInlineImages(context, message.id, document); - SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); - boolean disable_tracking = prefs.getBoolean("disable_tracking", true); - if (disable_tracking) - HtmlHelper.removeTrackingPixels(context, document); + SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); + boolean disable_tracking = prefs.getBoolean("disable_tracking", true); + if (disable_tracking) + HtmlHelper.removeTrackingPixels(context, document); - if (debug) { - Document format = JsoupEx.parse(document.html()); - format.outputSettings().prettyPrint(true).outline(true).indentAmount(1); - Element pre = document.createElement("pre"); - pre.text(format.html()); - document.body().appendChild(pre); - } - - return document.html(); - } else { - // Collapse quotes - if (!show_quotes) { - for (Element quote : document.select("blockquote")) - quote.html("…"); - body = document.html(); - } - - // Cleanup message - String html = HtmlHelper.sanitize(context, body, show_images); - if (debug) { - Document format = JsoupEx.parse(html); - format.outputSettings().prettyPrint(true).outline(true).indentAmount(1); - String[] lines = format.html().split("\\r?\\n"); - for (int i = 0; i < lines.length; i++) - lines[i] = Html.escapeHtml(lines[i]); - html += "
" + TextUtils.join("
", lines) + "
"; - } - - Spanned spanned = HtmlHelper.fromHtml(html, new Html.ImageGetter() { - @Override - public Drawable getDrawable(String source) { - Drawable drawable = ImageHelper.decodeImage(context, message.id, source, show_images, tvBody); - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { - if (drawable instanceof AnimatedImageDrawable) - ((AnimatedImageDrawable) drawable).start(); + if (debug) { + Document format = JsoupEx.parse(document.html()); + format.outputSettings().prettyPrint(true).outline(true).indentAmount(1); + Element pre = document.createElement("pre"); + pre.text(format.html()); + document.body().appendChild(pre); } - return drawable; + return document.html(); + } else { + // Collapse quotes + if (!show_quotes) { + for (Element quote : document.select("blockquote")) + quote.html("…"); + body = document.html(); + } + + // Cleanup message + String html = HtmlHelper.sanitize(context, body, show_images); + if (debug) { + Document format = JsoupEx.parse(html); + format.outputSettings().prettyPrint(true).outline(true).indentAmount(1); + String[] lines = format.html().split("\\r?\\n"); + for (int i = 0; i < lines.length; i++) + lines[i] = Html.escapeHtml(lines[i]); + html += "
" + TextUtils.join("
", lines) + "
"; + } + + Spanned spanned = HtmlHelper.fromHtml(html, new Html.ImageGetter() { + @Override + public Drawable getDrawable(String source) { + Drawable drawable = ImageHelper.decodeImage(context, message.id, source, show_images, tvBody); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { + if (drawable instanceof AnimatedImageDrawable) + ((AnimatedImageDrawable) drawable).start(); + } + + return drawable; + } + }, null); + + // Replace quote spans + SpannableStringBuilder builder = new SpannableStringBuilder(spanned); + QuoteSpan[] quoteSpans = builder.getSpans(0, builder.length(), QuoteSpan.class); + for (QuoteSpan quoteSpan : quoteSpans) { + builder.setSpan( + new StyledQuoteSpan(context, colorPrimary), + builder.getSpanStart(quoteSpan), + builder.getSpanEnd(quoteSpan), + builder.getSpanFlags(quoteSpan)); + builder.removeSpan(quoteSpan); + } + + // Make collapsed quotes clickable + if (!show_quotes) { + final int px = Helper.dp2pixels(context, 24 + (zoom) * 8); + + StyledQuoteSpan[] squotes = builder.getSpans(0, builder.length(), StyledQuoteSpan.class); + for (StyledQuoteSpan squote : squotes) + builder.setSpan(new DynamicDrawableSpan() { + @Override + public Drawable getDrawable() { + Drawable d = context.getDrawable(R.drawable.baseline_format_quote_24); + d.setTint(colorAccent); + d.setBounds(0, 0, px, px); + return d; + } + }, + builder.getSpanStart(squote), + builder.getSpanEnd(squote), + builder.getSpanFlags(squote)); + } + + return builder; } - }, null); - - // Replace quote spans - SpannableStringBuilder builder = new SpannableStringBuilder(spanned); - QuoteSpan[] quoteSpans = builder.getSpans(0, builder.length(), QuoteSpan.class); - for (QuoteSpan quoteSpan : quoteSpans) { - builder.setSpan( - new StyledQuoteSpan(context, colorPrimary), - builder.getSpanStart(quoteSpan), - builder.getSpanEnd(quoteSpan), - builder.getSpanFlags(quoteSpan)); - builder.removeSpan(quoteSpan); } - // Make collapsed quotes clickable - if (!show_quotes) { - final int px = Helper.dp2pixels(context, 24 + (zoom) * 8); + @Override + protected void onExecuted(Bundle args, Object result) { + TupleMessageEx message = (TupleMessageEx) args.getSerializable("message"); + properties.setValue("iencrypted", message.id, args.getBoolean("iencrypted")); - StyledQuoteSpan[] squotes = builder.getSpans(0, builder.length(), StyledQuoteSpan.class); - for (StyledQuoteSpan squote : squotes) - builder.setSpan(new DynamicDrawableSpan() { - @Override - public Drawable getDrawable() { - Drawable d = context.getDrawable(R.drawable.baseline_format_quote_24); - d.setTint(colorAccent); - d.setBounds(0, 0, px, px); - return d; - } - }, - builder.getSpanStart(squote), - builder.getSpanEnd(squote), - builder.getSpanFlags(squote)); + TupleMessageEx amessage = getMessage(); + if (amessage == null || !amessage.id.equals(message.id)) + return; + + boolean show_expanded = properties.getValue("expanded", message.id); + if (!show_expanded) + return; + + boolean has_images = args.getBoolean("has_images"); + boolean show_images = properties.getValue("images", message.id); + + if (result instanceof Spanned) { + tvBody.setText((Spanned) result); + tvBody.setTextIsSelectable(false); + tvBody.setTextIsSelectable(true); + tvBody.setMovementMethod(new TouchHandler(message)); + } else if (result instanceof String) + ((WebView) wvBody).loadDataWithBaseURL(null, (String) result, "text/html", "UTF-8", null); + else + throw new IllegalStateException("Result=" + result); + + pbBody.setVisibility(View.GONE); + + // Show attachments/images + cowner.start(); + ibImages.setVisibility(has_images && !show_images ? View.VISIBLE : View.GONE); } - return builder; - } + @Override + protected void onException(Bundle args, Throwable ex) { + Helper.unexpectedError(parentFragment.getFragmentManager(), ex); + } + }.execute(context, owner, args, "message:body"); } - - @Override - protected void onExecuted(Bundle args, Object result) { - TupleMessageEx message = (TupleMessageEx) args.getSerializable("message"); - properties.setValue("iencrypted", message.id, args.getBoolean("iencrypted")); - - TupleMessageEx amessage = getMessage(); - if (amessage == null || !amessage.id.equals(message.id)) - return; - - boolean show_expanded = properties.getValue("expanded", message.id); - if (!show_expanded) - return; - - boolean has_images = args.getBoolean("has_images"); - boolean show_images = properties.getValue("images", message.id); - - if (result instanceof Spanned) { - tvBody.setText((Spanned) result); - tvBody.setTextIsSelectable(false); - tvBody.setTextIsSelectable(true); - tvBody.setMovementMethod(new TouchHandler(message)); - } else if (result instanceof String) - ((WebView) wvBody).loadDataWithBaseURL(null, (String) result, "text/html", "UTF-8", null); - else - throw new IllegalStateException("Result=" + result); - - pbBody.setVisibility(View.GONE); - - // Show attachments/images - cowner.start(); - ibImages.setVisibility(has_images && !show_images ? View.VISIBLE : View.GONE); - } - - @Override - protected void onException(Bundle args, Throwable ex) { - Helper.unexpectedError(parentFragment.getFragmentManager(), ex); - } - }.execute(context, owner, args, "message:body"); + }); } private void bindAttachments(final TupleMessageEx message, @Nullable List attachments) { diff --git a/app/src/main/java/eu/faircode/email/ImageHelper.java b/app/src/main/java/eu/faircode/email/ImageHelper.java index f997d690cf..473f9c375d 100644 --- a/app/src/main/java/eu/faircode/email/ImageHelper.java +++ b/app/src/main/java/eu/faircode/email/ImageHelper.java @@ -58,8 +58,6 @@ import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; -import java.util.concurrent.Semaphore; -import java.util.concurrent.TimeUnit; class ImageHelper { private static final float MIN_LUMINANCE = 0.33f; @@ -387,33 +385,12 @@ class ImageHelper { d.setBounds(0, 0, w, h); } - final Semaphore semaphore = new Semaphore(0); - - view.addOnLayoutChangeListener(new View.OnLayoutChangeListener() { - @Override - public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) { - view.removeOnLayoutChangeListener(this); - - Rect bounds = d.getBounds(); - int w = bounds.width(); - int h = bounds.height(); - - float width = view.getWidth(); - if (w > width) { - float scale = width / w; - w = Math.round(w * scale); - h = Math.round(h * scale); - d.setBounds(0, 0, w, h); - } - - semaphore.release(); - } - }); - - try { - semaphore.tryAcquire(2500, TimeUnit.MILLISECONDS); - } catch (InterruptedException ex) { - Log.e(ex); + float width = view.getWidth(); + if (w > width) { + float scale = width / w; + w = Math.round(w * scale); + h = Math.round(h * scale); + d.setBounds(0, 0, w, h); } }