diff --git a/app/src/main/java/eu/faircode/email/Core.java b/app/src/main/java/eu/faircode/email/Core.java index 4c8e8e1a77..8e1dbf5366 100644 --- a/app/src/main/java/eu/faircode/email/Core.java +++ b/app/src/main/java/eu/faircode/email/Core.java @@ -4582,11 +4582,11 @@ class Core { // Wearables StringBuilder sb = new StringBuilder(); if (!TextUtils.isEmpty(message.subject)) - sb.append(message.subject); + sb.append(TextHelper.transliterate(context, message.subject)); if (wearable_preview && !TextUtils.isEmpty(preview)) { if (sb.length() > 0) sb.append(" - "); - sb.append(preview); + sb.append(TextHelper.transliterate(context, preview)); } if (sb.length() > 0) mbuilder.setContentText(sb.toString()); @@ -4611,7 +4611,7 @@ class Core { } } else { if (!TextUtils.isEmpty(message.subject)) - mbuilder.setContentText(message.subject); + mbuilder.setContentText(TextHelper.transliterate(context, message.subject)); } if (info[0].hasPhoto()) diff --git a/app/src/main/java/eu/faircode/email/FragmentOptionsNotifications.java b/app/src/main/java/eu/faircode/email/FragmentOptionsNotifications.java index 450edec1dd..29bba0ee56 100644 --- a/app/src/main/java/eu/faircode/email/FragmentOptionsNotifications.java +++ b/app/src/main/java/eu/faircode/email/FragmentOptionsNotifications.java @@ -91,6 +91,7 @@ public class FragmentOptionsNotifications extends FragmentBase implements Shared private SwitchCompat swNotifyPreview; private SwitchCompat swNotifyPreviewAll; private SwitchCompat swNotifyPreviewOnly; + private SwitchCompat swNotifyTransliterate; private ImageButton ibLight; private SwitchCompat swWearablePreview; private ImageButton ibWearable; @@ -112,7 +113,8 @@ public class FragmentOptionsNotifications extends FragmentBase implements Shared "light", "sound", "badge", "unseen_ignored", "notify_background_only", "notify_known", "notify_summary", "notify_remove", "notify_clear", - "notify_subtext", "notify_preview", "notify_preview_all", "notify_preview_only", "wearable_preview", + "notify_subtext", "notify_preview", "notify_preview_all", "notify_preview_only", "notify_transliterate", + "wearable_preview", "notify_messaging", "biometrics_notify", "alert_once" @@ -165,6 +167,7 @@ public class FragmentOptionsNotifications extends FragmentBase implements Shared swNotifyPreview = view.findViewById(R.id.swNotifyPreview); swNotifyPreviewAll = view.findViewById(R.id.swNotifyPreviewAll); swNotifyPreviewOnly = view.findViewById(R.id.swNotifyPreviewOnly); + swNotifyTransliterate = view.findViewById(R.id.swNotifyTransliterate); ibLight = view.findViewById(R.id.ibLight); swWearablePreview = view.findViewById(R.id.swWearablePreview); ibWearable = view.findViewById(R.id.ibWearable); @@ -439,6 +442,13 @@ public class FragmentOptionsNotifications extends FragmentBase implements Shared } }); + swNotifyTransliterate.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { + @Override + public void onCheckedChanged(CompoundButton compoundButton, boolean checked) { + prefs.edit().putBoolean("notify_transliterate", checked).apply(); + } + }); + ibLight.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { @@ -489,6 +499,7 @@ public class FragmentOptionsNotifications extends FragmentBase implements Shared : R.color.lightColorBackground_cards)); } + swNotifyTransliterate.setVisibility(TextHelper.canTransliterate() ? View.VISIBLE : View.GONE); swUnseenIgnored.setVisibility(Helper.isXiaomi() ? View.GONE : View.VISIBLE); swAlertOnce.setVisibility(Helper.isXiaomi() || BuildConfig.DEBUG ? View.VISIBLE : View.GONE); @@ -587,6 +598,7 @@ public class FragmentOptionsNotifications extends FragmentBase implements Shared swNotifyPreview.setChecked(prefs.getBoolean("notify_preview", true)); swNotifyPreviewAll.setChecked(prefs.getBoolean("notify_preview_all", false)); swNotifyPreviewOnly.setChecked(prefs.getBoolean("notify_preview_only", false)); + swNotifyTransliterate.setChecked(prefs.getBoolean("notify_transliterate", false)); swWearablePreview.setChecked(prefs.getBoolean("wearable_preview", false)); swMessagingStyle.setChecked(prefs.getBoolean("notify_messaging", false)); swBiometricsNotify.setChecked(prefs.getBoolean("biometrics_notify", true)); diff --git a/app/src/main/java/eu/faircode/email/Log.java b/app/src/main/java/eu/faircode/email/Log.java index 68dc2a6148..f397442102 100644 --- a/app/src/main/java/eu/faircode/email/Log.java +++ b/app/src/main/java/eu/faircode/email/Log.java @@ -35,6 +35,7 @@ import android.content.res.Configuration; import android.content.res.Resources; import android.database.sqlite.SQLiteFullException; import android.graphics.Point; +import android.icu.text.Transliterator; import android.net.ConnectivityManager; import android.net.LinkProperties; import android.net.Network; @@ -99,6 +100,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Date; +import java.util.Enumeration; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -1692,6 +1694,15 @@ public class Log { .append(" yes=").append((uiMode & Configuration.UI_MODE_NIGHT_YES) != 0) .append("\r\n"); + if (BuildConfig.DEBUG && + Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { + sb.append("Transliterators:"); + Enumeration ids = Transliterator.getAvailableIDs(); + while (ids.hasMoreElements()) + sb.append(' ').append(ids.nextElement()); + sb.append("\r\n"); + } + try { int maxKeySize = javax.crypto.Cipher.getMaxAllowedKeyLength("AES"); sb.append(context.getString(R.string.title_advanced_aes_key_size, maxKeySize)).append("\r\n"); diff --git a/app/src/main/java/eu/faircode/email/TextHelper.java b/app/src/main/java/eu/faircode/email/TextHelper.java index 319c8d2f9e..2220b054ca 100644 --- a/app/src/main/java/eu/faircode/email/TextHelper.java +++ b/app/src/main/java/eu/faircode/email/TextHelper.java @@ -21,6 +21,8 @@ package eu.faircode.email; import android.app.Person; import android.content.Context; +import android.content.SharedPreferences; +import android.icu.text.Transliterator; import android.os.Build; import android.text.TextUtils; import android.view.textclassifier.ConversationAction; @@ -28,6 +30,9 @@ import android.view.textclassifier.ConversationActions; import android.view.textclassifier.TextClassificationManager; import android.view.textclassifier.TextClassifier; +import androidx.preference.PreferenceManager; + +import java.text.Normalizer; import java.time.ZoneId; import java.time.ZonedDateTime; import java.util.ArrayList; @@ -82,6 +87,42 @@ public class TextHelper { } } + static boolean canTransliterate() { + if (!BuildConfig.DEBUG) + return false; + + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) + return false; + + try { + Transliterator.getInstance("Any-Latin"); + return true; + } catch (Throwable ex) { + return false; + } + } + + static String transliterate(Context context, String text) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) + return text; + + SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); + boolean notify_transliterate = prefs.getBoolean("notify_transliterate", false); + if (!notify_transliterate) + return text; + + try { + Transliterator t = Transliterator.getInstance("Any-Latin"); + text = t.transliterate(text); + String normalized = Normalizer.normalize(text, Normalizer.Form.NFD); + text = normalized.replaceAll("\\p{InCombiningDiacriticalMarks}+", ""); + } catch (Throwable ex) { + Log.w(ex); + } + + return text; + } + static ConversationActions getConversationActions( Context context, String[] texts, boolean replies, boolean outgoing, long time) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) diff --git a/app/src/main/res/layout/fragment_options_notifications.xml b/app/src/main/res/layout/fragment_options_notifications.xml index df0a557300..1399b9d9d0 100644 --- a/app/src/main/res/layout/fragment_options_notifications.xml +++ b/app/src/main/res/layout/fragment_options_notifications.xml @@ -619,6 +619,17 @@ app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/swNotifyPreviewOnly" /> + + Show message preview in notifications Preview all text Show notifications with a preview text only + Transliterate Notification actions Trash Spam