use common trust manager in quicksy

Daniel Gultsch created

Change summary

src/quicksy/java/eu/siacs/conversations/services/QuickConversationsService.java | 402 
1 file changed, 224 insertions(+), 178 deletions(-)

Detailed changes

src/quicksy/java/eu/siacs/conversations/services/QuickConversationsService.java 🔗

@@ -1,21 +1,17 @@
 package eu.siacs.conversations.services;
 
-
 import static eu.siacs.conversations.utils.Random.SECURE_RANDOM;
 
 import android.content.Context;
 import android.content.Intent;
 import android.net.Uri;
-import android.os.Build;
 import android.os.Bundle;
 import android.os.SystemClock;
 import android.util.Log;
-
 import com.google.common.collect.ImmutableMap;
-
+import de.gultsch.common.TrustManagers;
 import eu.siacs.conversations.Config;
 import eu.siacs.conversations.android.PhoneNumberContact;
-import eu.siacs.conversations.crypto.TrustManagers;
 import eu.siacs.conversations.crypto.sasl.Plain;
 import eu.siacs.conversations.entities.Account;
 import eu.siacs.conversations.entities.Contact;
@@ -30,11 +26,8 @@ import eu.siacs.conversations.utils.TLSSocketFactory;
 import eu.siacs.conversations.xml.Element;
 import eu.siacs.conversations.xml.Namespace;
 import eu.siacs.conversations.xmpp.Jid;
-
 import im.conversations.android.xmpp.model.stanza.Iq;
-
 import io.michaelrocks.libphonenumber.android.Phonenumber;
-
 import java.io.BufferedWriter;
 import java.io.IOException;
 import java.io.OutputStream;
@@ -63,7 +56,6 @@ import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicInteger;
-
 import javax.net.ssl.HttpsURLConnection;
 import javax.net.ssl.SSLException;
 import javax.net.ssl.SSLHandshakeException;
@@ -73,7 +65,6 @@ import javax.net.ssl.X509TrustManager;
 
 public class QuickConversationsService extends AbstractQuickConversationsService {
 
-
     public static final int API_ERROR_OTHER = -1;
     public static final int API_ERROR_UNKNOWN_HOST = -2;
     public static final int API_ERROR_CONNECT = -3;
@@ -87,8 +78,10 @@ public class QuickConversationsService extends AbstractQuickConversationsService
 
     private static final String BASE_URL = "https://" + API_DOMAIN;
 
-    private final Set<OnVerificationRequested> mOnVerificationRequested = Collections.newSetFromMap(new WeakHashMap<>());
-    private final Set<OnVerification> mOnVerification = Collections.newSetFromMap(new WeakHashMap<>());
+    private final Set<OnVerificationRequested> mOnVerificationRequested =
+            Collections.newSetFromMap(new WeakHashMap<>());
+    private final Set<OnVerification> mOnVerification =
+            Collections.newSetFromMap(new WeakHashMap<>());
 
     private final AtomicBoolean mVerificationInProgress = new AtomicBoolean(false);
     private final AtomicBoolean mVerificationRequestInProgress = new AtomicBoolean(false);
@@ -97,7 +90,8 @@ public class QuickConversationsService extends AbstractQuickConversationsService
 
     private Attempt mLastSyncAttempt = Attempt.NULL;
 
-    private final SerialSingleThreadExecutor mSerialSingleThreadExecutor = new SerialSingleThreadExecutor(QuickConversationsService.class.getSimpleName());
+    private final SerialSingleThreadExecutor mSerialSingleThreadExecutor =
+            new SerialSingleThreadExecutor(QuickConversationsService.class.getSimpleName());
 
     QuickConversationsService(XmppConnectionService xmppConnectionService) {
         super(xmppConnectionService);
@@ -105,19 +99,22 @@ public class QuickConversationsService extends AbstractQuickConversationsService
 
     private static long retryAfter(HttpURLConnection connection) {
         try {
-            return SystemClock.elapsedRealtime() + (Long.parseLong(connection.getHeaderField("Retry-After")) * 1000L);
+            return SystemClock.elapsedRealtime()
+                    + (Long.parseLong(connection.getHeaderField("Retry-After")) * 1000L);
         } catch (Exception e) {
             return 0;
         }
     }
 
-    public void addOnVerificationRequestedListener(OnVerificationRequested onVerificationRequested) {
+    public void addOnVerificationRequestedListener(
+            OnVerificationRequested onVerificationRequested) {
         synchronized (mOnVerificationRequested) {
             mOnVerificationRequested.add(onVerificationRequested);
         }
     }
 
-    public void removeOnVerificationRequestedListener(OnVerificationRequested onVerificationRequested) {
+    public void removeOnVerificationRequestedListener(
+            OnVerificationRequested onVerificationRequested) {
         synchronized (mOnVerificationRequested) {
             mOnVerificationRequested.remove(onVerificationRequested);
         }
@@ -139,62 +136,63 @@ public class QuickConversationsService extends AbstractQuickConversationsService
         final String e164 = PhoneNumberUtilWrapper.normalize(service, phoneNumber);
         if (mVerificationRequestInProgress.compareAndSet(false, true)) {
             SmsRetrieverWrapper.start(service);
-            new Thread(() -> {
-                try {
-                    final URL url = new URL(BASE_URL + "/authentication/" + e164);
-                    final HttpURLConnection connection = (HttpURLConnection) url.openConnection();
-                    setBundledLetsEncrypt(service, connection);
-                    connection.setConnectTimeout(Config.SOCKET_TIMEOUT * 1000);
-                    connection.setReadTimeout(Config.SOCKET_TIMEOUT * 1000);
-                    setHeader(connection);
-                    final int code = connection.getResponseCode();
-                    if (code == 200) {
-                        createAccountAndWait(phoneNumber, 0L);
-                    } else if (code == 429) {
-                        createAccountAndWait(phoneNumber, retryAfter(connection));
-                    } else {
-                        synchronized (mOnVerificationRequested) {
-                            for (OnVerificationRequested onVerificationRequested : mOnVerificationRequested) {
-                                onVerificationRequested.onVerificationRequestFailed(code);
-                            }
-                        }
-                    }
-                } catch (IOException e) {
-                    final int code = getApiErrorCode(e);
-                    synchronized (mOnVerificationRequested) {
-                        for (OnVerificationRequested onVerificationRequested : mOnVerificationRequested) {
-                            onVerificationRequested.onVerificationRequestFailed(code);
-                        }
-                    }
-                } finally {
-                    mVerificationRequestInProgress.set(false);
-                }
-            }).start();
+            new Thread(
+                            () -> {
+                                try {
+                                    final URL url = new URL(BASE_URL + "/authentication/" + e164);
+                                    final HttpURLConnection connection =
+                                            (HttpURLConnection) url.openConnection();
+                                    setBundledLetsEncrypt(service, connection);
+                                    connection.setConnectTimeout(Config.SOCKET_TIMEOUT * 1000);
+                                    connection.setReadTimeout(Config.SOCKET_TIMEOUT * 1000);
+                                    setHeader(connection);
+                                    final int code = connection.getResponseCode();
+                                    if (code == 200) {
+                                        createAccountAndWait(phoneNumber, 0L);
+                                    } else if (code == 429) {
+                                        createAccountAndWait(phoneNumber, retryAfter(connection));
+                                    } else {
+                                        synchronized (mOnVerificationRequested) {
+                                            for (OnVerificationRequested onVerificationRequested :
+                                                    mOnVerificationRequested) {
+                                                onVerificationRequested.onVerificationRequestFailed(
+                                                        code);
+                                            }
+                                        }
+                                    }
+                                } catch (IOException e) {
+                                    final int code = getApiErrorCode(e);
+                                    synchronized (mOnVerificationRequested) {
+                                        for (OnVerificationRequested onVerificationRequested :
+                                                mOnVerificationRequested) {
+                                            onVerificationRequested.onVerificationRequestFailed(
+                                                    code);
+                                        }
+                                    }
+                                } finally {
+                                    mVerificationRequestInProgress.set(false);
+                                }
+                            })
+                    .start();
         }
     }
 
     private static void setBundledLetsEncrypt(
             final Context context, final HttpURLConnection connection) {
         if (connection instanceof HttpsURLConnection httpsURLConnection) {
-            final X509TrustManager trustManager;
-            if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.N) {
-                try {
-                    trustManager = TrustManagers.defaultWithBundledLetsEncrypt(context);
-                } catch (final NoSuchAlgorithmException
-                        | KeyStoreException
-                        | CertificateException
-                        | IOException e) {
-                    Log.e(Config.LOGTAG, "could not configured bundled LetsEncrypt", e);
-                    return;
-                }
-            } else {
-                return;
-            }
             final SSLSocketFactory socketFactory;
             try {
                 socketFactory =
-                        new TLSSocketFactory(new X509TrustManager[] {trustManager}, SECURE_RANDOM);
-            } catch (final KeyManagementException | NoSuchAlgorithmException e) {
+                        new TLSSocketFactory(
+                                new X509TrustManager[] {
+                                    TrustManagers.createForAndroidVersion(context)
+                                },
+                                SECURE_RANDOM);
+            } catch (final KeyManagementException
+                    | NoSuchAlgorithmException
+                    | KeyStoreException
+                    | CertificateException
+                    | IOException e) {
                 Log.e(Config.LOGTAG, "could not configured bundled LetsEncrypt", e);
                 return;
             }
@@ -211,7 +209,10 @@ public class QuickConversationsService extends AbstractQuickConversationsService
 
     private void createAccountAndWait(Phonenumber.PhoneNumber phoneNumber, final long timestamp) {
         String local = PhoneNumberUtilWrapper.normalize(service, phoneNumber);
-        Log.d(Config.LOGTAG, "requesting verification for " + PhoneNumberUtilWrapper.normalize(service, phoneNumber));
+        Log.d(
+                Config.LOGTAG,
+                "requesting verification for "
+                        + PhoneNumberUtilWrapper.normalize(service, phoneNumber));
         Jid jid = Jid.of(local, Config.QUICKSY_DOMAIN, null);
         Account account = AccountUtils.getFirst(service);
         if (account == null || !account.getJid().asBareJid().equals(jid.asBareJid())) {
@@ -237,64 +238,74 @@ public class QuickConversationsService extends AbstractQuickConversationsService
 
     public void verify(final Account account, String pin) {
         if (mVerificationInProgress.compareAndSet(false, true)) {
-            new Thread(() -> {
-                try {
-                    final URL url = new URL(BASE_URL + "/password");
-                    final HttpURLConnection connection = (HttpURLConnection) url.openConnection();
-                    setBundledLetsEncrypt(service, connection);
-                    connection.setConnectTimeout(Config.SOCKET_TIMEOUT * 1000);
-                    connection.setReadTimeout(Config.SOCKET_TIMEOUT * 1000);
-                    connection.setRequestMethod("POST");
-                    connection.setRequestProperty("Authorization", Plain.getMessage(account.getUsername(), pin));
-                    setHeader(connection);
-                    final OutputStream os = connection.getOutputStream();
-                    final BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(os, "UTF-8"));
-                    writer.write(account.getPassword());
-                    writer.flush();
-                    writer.close();
-                    os.close();
-                    connection.connect();
-                    final int code = connection.getResponseCode();
-                    if (code == 200 || code == 201) {
-                        account.setOption(Account.OPTION_UNVERIFIED, false);
-                        account.setOption(Account.OPTION_DISABLED, false);
-                        awaitingAccountStateChange = new CountDownLatch(1);
-                        service.updateAccount(account);
-                        try {
-                            awaitingAccountStateChange.await(5, TimeUnit.SECONDS);
-                        } catch (InterruptedException e) {
-                            Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": timer expired while waiting for account to connect");
-                        }
-                        synchronized (mOnVerification) {
-                            for (OnVerification onVerification : mOnVerification) {
-                                onVerification.onVerificationSucceeded();
-                            }
-                        }
-                    } else if (code == 429) {
-                        final long retryAfter = retryAfter(connection);
-                        synchronized (mOnVerification) {
-                            for (OnVerification onVerification : mOnVerification) {
-                                onVerification.onVerificationRetryAt(retryAfter);
-                            }
-                        }
-                    } else {
-                        synchronized (mOnVerification) {
-                            for (OnVerification onVerification : mOnVerification) {
-                                onVerification.onVerificationFailed(code);
-                            }
-                        }
-                    }
-                } catch (IOException e) {
-                    final int code = getApiErrorCode(e);
-                    synchronized (mOnVerification) {
-                        for (OnVerification onVerification : mOnVerification) {
-                            onVerification.onVerificationFailed(code);
-                        }
-                    }
-                } finally {
-                    mVerificationInProgress.set(false);
-                }
-            }).start();
+            new Thread(
+                            () -> {
+                                try {
+                                    final URL url = new URL(BASE_URL + "/password");
+                                    final HttpURLConnection connection =
+                                            (HttpURLConnection) url.openConnection();
+                                    setBundledLetsEncrypt(service, connection);
+                                    connection.setConnectTimeout(Config.SOCKET_TIMEOUT * 1000);
+                                    connection.setReadTimeout(Config.SOCKET_TIMEOUT * 1000);
+                                    connection.setRequestMethod("POST");
+                                    connection.setRequestProperty(
+                                            "Authorization",
+                                            Plain.getMessage(account.getUsername(), pin));
+                                    setHeader(connection);
+                                    final OutputStream os = connection.getOutputStream();
+                                    final BufferedWriter writer =
+                                            new BufferedWriter(new OutputStreamWriter(os, "UTF-8"));
+                                    writer.write(account.getPassword());
+                                    writer.flush();
+                                    writer.close();
+                                    os.close();
+                                    connection.connect();
+                                    final int code = connection.getResponseCode();
+                                    if (code == 200 || code == 201) {
+                                        account.setOption(Account.OPTION_UNVERIFIED, false);
+                                        account.setOption(Account.OPTION_DISABLED, false);
+                                        awaitingAccountStateChange = new CountDownLatch(1);
+                                        service.updateAccount(account);
+                                        try {
+                                            awaitingAccountStateChange.await(5, TimeUnit.SECONDS);
+                                        } catch (InterruptedException e) {
+                                            Log.d(
+                                                    Config.LOGTAG,
+                                                    account.getJid().asBareJid()
+                                                            + ": timer expired while waiting for"
+                                                            + " account to connect");
+                                        }
+                                        synchronized (mOnVerification) {
+                                            for (OnVerification onVerification : mOnVerification) {
+                                                onVerification.onVerificationSucceeded();
+                                            }
+                                        }
+                                    } else if (code == 429) {
+                                        final long retryAfter = retryAfter(connection);
+                                        synchronized (mOnVerification) {
+                                            for (OnVerification onVerification : mOnVerification) {
+                                                onVerification.onVerificationRetryAt(retryAfter);
+                                            }
+                                        }
+                                    } else {
+                                        synchronized (mOnVerification) {
+                                            for (OnVerification onVerification : mOnVerification) {
+                                                onVerification.onVerificationFailed(code);
+                                            }
+                                        }
+                                    }
+                                } catch (IOException e) {
+                                    final int code = getApiErrorCode(e);
+                                    synchronized (mOnVerification) {
+                                        for (OnVerification onVerification : mOnVerification) {
+                                            onVerification.onVerificationFailed(code);
+                                        }
+                                    }
+                                } finally {
+                                    mVerificationInProgress.set(false);
+                                }
+                            })
+                    .start();
         }
     }
 
@@ -339,7 +350,6 @@ public class QuickConversationsService extends AbstractQuickConversationsService
         return mVerificationRequestInProgress.get();
     }
 
-
     @Override
     public boolean isSynchronizing() {
         return mRunningSyncJobs.get() > 0;
@@ -353,12 +363,13 @@ public class QuickConversationsService extends AbstractQuickConversationsService
     @Override
     public void considerSyncBackground(final boolean forced) {
         mRunningSyncJobs.incrementAndGet();
-        mSerialSingleThreadExecutor.execute(() -> {
-            considerSync(forced);
-            if (mRunningSyncJobs.decrementAndGet() == 0) {
-                service.updateRosterUi();
-            }
-        });
+        mSerialSingleThreadExecutor.execute(
+                () -> {
+                    considerSync(forced);
+                    if (mRunningSyncJobs.decrementAndGet() == 0) {
+                        service.updateRosterUi();
+                    }
+                });
     }
 
     @Override
@@ -380,16 +391,19 @@ public class QuickConversationsService extends AbstractQuickConversationsService
                 onVerification.startBackgroundVerification(pin);
             }
         }
-
     }
 
-
     private void considerSync(boolean forced) {
-        final ImmutableMap<String, PhoneNumberContact> allContacts = PhoneNumberContact.load(service);
+        final ImmutableMap<String, PhoneNumberContact> allContacts =
+                PhoneNumberContact.load(service);
         for (final Account account : service.getAccounts()) {
-            final Map<String, PhoneNumberContact> contacts = filtered(allContacts, account.getJid().getLocal());
+            final Map<String, PhoneNumberContact> contacts =
+                    filtered(allContacts, account.getJid().getLocal());
             if (contacts.size() < allContacts.size()) {
-                Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": found own phone number in address book. ignoring...");
+                Log.d(
+                        Config.LOGTAG,
+                        account.getJid().asBareJid()
+                                + ": found own phone number in address book. ignoring...");
             }
             refresh(account, contacts.values());
             if (!considerSync(account, contacts, forced)) {
@@ -408,17 +422,24 @@ public class QuickConversationsService extends AbstractQuickConversationsService
     }
 
     private void refresh(Account account, Collection<PhoneNumberContact> contacts) {
-        for (Contact contact : account.getRoster().getWithSystemAccounts(PhoneNumberContact.class)) {
+        for (Contact contact :
+                account.getRoster().getWithSystemAccounts(PhoneNumberContact.class)) {
             final Uri uri = contact.getSystemAccount();
             if (uri == null) {
                 continue;
             }
             final String number = getNumber(contact);
-            final PhoneNumberContact phoneNumberContact = PhoneNumberContact.findByUriOrNumber(contacts, uri, number);
+            final PhoneNumberContact phoneNumberContact =
+                    PhoneNumberContact.findByUriOrNumber(contacts, uri, number);
             final boolean needsCacheClean;
             if (phoneNumberContact != null) {
                 if (!uri.equals(phoneNumberContact.getLookupUri())) {
-                    Log.d(Config.LOGTAG, "lookupUri has changed from " + uri + " to " + phoneNumberContact.getLookupUri());
+                    Log.d(
+                            Config.LOGTAG,
+                            "lookupUri has changed from "
+                                    + uri
+                                    + " to "
+                                    + phoneNumberContact.getLookupUri());
                 }
                 needsCacheClean = contact.setPhoneContact(phoneNumberContact);
             } else {
@@ -439,7 +460,10 @@ public class QuickConversationsService extends AbstractQuickConversationsService
         return null;
     }
 
-    private boolean considerSync(final Account account, final Map<String, PhoneNumberContact> contacts, final boolean forced) {
+    private boolean considerSync(
+            final Account account,
+            final Map<String, PhoneNumberContact> contacts,
+            final boolean forced) {
         final int hash = contacts.keySet().hashCode();
         Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": consider sync of " + hash);
         if (!mLastSyncAttempt.retry(hash) && !forced) {
@@ -448,59 +472,79 @@ public class QuickConversationsService extends AbstractQuickConversationsService
         }
         mRunningSyncJobs.incrementAndGet();
         final Jid syncServer = Jid.of(API_DOMAIN);
-        Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": sending phone list to " + syncServer);
+        Log.d(
+                Config.LOGTAG,
+                account.getJid().asBareJid() + ": sending phone list to " + syncServer);
         final List<Element> entries = new ArrayList<>();
         for (final PhoneNumberContact c : contacts.values()) {
             entries.add(new Element("entry").setAttribute("number", c.getPhoneNumber()));
         }
         final Iq query = new Iq(Iq.Type.GET);
         query.setTo(syncServer);
-        final Element book = new Element("phone-book", Namespace.SYNCHRONIZATION).setChildren(entries);
-        final String statusQuo = Entry.statusQuo(contacts.values(), account.getRoster().getWithSystemAccounts(PhoneNumberContact.class));
+        final Element book =
+                new Element("phone-book", Namespace.SYNCHRONIZATION).setChildren(entries);
+        final String statusQuo =
+                Entry.statusQuo(
+                        contacts.values(),
+                        account.getRoster().getWithSystemAccounts(PhoneNumberContact.class));
         book.setAttribute("ver", statusQuo);
         query.addChild(book);
         mLastSyncAttempt = Attempt.create(hash);
-        service.sendIqPacket(account, query, (response) -> {
-            if (response.getType() == Iq.Type.RESULT) {
-                final Element phoneBook = response.findChild("phone-book", Namespace.SYNCHRONIZATION);
-                if (phoneBook != null) {
-                    final List<Contact> withSystemAccounts = account.getRoster().getWithSystemAccounts(PhoneNumberContact.class);
-                    for (Entry entry : Entry.ofPhoneBook(phoneBook)) {
-                        final PhoneNumberContact phoneContact = contacts.get(entry.getNumber());
-                        if (phoneContact == null) {
-                            continue;
-                        }
-                        for (final Jid jid : entry.getJids()) {
-                            final Contact contact = account.getRoster().getContact(jid);
-                            final boolean needsCacheClean = contact.setPhoneContact(phoneContact);
-                            if (needsCacheClean) {
-                                service.getAvatarService().clear(contact);
+        service.sendIqPacket(
+                account,
+                query,
+                (response) -> {
+                    if (response.getType() == Iq.Type.RESULT) {
+                        final Element phoneBook =
+                                response.findChild("phone-book", Namespace.SYNCHRONIZATION);
+                        if (phoneBook != null) {
+                            final List<Contact> withSystemAccounts =
+                                    account.getRoster()
+                                            .getWithSystemAccounts(PhoneNumberContact.class);
+                            for (Entry entry : Entry.ofPhoneBook(phoneBook)) {
+                                final PhoneNumberContact phoneContact =
+                                        contacts.get(entry.getNumber());
+                                if (phoneContact == null) {
+                                    continue;
+                                }
+                                for (final Jid jid : entry.getJids()) {
+                                    final Contact contact = account.getRoster().getContact(jid);
+                                    final boolean needsCacheClean =
+                                            contact.setPhoneContact(phoneContact);
+                                    if (needsCacheClean) {
+                                        service.getAvatarService().clear(contact);
+                                    }
+                                    withSystemAccounts.remove(contact);
+                                }
                             }
-                            withSystemAccounts.remove(contact);
-                        }
-                    }
-                    for (final Contact contact : withSystemAccounts) {
-                        final boolean needsCacheClean = contact.unsetPhoneContact(PhoneNumberContact.class);
-                        if (needsCacheClean) {
-                            service.getAvatarService().clear(contact);
+                            for (final Contact contact : withSystemAccounts) {
+                                final boolean needsCacheClean =
+                                        contact.unsetPhoneContact(PhoneNumberContact.class);
+                                if (needsCacheClean) {
+                                    service.getAvatarService().clear(contact);
+                                }
+                            }
+                        } else {
+                            Log.d(
+                                    Config.LOGTAG,
+                                    account.getJid().asBareJid()
+                                            + ": phone number contact list remains unchanged");
                         }
+                    } else if (response.getType() == Iq.Type.TIMEOUT) {
+                        mLastSyncAttempt = Attempt.NULL;
+                    } else {
+                        Log.d(
+                                Config.LOGTAG,
+                                account.getJid().asBareJid()
+                                        + ": failed to sync contact list with api server");
                     }
-                } else {
-                    Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": phone number contact list remains unchanged");
-                }
-            } else if (response.getType() == Iq.Type.TIMEOUT) {
-                mLastSyncAttempt = Attempt.NULL;
-            } else {
-                Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": failed to sync contact list with api server");
-            }
-            mRunningSyncJobs.decrementAndGet();
-            service.syncRoster(account);
-            service.updateRosterUi();
-        });
+                    mRunningSyncJobs.decrementAndGet();
+                    service.syncRoster(account);
+                    service.updateRosterUi();
+                });
         return true;
     }
 
-
     public interface OnVerificationRequested {
         void onVerificationRequestFailed(int code);
 
@@ -535,7 +579,9 @@ public class QuickConversationsService extends AbstractQuickConversationsService
         }
 
         public boolean retry(int hash) {
-            return hash != this.hash || SystemClock.elapsedRealtime() - timestamp >= Config.CONTACT_SYNC_RETRY_INTERVAL;
+            return hash != this.hash
+                    || SystemClock.elapsedRealtime() - timestamp
+                            >= Config.CONTACT_SYNC_RETRY_INTERVAL;
         }
     }
-}
+}