diff --git a/app/src/main/java/eu/faircode/email/ActivityEML.java b/app/src/main/java/eu/faircode/email/ActivityEML.java index 3deff1b2b7..999e5b1092 100644 --- a/app/src/main/java/eu/faircode/email/ActivityEML.java +++ b/app/src/main/java/eu/faircode/email/ActivityEML.java @@ -275,7 +275,7 @@ public class ActivityEML extends ActivityBase { } int textColorLink = Helper.resolveColor(context, android.R.attr.textColorLink); - SpannableStringBuilder ssb = new SpannableStringBuilder(); + SpannableStringBuilder ssb = new SpannableStringBuilderEx(); getStructure(imessage, ssb, 0, textColorLink); result.structure = ssb; diff --git a/app/src/main/java/eu/faircode/email/ActivitySignature.java b/app/src/main/java/eu/faircode/email/ActivitySignature.java index bb2d72c35d..61bdaa8582 100644 --- a/app/src/main/java/eu/faircode/email/ActivitySignature.java +++ b/app/src/main/java/eu/faircode/email/ActivitySignature.java @@ -356,7 +356,7 @@ public class ActivitySignature extends ActivityBase { if (etText.isRaw()) etText.getText().insert(start, ""); else { - SpannableStringBuilder ssb = new SpannableStringBuilder(etText.getText()); + SpannableStringBuilder ssb = new SpannableStringBuilderEx(etText.getText()); ssb.insert(start, " \uFFFC"); // Object replacement character String source = uri.toString(); Drawable d = ImageHelper.decodeImage(this, -1, source, true, 0, 1.0f, etText); diff --git a/app/src/main/java/eu/faircode/email/AdapterLog.java b/app/src/main/java/eu/faircode/email/AdapterLog.java index 2d639fc348..8e0fa10d1f 100644 --- a/app/src/main/java/eu/faircode/email/AdapterLog.java +++ b/app/src/main/java/eu/faircode/email/AdapterLog.java @@ -80,7 +80,7 @@ public class AdapterLog extends RecyclerView.Adapter { private void bindTo(EntityLog log) { tvTime.setText(TF.format(log.time)); - SpannableStringBuilder ssb = new SpannableStringBuilder(log.data); + SpannableStringBuilder ssb = new SpannableStringBuilderEx(log.data); switch (log.type) { case General: break; diff --git a/app/src/main/java/eu/faircode/email/AdapterMessage.java b/app/src/main/java/eu/faircode/email/AdapterMessage.java index 3febda8b84..5b9444d2b9 100644 --- a/app/src/main/java/eu/faircode/email/AdapterMessage.java +++ b/app/src/main/java/eu/faircode/email/AdapterMessage.java @@ -1996,7 +1996,7 @@ public class AdapterMessage extends RecyclerView.Adapter s.length()) @@ -6118,7 +6118,7 @@ public class FragmentCompose extends FragmentBase { } }, null); - SpannableStringBuilder bodyBuilder = new SpannableStringBuilder(spannedBody); + SpannableStringBuilder bodyBuilder = new SpannableStringBuilderEx(spannedBody); QuoteSpan[] bodySpans = bodyBuilder.getSpans(0, bodyBuilder.length(), QuoteSpan.class); for (QuoteSpan quoteSpan : bodySpans) { QuoteSpan q; diff --git a/app/src/main/java/eu/faircode/email/FragmentDialogOpenLink.java b/app/src/main/java/eu/faircode/email/FragmentDialogOpenLink.java index 8059b9619c..ea8a071d48 100644 --- a/app/src/main/java/eu/faircode/email/FragmentDialogOpenLink.java +++ b/app/src/main/java/eu/faircode/email/FragmentDialogOpenLink.java @@ -641,7 +641,7 @@ public class FragmentDialogOpenLink extends FragmentDialogBase { String scheme = uri.getScheme(); String host = uri.getHost(); String text = uri.toString(); - SpannableStringBuilder ssb = new SpannableStringBuilder(text); + SpannableStringBuilder ssb = new SpannableStringBuilderEx(text); try { int textColorLink = Helper.resolveColor(context, android.R.attr.textColorLink); diff --git a/app/src/main/java/eu/faircode/email/FragmentMessages.java b/app/src/main/java/eu/faircode/email/FragmentMessages.java index 986ab350b9..adba676ed1 100644 --- a/app/src/main/java/eu/faircode/email/FragmentMessages.java +++ b/app/src/main/java/eu/faircode/email/FragmentMessages.java @@ -4640,7 +4640,7 @@ public class FragmentMessages extends FragmentBase implements SharedPreferences. PopupMenuLifecycle popupMenu = new PopupMenuLifecycle(getContext(), getViewLifecycleOwner(), vwAnchor); - SpannableStringBuilder all = new SpannableStringBuilder(getString(R.string.title_language_all)); + SpannableStringBuilder all = new SpannableStringBuilderEx(getString(R.string.title_language_all)); if (current == null) { all.setSpan(new StyleSpan(Typeface.BOLD), 0, all.length(), 0); all.setSpan(new RelativeSizeSpan(HtmlHelper.FONT_LARGE), 0, all.length(), 0); @@ -4651,7 +4651,7 @@ public class FragmentMessages extends FragmentBase implements SharedPreferences. for (int i = 0; i < locales.size(); i++) { Locale locale = locales.get(i); String language = locale.getLanguage(); - SpannableStringBuilder title = new SpannableStringBuilder(locale.getDisplayLanguage()); + SpannableStringBuilder title = new SpannableStringBuilderEx(locale.getDisplayLanguage()); if (language.equals(current)) { title.setSpan(new StyleSpan(Typeface.BOLD), 0, title.length(), 0); title.setSpan(new RelativeSizeSpan(HtmlHelper.FONT_LARGE), 0, title.length(), 0); diff --git a/app/src/main/java/eu/faircode/email/FragmentOptions.java b/app/src/main/java/eu/faircode/email/FragmentOptions.java index a7df91171d..9de78c315b 100644 --- a/app/src/main/java/eu/faircode/email/FragmentOptions.java +++ b/app/src/main/java/eu/faircode/email/FragmentOptions.java @@ -220,7 +220,7 @@ public class FragmentOptions extends FragmentBase { for (int i = 0; i < tabLayout.getTabCount(); i++) { Drawable d = context.getDrawable(PAGE_ICONS[i]); d.setColorFilter(colorAccent, PorterDuff.Mode.SRC_ATOP); - SpannableStringBuilder title = new SpannableStringBuilder(getString(PAGE_TITLES[i])); + SpannableStringBuilder title = new SpannableStringBuilderEx(getString(PAGE_TITLES[i])); if (i > 0) title.setSpan(new RelativeSizeSpan(0.85f), 0, title.length(), 0); tabLayout.getTabAt(i) diff --git a/app/src/main/java/eu/faircode/email/FragmentOptionsEncryption.java b/app/src/main/java/eu/faircode/email/FragmentOptionsEncryption.java index a89eb1a716..97aacf90e4 100644 --- a/app/src/main/java/eu/faircode/email/FragmentOptionsEncryption.java +++ b/app/src/main/java/eu/faircode/email/FragmentOptionsEncryption.java @@ -416,7 +416,7 @@ public class FragmentOptionsEncryption extends FragmentBase implements SharedPre @Override protected Spanned onExecute(Context context, Bundle args) { boolean debug = args.getBoolean("debug"); - SpannableStringBuilder ssb = new SpannableStringBuilder(); + SpannableStringBuilder ssb = new SpannableStringBuilderEx(); int dp24 = Helper.dp2pixels(context, 24); diff --git a/app/src/main/java/eu/faircode/email/FragmentOptionsMisc.java b/app/src/main/java/eu/faircode/email/FragmentOptionsMisc.java index 8d0de44c2c..1caf3dc4e5 100644 --- a/app/src/main/java/eu/faircode/email/FragmentOptionsMisc.java +++ b/app/src/main/java/eu/faircode/email/FragmentOptionsMisc.java @@ -1189,7 +1189,7 @@ public class FragmentOptionsMisc extends FragmentBase implements SharedPreferenc try { int start = 0; int dp24 = Helper.dp2pixels(getContext(), 24); - SpannableStringBuilder ssb = new SpannableStringBuilder(); + SpannableStringBuilder ssb = new SpannableStringBuilderEx(); PackageManager pm = getContext().getPackageManager(); PackageInfo pi = pm.getPackageInfo(BuildConfig.APPLICATION_ID, PackageManager.GET_PERMISSIONS); for (int i = 0; i < pi.requestedPermissions.length; i++) { diff --git a/app/src/main/java/eu/faircode/email/FragmentOptionsSend.java b/app/src/main/java/eu/faircode/email/FragmentOptionsSend.java index 1d920051cf..ea59e0d5ad 100644 --- a/app/src/main/java/eu/faircode/email/FragmentOptionsSend.java +++ b/app/src/main/java/eu/faircode/email/FragmentOptionsSend.java @@ -159,7 +159,7 @@ public class FragmentOptionsSend extends FragmentBase implements SharedPreferenc List fn = new ArrayList<>(); for (int i = 0; i < fontNameNames.length; i++) { - SpannableStringBuilder ssb = new SpannableStringBuilder(fontNameNames[i]); + SpannableStringBuilder ssb = new SpannableStringBuilderEx(fontNameNames[i]); ssb.setSpan(new TypefaceSpan(fontNameValues[i]), 0, ssb.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); fn.add(ssb); } diff --git a/app/src/main/java/eu/faircode/email/HtmlHelper.java b/app/src/main/java/eu/faircode/email/HtmlHelper.java index e466a82da5..5fe7e596ad 100644 --- a/app/src/main/java/eu/faircode/email/HtmlHelper.java +++ b/app/src/main/java/eu/faircode/email/HtmlHelper.java @@ -2260,7 +2260,7 @@ public class HtmlHelper { } static Spanned highlightHeaders(Context context, String headers, boolean blocklist) { - SpannableStringBuilder ssb = new SpannableStringBuilder(headers); + SpannableStringBuilder ssb = new SpannableStringBuilderEx(headers); int textColorLink = Helper.resolveColor(context, android.R.attr.textColorLink); int index = 0; @@ -2584,7 +2584,7 @@ public class HtmlHelper { }, document.body()); // https://developer.android.com/guide/topics/text/spans - SpannableStringBuilder ssb = new SpannableStringBuilder(); + SpannableStringBuilder ssb = new SpannableStringBuilderEx(); NodeTraversor.traverse(new NodeVisitor() { private Element element; diff --git a/app/src/main/java/eu/faircode/email/PopupMenuLifecycle.java b/app/src/main/java/eu/faircode/email/PopupMenuLifecycle.java index 6664fdb623..44e232b577 100644 --- a/app/src/main/java/eu/faircode/email/PopupMenuLifecycle.java +++ b/app/src/main/java/eu/faircode/email/PopupMenuLifecycle.java @@ -131,7 +131,7 @@ public class PopupMenuLifecycle extends PopupMenu implements LifecycleObserver { icon.setBounds(0, 0, iconSize, iconSize); ImageSpan imageSpan = new CenteredImageSpan(icon); - SpannableStringBuilder ssb = new SpannableStringBuilder(menuItem.getTitle()); + SpannableStringBuilder ssb = new SpannableStringBuilderEx(menuItem.getTitle()); ssb.insert(0, "\uFFFC\u2002"); // object replacement character, en space ssb.setSpan(imageSpan, 0, 1, 0); menuItem.setTitle(ssb); diff --git a/app/src/main/java/eu/faircode/email/SpannableStringBuilderEx.java b/app/src/main/java/eu/faircode/email/SpannableStringBuilderEx.java new file mode 100644 index 0000000000..9b3cc6980c --- /dev/null +++ b/app/src/main/java/eu/faircode/email/SpannableStringBuilderEx.java @@ -0,0 +1,70 @@ +package eu.faircode.email; + +/* + This file is part of FairEmail. + + FairEmail is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + FairEmail is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with FairEmail. If not, see . + + Copyright 2018-2021 by Marcel Bokhorst (M66B) +*/ + +import android.text.SpannableStringBuilder; + +public class SpannableStringBuilderEx extends SpannableStringBuilder { + public SpannableStringBuilderEx() { + super(); + } + + public SpannableStringBuilderEx(CharSequence text) { + super(text); + } + + public SpannableStringBuilderEx(CharSequence text, int start, int end) { + super(text, start, end); + } + + @Override + public void setSpan(Object what, int start, int end, int flags) { + try { + super.setSpan(what, start, end, flags); + } catch (Throwable ex) { + Log.e(ex); + /* + java.lang.IndexOutOfBoundsException: setSpan (-1 ... -1) starts before 0 + at android.text.SpannableStringInternal.checkRange(SpannableStringInternal.java:497) + at android.text.SpannableStringInternal.setSpan(SpannableStringInternal.java:197) + at android.text.SpannableStringInternal.setSpan(SpannableStringInternal.java:184) + at android.text.SpannableString.setSpan(SpannableString.java:60) + at android.text.Selection.setSelection(Selection.java:96) + at android.text.Selection.setSelection(Selection.java:78) + at android.widget.Editor$SelectionStartHandleView.updateSelection(Editor.java:7649) + at android.widget.Editor$HandleView.positionAtCursorOffset(Editor.java:6886) + at android.widget.Editor$HandleView.updatePosition(Editor.java:6920) + at android.widget.Editor$PositionListener.onPreDraw(Editor.java:3660) + at android.view.ViewTreeObserver.dispatchOnPreDraw(ViewTreeObserver.java:1093) + at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:3194) + at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:2046) + at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:8349) + at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1058) + at android.view.Choreographer.doCallbacks(Choreographer.java:880) + at android.view.Choreographer.doFrame(Choreographer.java:813) + at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:1043) + at android.os.Handler.handleCallback(Handler.java:938) + at android.os.Handler.dispatchMessage(Handler.java:99) + at android.os.Looper.loop(Looper.java:236) + at android.app.ActivityThread.main(ActivityThread.java:7861) + */ + } + } +} diff --git a/app/src/main/java/eu/faircode/email/StyleHelper.java b/app/src/main/java/eu/faircode/email/StyleHelper.java index 63925efc13..046e6aa160 100644 --- a/app/src/main/java/eu/faircode/email/StyleHelper.java +++ b/app/src/main/java/eu/faircode/email/StyleHelper.java @@ -146,7 +146,7 @@ public class StyleHelper { int[] titles = new int[]{R.string.title_style_size_small, R.string.title_style_size_medium, R.string.title_style_size_large}; float[] sizes = new float[]{HtmlHelper.FONT_SMALL, 1.0f, HtmlHelper.FONT_LARGE}; for (int i = 0; i < ids.length; i++) { - SpannableStringBuilder ssb = new SpannableStringBuilder(context.getString(titles[i])); + SpannableStringBuilder ssb = new SpannableStringBuilderEx(context.getString(titles[i])); ssb.setSpan(new RelativeSizeSpan(sizes[i]), 0, ssb.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); smenu.add(R.id.group_style_size, ids[i], i, ssb); } @@ -156,7 +156,7 @@ public class StyleHelper { String[] fontNameValues = anchor.getResources().getStringArray(R.array.fontNameValues); SubMenu smenu = popupMenu.getMenu().findItem(R.id.menu_style_font).getSubMenu(); for (int i = 0; i < fontNameNames.length; i++) { - SpannableStringBuilder ssb = new SpannableStringBuilder(fontNameNames[i]); + SpannableStringBuilder ssb = new SpannableStringBuilderEx(fontNameNames[i]); ssb.setSpan(getTypefaceSpan(fontNameValues[i], context), 0, ssb.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); smenu.add(R.id.group_style_font, i, 0, ssb); }