Added Gravatar support

pull/172/head
M66B 6 years ago
parent 0b16601726
commit 3b192301a3

@ -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_RULES = BuildConfig.APPLICATION_ID + ".EDIT_RULES";
static final String ACTION_EDIT_RULE = BuildConfig.APPLICATION_ID + ".EDIT_RULE"; 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 private static final long EXIT_DELAY = 2500L; // milliseconds
static final long UPDATE_INTERVAL = (BuildConfig.BETA_RELEASE ? 4 : 12) * 3600 * 1000L; // 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); URL latest = new URL(BuildConfig.GITHUB_LATEST_API);
urlConnection = (HttpsURLConnection) latest.openConnection(); urlConnection = (HttpsURLConnection) latest.openConnection();
urlConnection.setRequestMethod("GET"); urlConnection.setRequestMethod("GET");
urlConnection.setReadTimeout(UPDATE_TIMEOUT);
urlConnection.setConnectTimeout(UPDATE_TIMEOUT);
urlConnection.setDoOutput(false); urlConnection.setDoOutput(false);
urlConnection.connect(); urlConnection.connect();

@ -34,7 +34,10 @@ import android.provider.ContactsContract;
import androidx.preference.PreferenceManager; import androidx.preference.PreferenceManager;
import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Date; import java.util.Date;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
@ -57,7 +60,8 @@ public class ContactInfo {
private static final ExecutorService executor = private static final ExecutorService executor =
Helper.getBackgroundExecutor(1, "contact"); 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() { 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; boolean identicon = false;
if (info.bitmap == null) { if (info.bitmap == null) {
int dp = Helper.dp2pixels(context, 96); int dp = Helper.dp2pixels(context, 96);

@ -316,9 +316,9 @@ public class EmailProvider {
Log.i("Fetching " + url); Log.i("Fetching " + url);
request = (HttpURLConnection) url.openConnection(); request = (HttpURLConnection) url.openConnection();
request.setRequestMethod("GET");
request.setReadTimeout(ISPDB_TIMEOUT); request.setReadTimeout(ISPDB_TIMEOUT);
request.setConnectTimeout(ISPDB_TIMEOUT); request.setConnectTimeout(ISPDB_TIMEOUT);
request.setRequestMethod("GET");
request.setDoInput(true); request.setDoInput(true);
request.connect(); request.connect();

@ -382,9 +382,9 @@ public class FragmentOAuth extends FragmentBase {
Log.i("Fetching " + url); Log.i("Fetching " + url);
HttpURLConnection request = (HttpURLConnection) url.openConnection(); HttpURLConnection request = (HttpURLConnection) url.openConnection();
request.setRequestMethod("GET");
request.setReadTimeout(OAUTH_TIMEOUT); request.setReadTimeout(OAUTH_TIMEOUT);
request.setConnectTimeout(OAUTH_TIMEOUT); request.setConnectTimeout(OAUTH_TIMEOUT);
request.setRequestMethod("GET");
request.setDoInput(true); request.setDoInput(true);
request.setRequestProperty("Authorization", "Bearer " + token); request.setRequestProperty("Authorization", "Bearer " + token);
request.setRequestProperty("Accept", "application/json"); request.setRequestProperty("Accept", "application/json");
@ -421,9 +421,9 @@ public class FragmentOAuth extends FragmentBase {
Log.i("Fetching " + url); Log.i("Fetching " + url);
HttpURLConnection request = (HttpURLConnection) url.openConnection(); HttpURLConnection request = (HttpURLConnection) url.openConnection();
request.setRequestMethod("GET");
request.setReadTimeout(OAUTH_TIMEOUT); request.setReadTimeout(OAUTH_TIMEOUT);
request.setConnectTimeout(OAUTH_TIMEOUT); request.setConnectTimeout(OAUTH_TIMEOUT);
request.setRequestMethod("GET");
request.setDoInput(true); request.setDoInput(true);
request.setRequestProperty("Authorization", "Bearer " + token); request.setRequestProperty("Authorization", "Bearer " + token);
request.setRequestProperty("Content-Type", "application/json"); request.setRequestProperty("Content-Type", "application/json");

@ -44,7 +44,7 @@ public class FragmentOptions extends FragmentBase {
static String[] OPTIONS_RESTART = new String[]{ static String[] OPTIONS_RESTART = new String[]{
"subscriptions", "subscriptions",
"landscape", "landscape3", "startup", "cards", "indentation", "date", "threading", "highlight_unread", "color_stripe", "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", "name_email", "distinguish_contacts", "authentication",
"subject_top", "font_size_sender", "font_size_subject", "subject_italic", "subject_ellipsize", "subject_top", "font_size_sender", "font_size_subject", "subject_italic", "subject_ellipsize",
"flags", "flags_background", "preview", "preview_italic", "preview_lines", "flags", "flags_background", "preview", "preview_italic", "preview_lines",

@ -62,6 +62,7 @@ public class FragmentOptionsDisplay extends FragmentBase implements SharedPrefer
private SwitchCompat swHighlightUnread; private SwitchCompat swHighlightUnread;
private SwitchCompat swColorStripe; private SwitchCompat swColorStripe;
private SwitchCompat swAvatars; private SwitchCompat swAvatars;
private SwitchCompat swGravatars;
private SwitchCompat swGeneratedIcons; private SwitchCompat swGeneratedIcons;
private SwitchCompat swIdenticons; private SwitchCompat swIdenticons;
private SwitchCompat swCircular; private SwitchCompat swCircular;
@ -97,7 +98,7 @@ public class FragmentOptionsDisplay extends FragmentBase implements SharedPrefer
private final static String[] RESET_OPTIONS = new String[]{ private final static String[] RESET_OPTIONS = new String[]{
"theme", "landscape", "landscape3", "startup", "cards", "indentation", "date", "threading", "highlight_unread", "color_stripe", "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", "name_email", "distinguish_contacts", "authentication",
"subject_top", "font_size_sender", "font_size_subject", "subject_italic", "subject_ellipsize", "subject_top", "font_size_sender", "font_size_subject", "subject_italic", "subject_ellipsize",
"flags", "flags_background", "preview", "preview_italic", "preview_lines", "addresses", "attachments_alt", "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); swHighlightUnread = view.findViewById(R.id.swHighlightUnread);
swColorStripe = view.findViewById(R.id.swColorStripe); swColorStripe = view.findViewById(R.id.swColorStripe);
swAvatars = view.findViewById(R.id.swAvatars); swAvatars = view.findViewById(R.id.swAvatars);
swGravatars = view.findViewById(R.id.swGravatars);
swGeneratedIcons = view.findViewById(R.id.swGeneratedIcons); swGeneratedIcons = view.findViewById(R.id.swGeneratedIcons);
swIdenticons = view.findViewById(R.id.swIdenticons); swIdenticons = view.findViewById(R.id.swIdenticons);
swCircular = view.findViewById(R.id.swCircular); 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() { swGeneratedIcons.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override @Override
public void onCheckedChanged(CompoundButton compoundButton, boolean checked) { public void onCheckedChanged(CompoundButton compoundButton, boolean checked) {
prefs.edit().putBoolean("generated_icons", checked).apply(); prefs.edit().putBoolean("generated_icons", checked).apply();
swIdenticons.setEnabled(checked); swIdenticons.setEnabled(checked);
sbSaturation.setEnabled(swGeneratedIcons.isChecked()); sbSaturation.setEnabled(checked);
sbBrightness.setEnabled(swGeneratedIcons.isChecked()); sbBrightness.setEnabled(checked);
sbThreshold.setEnabled(swGeneratedIcons.isChecked()); sbThreshold.setEnabled(checked);
ContactInfo.clearCache(); ContactInfo.clearCache();
} }
}); });
@ -588,6 +598,7 @@ public class FragmentOptionsDisplay extends FragmentBase implements SharedPrefer
swHighlightUnread.setChecked(prefs.getBoolean("highlight_unread", false)); swHighlightUnread.setChecked(prefs.getBoolean("highlight_unread", false));
swColorStripe.setChecked(prefs.getBoolean("color_stripe", true)); swColorStripe.setChecked(prefs.getBoolean("color_stripe", true));
swAvatars.setChecked(prefs.getBoolean("avatars", true)); swAvatars.setChecked(prefs.getBoolean("avatars", true));
swGravatars.setChecked(prefs.getBoolean("gravatars", false));
swGeneratedIcons.setChecked(prefs.getBoolean("generated_icons", true)); swGeneratedIcons.setChecked(prefs.getBoolean("generated_icons", true));
swIdenticons.setChecked(prefs.getBoolean("identicons", false)); swIdenticons.setChecked(prefs.getBoolean("identicons", false));
swIdenticons.setEnabled(swGeneratedIcons.isChecked()); swIdenticons.setEnabled(swGeneratedIcons.isChecked());

@ -707,6 +707,10 @@ public class Helper {
return sha("SHA-256", data); 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 { static String sha(String digest, byte[] data) throws NoSuchAlgorithmException {
byte[] bytes = MessageDigest.getInstance(digest).digest(data); byte[] bytes = MessageDigest.getInstance(digest).digest(data);
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();

@ -38,6 +38,8 @@ import javax.net.ssl.HttpsURLConnection;
public class IPInfo { public class IPInfo {
private static Map<InetAddress, String> hostOrganization = new HashMap<>(); private static Map<InetAddress, String> hostOrganization = new HashMap<>();
private final static int FETCH_TIMEOUT = 15 * 1000; // milliseconds
static String[] getOrganization(Uri uri, Context context) throws IOException, ParseException { static String[] getOrganization(Uri uri, Context context) throws IOException, ParseException {
if ("mailto".equals(uri.getScheme())) { if ("mailto".equals(uri.getScheme())) {
MailTo email = MailTo.parse(uri.toString()); MailTo email = MailTo.parse(uri.toString());
@ -67,7 +69,7 @@ public class IPInfo {
Log.i("GET " + url); Log.i("GET " + url);
HttpsURLConnection connection = (HttpsURLConnection) url.openConnection(); HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
connection.setRequestMethod("GET"); connection.setRequestMethod("GET");
connection.setReadTimeout(15 * 1000); connection.setReadTimeout(FETCH_TIMEOUT);
connection.connect(); connection.connect();
try (BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()))) { try (BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()))) {
String organization = reader.readLine(); String organization = reader.readLine();

@ -72,6 +72,7 @@ class ImageHelper {
private static final ExecutorService executor = private static final ExecutorService executor =
Helper.getBackgroundExecutor(1, "image"); Helper.getBackgroundExecutor(1, "image");
private static final int DOWNLOAD_TIMEOUT = 15 * 1000; // milliseconds
private static final int MAX_REDIRECTS = 10; private static final int MAX_REDIRECTS = 10;
private static final long FIT_DRAWABLE_TIMEOUT = 10 * 1000L; // milliseconds private static final long FIT_DRAWABLE_TIMEOUT = 10 * 1000L; // milliseconds
@ -492,6 +493,8 @@ class ImageHelper {
urlConnection = (HttpURLConnection) url.openConnection(); urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setRequestMethod("GET"); urlConnection.setRequestMethod("GET");
urlConnection.setDoOutput(false); urlConnection.setDoOutput(false);
urlConnection.setReadTimeout(DOWNLOAD_TIMEOUT);
urlConnection.setConnectTimeout(DOWNLOAD_TIMEOUT);
urlConnection.setInstanceFollowRedirects(true); urlConnection.setInstanceFollowRedirects(true);
urlConnection.connect(); urlConnection.connect();

@ -191,6 +191,17 @@
app:layout_constraintTop_toBottomOf="@id/swColorStripe" app:layout_constraintTop_toBottomOf="@id/swColorStripe"
app:switchPadding="12dp" /> app:switchPadding="12dp" />
<androidx.appcompat.widget.SwitchCompat
android:id="@+id/swGravatars"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:text="@string/title_advanced_gravatars"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/swAvatars"
app:switchPadding="12dp" />
<androidx.appcompat.widget.SwitchCompat <androidx.appcompat.widget.SwitchCompat
android:id="@+id/swGeneratedIcons" android:id="@+id/swGeneratedIcons"
android:layout_width="0dp" android:layout_width="0dp"
@ -200,7 +211,7 @@
android:text="@string/title_advanced_generated_icons" android:text="@string/title_advanced_generated_icons"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/swAvatars" app:layout_constraintTop_toBottomOf="@id/swGravatars"
app:switchPadding="12dp" /> app:switchPadding="12dp" />
<androidx.appcompat.widget.SwitchCompat <androidx.appcompat.widget.SwitchCompat
@ -223,7 +234,8 @@
android:text="@string/title_advanced_circular" android:text="@string/title_advanced_circular"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/swIdenticons" app:layout_constraintTop_toBottomOf="@id/swIdenticons
"
app:switchPadding="12dp" /> app:switchPadding="12dp" />
<ImageView <ImageView

@ -290,6 +290,7 @@
<string name="title_advanced_distinguish_contacts">Underline the sender when the sender is known as local \'to\' contact</string> <string name="title_advanced_distinguish_contacts">Underline the sender when the sender is known as local \'to\' contact</string>
<string name="title_advanced_color_stripe">Show color stripe</string> <string name="title_advanced_color_stripe">Show color stripe</string>
<string name="title_advanced_avatars">Show contact photos</string> <string name="title_advanced_avatars">Show contact photos</string>
<string name="title_advanced_gravatars">Show Gravatars</string>
<string name="title_advanced_generated_icons">Show generated icons</string> <string name="title_advanced_generated_icons">Show generated icons</string>
<string name="title_advanced_identicons">Show identicons</string> <string name="title_advanced_identicons">Show identicons</string>
<string name="title_advanced_circular">Show round icons</string> <string name="title_advanced_circular">Show round icons</string>

Loading…
Cancel
Save