diff --git a/app/src/main/java/eu/faircode/email/ActivityView.java b/app/src/main/java/eu/faircode/email/ActivityView.java index 9c0662958c..b53737cd64 100644 --- a/app/src/main/java/eu/faircode/email/ActivityView.java +++ b/app/src/main/java/eu/faircode/email/ActivityView.java @@ -125,6 +125,7 @@ public class ActivityView extends ActivityBilling implements FragmentManager.OnB static final String ACTION_EDIT_RULES = BuildConfig.APPLICATION_ID + ".EDIT_RULES"; static final String ACTION_EDIT_RULE = BuildConfig.APPLICATION_ID + ".EDIT_RULE"; + private static final int UPDATE_TIMEOUT = 15 * 1000; // milliseconds private static final long EXIT_DELAY = 2500L; // milliseconds static final long UPDATE_INTERVAL = (BuildConfig.BETA_RELEASE ? 4 : 12) * 3600 * 1000L; // milliseconds @@ -720,6 +721,8 @@ public class ActivityView extends ActivityBilling implements FragmentManager.OnB URL latest = new URL(BuildConfig.GITHUB_LATEST_API); urlConnection = (HttpsURLConnection) latest.openConnection(); urlConnection.setRequestMethod("GET"); + urlConnection.setReadTimeout(UPDATE_TIMEOUT); + urlConnection.setConnectTimeout(UPDATE_TIMEOUT); urlConnection.setDoOutput(false); urlConnection.connect(); diff --git a/app/src/main/java/eu/faircode/email/ContactInfo.java b/app/src/main/java/eu/faircode/email/ContactInfo.java index 00e4b028b8..63d5de520e 100644 --- a/app/src/main/java/eu/faircode/email/ContactInfo.java +++ b/app/src/main/java/eu/faircode/email/ContactInfo.java @@ -34,7 +34,10 @@ import android.provider.ContactsContract; import androidx.preference.PreferenceManager; +import java.io.IOException; import java.io.InputStream; +import java.net.HttpURLConnection; +import java.net.URL; import java.util.Date; import java.util.HashMap; import java.util.Map; @@ -57,7 +60,8 @@ public class ContactInfo { private static final ExecutorService executor = Helper.getBackgroundExecutor(1, "contact"); - private static final long CACHE_CONTACT_DURATION = 120 * 1000L; + private static final int GRAVATAR_TIMEOUT = 15 * 1000; // milliseconds + private static final long CACHE_CONTACT_DURATION = 120 * 1000L; // milliseconds private ContactInfo() { } @@ -162,6 +166,35 @@ public class ContactInfo { } } + if (info.bitmap == null) { + boolean gravatars = prefs.getBoolean("gravatars", false); + if (gravatars) { + HttpURLConnection urlConnection = null; + try { + String hash = Helper.md5(address.getAddress().getBytes()); + URL url = new URL("https://www.gravatar.com/avatar/" + hash+"?d=404"); + + urlConnection = (HttpURLConnection) url.openConnection(); + urlConnection.setRequestMethod("GET"); + urlConnection.setDoOutput(false); + urlConnection.setReadTimeout(GRAVATAR_TIMEOUT); + urlConnection.setConnectTimeout(GRAVATAR_TIMEOUT); + urlConnection.connect(); + + int status = urlConnection.getResponseCode(); + if (status != HttpURLConnection.HTTP_OK) + throw new IOException("HTTP status=" + status); + + info.bitmap = BitmapFactory.decodeStream(urlConnection.getInputStream()); + } catch (Throwable ex) { + Log.w(ex); + } finally { + if (urlConnection != null) + urlConnection.disconnect(); + } + } + } + boolean identicon = false; if (info.bitmap == null) { int dp = Helper.dp2pixels(context, 96); diff --git a/app/src/main/java/eu/faircode/email/EmailProvider.java b/app/src/main/java/eu/faircode/email/EmailProvider.java index 331709c799..20111743cd 100644 --- a/app/src/main/java/eu/faircode/email/EmailProvider.java +++ b/app/src/main/java/eu/faircode/email/EmailProvider.java @@ -316,9 +316,9 @@ public class EmailProvider { Log.i("Fetching " + url); request = (HttpURLConnection) url.openConnection(); + request.setRequestMethod("GET"); request.setReadTimeout(ISPDB_TIMEOUT); request.setConnectTimeout(ISPDB_TIMEOUT); - request.setRequestMethod("GET"); request.setDoInput(true); request.connect(); diff --git a/app/src/main/java/eu/faircode/email/FragmentOAuth.java b/app/src/main/java/eu/faircode/email/FragmentOAuth.java index 01375fcf9f..8a69099f43 100644 --- a/app/src/main/java/eu/faircode/email/FragmentOAuth.java +++ b/app/src/main/java/eu/faircode/email/FragmentOAuth.java @@ -382,9 +382,9 @@ public class FragmentOAuth extends FragmentBase { Log.i("Fetching " + url); HttpURLConnection request = (HttpURLConnection) url.openConnection(); + request.setRequestMethod("GET"); request.setReadTimeout(OAUTH_TIMEOUT); request.setConnectTimeout(OAUTH_TIMEOUT); - request.setRequestMethod("GET"); request.setDoInput(true); request.setRequestProperty("Authorization", "Bearer " + token); request.setRequestProperty("Accept", "application/json"); @@ -421,9 +421,9 @@ public class FragmentOAuth extends FragmentBase { Log.i("Fetching " + url); HttpURLConnection request = (HttpURLConnection) url.openConnection(); + request.setRequestMethod("GET"); request.setReadTimeout(OAUTH_TIMEOUT); request.setConnectTimeout(OAUTH_TIMEOUT); - request.setRequestMethod("GET"); request.setDoInput(true); request.setRequestProperty("Authorization", "Bearer " + token); request.setRequestProperty("Content-Type", "application/json"); diff --git a/app/src/main/java/eu/faircode/email/FragmentOptions.java b/app/src/main/java/eu/faircode/email/FragmentOptions.java index 1047f9a8b3..1bdd22178b 100644 --- a/app/src/main/java/eu/faircode/email/FragmentOptions.java +++ b/app/src/main/java/eu/faircode/email/FragmentOptions.java @@ -44,7 +44,7 @@ public class FragmentOptions extends FragmentBase { static String[] OPTIONS_RESTART = new String[]{ "subscriptions", "landscape", "landscape3", "startup", "cards", "indentation", "date", "threading", "highlight_unread", "color_stripe", - "avatars", "generated_icons", "identicons", "circular", "saturation", "brightness", "threshold", + "avatars", "gravatars", "generated_icons", "identicons", "circular", "saturation", "brightness", "threshold", "name_email", "distinguish_contacts", "authentication", "subject_top", "font_size_sender", "font_size_subject", "subject_italic", "subject_ellipsize", "flags", "flags_background", "preview", "preview_italic", "preview_lines", diff --git a/app/src/main/java/eu/faircode/email/FragmentOptionsDisplay.java b/app/src/main/java/eu/faircode/email/FragmentOptionsDisplay.java index d9e3ba6948..6362594f18 100644 --- a/app/src/main/java/eu/faircode/email/FragmentOptionsDisplay.java +++ b/app/src/main/java/eu/faircode/email/FragmentOptionsDisplay.java @@ -62,6 +62,7 @@ public class FragmentOptionsDisplay extends FragmentBase implements SharedPrefer private SwitchCompat swHighlightUnread; private SwitchCompat swColorStripe; private SwitchCompat swAvatars; + private SwitchCompat swGravatars; private SwitchCompat swGeneratedIcons; private SwitchCompat swIdenticons; private SwitchCompat swCircular; @@ -97,7 +98,7 @@ public class FragmentOptionsDisplay extends FragmentBase implements SharedPrefer private final static String[] RESET_OPTIONS = new String[]{ "theme", "landscape", "landscape3", "startup", "cards", "indentation", "date", "threading", "highlight_unread", "color_stripe", - "avatars", "generated_icons", "identicons", "circular", "saturation", "brightness", "threshold", + "avatars", "gravatars", "generated_icons", "identicons", "circular", "saturation", "brightness", "threshold", "name_email", "distinguish_contacts", "authentication", "subject_top", "font_size_sender", "font_size_subject", "subject_italic", "subject_ellipsize", "flags", "flags_background", "preview", "preview_italic", "preview_lines", "addresses", "attachments_alt", @@ -126,6 +127,7 @@ public class FragmentOptionsDisplay extends FragmentBase implements SharedPrefer swHighlightUnread = view.findViewById(R.id.swHighlightUnread); swColorStripe = view.findViewById(R.id.swColorStripe); swAvatars = view.findViewById(R.id.swAvatars); + swGravatars = view.findViewById(R.id.swGravatars); swGeneratedIcons = view.findViewById(R.id.swGeneratedIcons); swIdenticons = view.findViewById(R.id.swIdenticons); swCircular = view.findViewById(R.id.swCircular); @@ -251,14 +253,22 @@ public class FragmentOptionsDisplay extends FragmentBase implements SharedPrefer } }); + swGravatars.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { + @Override + public void onCheckedChanged(CompoundButton compoundButton, boolean checked) { + prefs.edit().putBoolean("gravatars", checked).apply(); + ContactInfo.clearCache(); + } + }); + swGeneratedIcons.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton compoundButton, boolean checked) { prefs.edit().putBoolean("generated_icons", checked).apply(); swIdenticons.setEnabled(checked); - sbSaturation.setEnabled(swGeneratedIcons.isChecked()); - sbBrightness.setEnabled(swGeneratedIcons.isChecked()); - sbThreshold.setEnabled(swGeneratedIcons.isChecked()); + sbSaturation.setEnabled(checked); + sbBrightness.setEnabled(checked); + sbThreshold.setEnabled(checked); ContactInfo.clearCache(); } }); @@ -588,6 +598,7 @@ public class FragmentOptionsDisplay extends FragmentBase implements SharedPrefer swHighlightUnread.setChecked(prefs.getBoolean("highlight_unread", false)); swColorStripe.setChecked(prefs.getBoolean("color_stripe", true)); swAvatars.setChecked(prefs.getBoolean("avatars", true)); + swGravatars.setChecked(prefs.getBoolean("gravatars", false)); swGeneratedIcons.setChecked(prefs.getBoolean("generated_icons", true)); swIdenticons.setChecked(prefs.getBoolean("identicons", false)); swIdenticons.setEnabled(swGeneratedIcons.isChecked()); diff --git a/app/src/main/java/eu/faircode/email/Helper.java b/app/src/main/java/eu/faircode/email/Helper.java index b99fc98917..cd6167f395 100644 --- a/app/src/main/java/eu/faircode/email/Helper.java +++ b/app/src/main/java/eu/faircode/email/Helper.java @@ -707,6 +707,10 @@ public class Helper { return sha("SHA-256", data); } + static String md5(byte[] data) throws NoSuchAlgorithmException { + return sha("MD5", data); + } + static String sha(String digest, byte[] data) throws NoSuchAlgorithmException { byte[] bytes = MessageDigest.getInstance(digest).digest(data); StringBuilder sb = new StringBuilder(); diff --git a/app/src/main/java/eu/faircode/email/IPInfo.java b/app/src/main/java/eu/faircode/email/IPInfo.java index e4a649c4f5..1b3597d27a 100644 --- a/app/src/main/java/eu/faircode/email/IPInfo.java +++ b/app/src/main/java/eu/faircode/email/IPInfo.java @@ -38,6 +38,8 @@ import javax.net.ssl.HttpsURLConnection; public class IPInfo { private static Map hostOrganization = new HashMap<>(); + private final static int FETCH_TIMEOUT = 15 * 1000; // milliseconds + static String[] getOrganization(Uri uri, Context context) throws IOException, ParseException { if ("mailto".equals(uri.getScheme())) { MailTo email = MailTo.parse(uri.toString()); @@ -67,7 +69,7 @@ public class IPInfo { Log.i("GET " + url); HttpsURLConnection connection = (HttpsURLConnection) url.openConnection(); connection.setRequestMethod("GET"); - connection.setReadTimeout(15 * 1000); + connection.setReadTimeout(FETCH_TIMEOUT); connection.connect(); try (BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()))) { String organization = reader.readLine(); diff --git a/app/src/main/java/eu/faircode/email/ImageHelper.java b/app/src/main/java/eu/faircode/email/ImageHelper.java index 0202fb4e85..6903356a39 100644 --- a/app/src/main/java/eu/faircode/email/ImageHelper.java +++ b/app/src/main/java/eu/faircode/email/ImageHelper.java @@ -72,6 +72,7 @@ class ImageHelper { private static final ExecutorService executor = Helper.getBackgroundExecutor(1, "image"); + private static final int DOWNLOAD_TIMEOUT = 15 * 1000; // milliseconds private static final int MAX_REDIRECTS = 10; private static final long FIT_DRAWABLE_TIMEOUT = 10 * 1000L; // milliseconds @@ -492,6 +493,8 @@ class ImageHelper { urlConnection = (HttpURLConnection) url.openConnection(); urlConnection.setRequestMethod("GET"); urlConnection.setDoOutput(false); + urlConnection.setReadTimeout(DOWNLOAD_TIMEOUT); + urlConnection.setConnectTimeout(DOWNLOAD_TIMEOUT); urlConnection.setInstanceFollowRedirects(true); urlConnection.connect(); diff --git a/app/src/main/res/layout/fragment_options_display.xml b/app/src/main/res/layout/fragment_options_display.xml index 447dc8fc26..0fe929ae5a 100644 --- a/app/src/main/res/layout/fragment_options_display.xml +++ b/app/src/main/res/layout/fragment_options_display.xml @@ -191,6 +191,17 @@ app:layout_constraintTop_toBottomOf="@id/swColorStripe" app:switchPadding="12dp" /> + + Underline the sender when the sender is known as local \'to\' contact Show color stripe Show contact photos + Show Gravatars Show generated icons Show identicons Show round icons