diff --git a/app/src/main/java/eu/faircode/email/ContactInfo.java b/app/src/main/java/eu/faircode/email/ContactInfo.java index 6f9deafeb9..63f29520db 100644 --- a/app/src/main/java/eu/faircode/email/ContactInfo.java +++ b/app/src/main/java/eu/faircode/email/ContactInfo.java @@ -49,17 +49,21 @@ import java.io.OutputStream; import java.io.UnsupportedEncodingException; import java.net.ConnectException; import java.net.HttpURLConnection; -import java.net.SocketTimeoutException; import java.net.URL; import java.net.UnknownHostException; import java.nio.charset.StandardCharsets; import java.security.cert.CertificateException; +import java.util.ArrayList; import java.util.Date; import java.util.HashMap; +import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.concurrent.Callable; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; +import java.util.concurrent.Future; import javax.mail.Address; import javax.mail.internet.InternetAddress; @@ -81,9 +85,12 @@ public class ContactInfo { private static final Map emailContactInfo = new HashMap<>(); private static final Map emailGravatar = new HashMap<>(); - private static final ExecutorService executor = + private static final ExecutorService executorLookup = Helper.getBackgroundExecutor(1, "contact"); + private static final ExecutorService executorFavicon = + Helper.getBackgroundExecutor(0, "favicon"); + private static final int GRAVATAR_TIMEOUT = 5 * 1000; // milliseconds private static final int FAVICON_CONNECT_TIMEOUT = 5 * 1000; // milliseconds private static final int FAVICON_READ_TIMEOUT = 10 * 1000; // milliseconds @@ -133,7 +140,7 @@ public class ContactInfo { final File dir = new File(context.getCacheDir(), "favicons"); - executor.submit(new Runnable() { + executorFavicon.submit(new Runnable() { @Override public void run() { try { @@ -305,51 +312,56 @@ public class ContactInfo { else info.bitmap = BitmapFactory.decodeFile(file.getAbsolutePath()); else { - URL base = new URL("https://" + domain); - URL www = new URL("https://www." + domain); + final URL base = new URL("https://" + domain); + final URL www = new URL("https://www." + domain); - try { - info.bitmap = parseFavicon(base); - } catch (IOException ex) { - if (ex instanceof SocketTimeoutException) - throw ex; - Log.i("Favicon ex=" + ex.getClass().getName() + " " + ex.getMessage()); - } + List> futures = new ArrayList<>(); - if (info.bitmap == null) - try { - info.bitmap = parseFavicon(www); - } catch (IOException ex) { - if (ex instanceof SocketTimeoutException) - throw ex; - Log.i("Favicon ex=" + ex.getClass().getName() + " " + ex.getMessage()); + futures.add(executorFavicon.submit(new Callable() { + @Override + public Bitmap call() throws Exception { + return parseFavicon(base); } + })); - if (info.bitmap == null) - try { - info.bitmap = getFavicon(new URL(base, "favicon.ico")); - } catch (IOException ex) { - if (ex instanceof SocketTimeoutException) - throw ex; - Log.i("Favicon ex=" + ex.getClass().getName() + " " + ex.getMessage()); + futures.add(executorFavicon.submit(new Callable() { + @Override + public Bitmap call() throws Exception { + return parseFavicon(www); } + })); - if (info.bitmap == null) + futures.add(executorFavicon.submit(new Callable() { + @Override + public Bitmap call() throws Exception { + return getFavicon(new URL(base, "favicon.ico")); + } + })); + + futures.add(executorFavicon.submit(new Callable() { + @Override + public Bitmap call() throws Exception { + return getFavicon(new URL(www, "favicon.ico")); + } + })); + + Throwable ex = null; + for (Future future : futures) try { - info.bitmap = getFavicon(new URL(www, "favicon.ico")); - } catch (IOException ex) { - if (ex instanceof SocketTimeoutException) - throw ex; - Log.i("Favicon ex=" + ex.getClass().getName() + " " + ex.getMessage()); + info.bitmap = future.get(); + } catch (ExecutionException exex) { + ex = exex.getCause(); + } catch (Throwable exex) { + ex = exex; } - // Add to cache if (info.bitmap == null) - throw new FileNotFoundException("decode"); - else - try (OutputStream os = new BufferedOutputStream(new FileOutputStream(file))) { - info.bitmap.compress(Bitmap.CompressFormat.PNG, 90, os); - } + throw ex; + + // Add to cache + try (OutputStream os = new BufferedOutputStream(new FileOutputStream(file))) { + info.bitmap.compress(Bitmap.CompressFormat.PNG, 90, os); + } } } catch (Throwable ex) { if (isRecoverable(ex)) @@ -440,6 +452,7 @@ public class ContactInfo { return null; } + @NonNull private static Bitmap getFavicon(URL url) throws IOException { Log.i("GET favicon " + url); @@ -451,7 +464,11 @@ public class ContactInfo { connection.connect(); try { - return BitmapFactory.decodeStream(connection.getInputStream()); + Bitmap bitmap = BitmapFactory.decodeStream(connection.getInputStream()); + if (bitmap == null) + throw new FileNotFoundException("decodeStream"); + else + return bitmap; } finally { connection.disconnect(); } @@ -481,7 +498,7 @@ public class ContactInfo { @Override public void onChange(boolean selfChange, Uri uri) { Log.i("Contact changed uri=" + uri); - executor.submit(new Runnable() { + executorLookup.submit(new Runnable() { @Override public void run() { try { @@ -494,7 +511,7 @@ public class ContactInfo { } }; - executor.submit(new Runnable() { + executorLookup.submit(new Runnable() { @Override public void run() { try {