Merge "Stop using static common test lib. Fix Jack build"
diff --git a/src/com/android/dialer/calllog/CallLogAdapter.java b/src/com/android/dialer/calllog/CallLogAdapter.java
index ff841e6..8ea861f 100644
--- a/src/com/android/dialer/calllog/CallLogAdapter.java
+++ b/src/com/android/dialer/calllog/CallLogAdapter.java
@@ -16,16 +16,13 @@
 
 package com.android.dialer.calllog;
 
-import android.content.ContentValues;
 import android.content.Context;
 import android.content.Intent;
 import android.content.res.Resources;
 import android.database.Cursor;
-import android.database.sqlite.SQLiteFullException;
 import android.net.Uri;
 import android.os.Handler;
 import android.os.Message;
-import android.provider.CallLog.Calls;
 import android.provider.ContactsContract.CommonDataKinds.Phone;
 import android.provider.ContactsContract.PhoneLookup;
 import android.telecom.PhoneAccountHandle;
@@ -46,11 +43,12 @@
 import com.android.dialer.PhoneCallDetails;
 import com.android.dialer.PhoneCallDetailsHelper;
 import com.android.dialer.R;
+import com.android.dialer.contactinfo.ContactInfoRequest;
+import com.android.dialer.contactinfo.NumberWithCountryIso;
 import com.android.dialer.util.DialerUtils;
 import com.android.dialer.util.ExpirableCache;
 
 import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Objects;
 
 import java.util.HashMap;
 import java.util.LinkedList;
@@ -95,37 +93,6 @@
         public void onReportButtonClick(String number);
     }
 
-    /**
-     * Stores a phone number of a call with the country code where it originally occurred.
-     * <p>
-     * Note the country does not necessarily specifies the country of the phone number itself, but
-     * it is the country in which the user was in when the call was placed or received.
-     */
-    private static final class NumberWithCountryIso {
-        public final String number;
-        public final String countryIso;
-
-        public NumberWithCountryIso(String number, String countryIso) {
-            this.number = number;
-            this.countryIso = countryIso;
-        }
-
-        @Override
-        public boolean equals(Object o) {
-            if (o == null) return false;
-            if (!(o instanceof NumberWithCountryIso)) return false;
-            NumberWithCountryIso other = (NumberWithCountryIso) o;
-            return TextUtils.equals(number, other.number)
-                    && TextUtils.equals(countryIso, other.countryIso);
-        }
-
-        @Override
-        public int hashCode() {
-            return (number == null ? 0 : number.hashCode())
-                    ^ (countryIso == null ? 0 : countryIso.hashCode());
-        }
-    }
-
     /** The time in millis to delay starting the thread processing requests. */
     private static final int START_PROCESSING_REQUESTS_DELAY_MILLIS = 1000;
 
@@ -177,49 +144,6 @@
     private HashMap<Long,Integer> mDayGroups = new HashMap<Long, Integer>();
 
     /**
-     * A request for contact details for the given number.
-     */
-    private static final class ContactInfoRequest {
-        /** The number to look-up. */
-        public final String number;
-        /** The country in which a call to or from this number was placed or received. */
-        public final String countryIso;
-        /** The cached contact information stored in the call log. */
-        public final ContactInfo callLogInfo;
-
-        public ContactInfoRequest(String number, String countryIso, ContactInfo callLogInfo) {
-            this.number = number;
-            this.countryIso = countryIso;
-            this.callLogInfo = callLogInfo;
-        }
-
-        @Override
-        public boolean equals(Object obj) {
-            if (this == obj) return true;
-            if (obj == null) return false;
-            if (!(obj instanceof ContactInfoRequest)) return false;
-
-            ContactInfoRequest other = (ContactInfoRequest) obj;
-
-            if (!TextUtils.equals(number, other.number)) return false;
-            if (!TextUtils.equals(countryIso, other.countryIso)) return false;
-            if (!Objects.equal(callLogInfo, other.callLogInfo)) return false;
-
-            return true;
-        }
-
-        @Override
-        public int hashCode() {
-            final int prime = 31;
-            int result = 1;
-            result = prime * result + ((callLogInfo == null) ? 0 : callLogInfo.hashCode());
-            result = prime * result + ((countryIso == null) ? 0 : countryIso.hashCode());
-            result = prime * result + ((number == null) ? 0 : number.hashCode());
-            return result;
-        }
-    }
-
-    /**
      * List of requests to update contact details.
      * <p>
      * Each request is made of a phone number to look up, and the contact info currently stored in
@@ -478,9 +402,10 @@
         // Store the data in the cache so that the UI thread can use to display it. Store it
         // even if it has not changed so that it is marked as not expired.
         mContactInfoCache.put(numberCountryIso, info);
+
         // Update the call log even if the cache it is up-to-date: it is possible that the cache
         // contains the value from a different call log entry.
-        updateCallLogContactInfoCache(number, countryIso, info, callLogInfo);
+        mContactInfoHelper.updateCallLogContactInfo(number, countryIso, info, callLogInfo);
         return updated;
     }
 
@@ -640,7 +565,7 @@
         // Stash away the Ids of the calls so that we can support deleting a row in the call log.
         views.callIds = getCallIds(c, count);
 
-        final ContactInfo cachedContactInfo = getContactInfoFromCallLog(c);
+        final ContactInfo cachedContactInfo = mContactInfoHelper.getContactInfo(c);
 
         final boolean isVoicemailNumber =
                 mPhoneNumberUtilsWrapper.isVoicemailNumber(accountHandle, number);
@@ -830,105 +755,6 @@
                 && TextUtils.equals(callLogInfo.label, info.label);
     }
 
-    /** Stores the updated contact info in the call log if it is different from the current one. */
-    private void updateCallLogContactInfoCache(String number, String countryIso,
-            ContactInfo updatedInfo, ContactInfo callLogInfo) {
-        final ContentValues values = new ContentValues();
-        boolean needsUpdate = false;
-
-        if (callLogInfo != null) {
-            if (!TextUtils.equals(updatedInfo.name, callLogInfo.name)) {
-                values.put(Calls.CACHED_NAME, updatedInfo.name);
-                needsUpdate = true;
-            }
-
-            if (updatedInfo.type != callLogInfo.type) {
-                values.put(Calls.CACHED_NUMBER_TYPE, updatedInfo.type);
-                needsUpdate = true;
-            }
-
-            if (!TextUtils.equals(updatedInfo.label, callLogInfo.label)) {
-                values.put(Calls.CACHED_NUMBER_LABEL, updatedInfo.label);
-                needsUpdate = true;
-            }
-            if (!UriUtils.areEqual(updatedInfo.lookupUri, callLogInfo.lookupUri)) {
-                values.put(Calls.CACHED_LOOKUP_URI, UriUtils.uriToString(updatedInfo.lookupUri));
-                needsUpdate = true;
-            }
-            // Only replace the normalized number if the new updated normalized number isn't empty.
-            if (!TextUtils.isEmpty(updatedInfo.normalizedNumber) &&
-                    !TextUtils.equals(updatedInfo.normalizedNumber, callLogInfo.normalizedNumber)) {
-                values.put(Calls.CACHED_NORMALIZED_NUMBER, updatedInfo.normalizedNumber);
-                needsUpdate = true;
-            }
-            if (!TextUtils.equals(updatedInfo.number, callLogInfo.number)) {
-                values.put(Calls.CACHED_MATCHED_NUMBER, updatedInfo.number);
-                needsUpdate = true;
-            }
-            if (updatedInfo.photoId != callLogInfo.photoId) {
-                values.put(Calls.CACHED_PHOTO_ID, updatedInfo.photoId);
-                needsUpdate = true;
-            }
-            final Uri updatedPhotoUriContactsOnly =
-                    UriUtils.nullForNonContactsUri(updatedInfo.photoUri);
-            if (!UriUtils.areEqual(updatedPhotoUriContactsOnly, callLogInfo.photoUri)) {
-                values.put(Calls.CACHED_PHOTO_URI, UriUtils.uriToString(
-                        updatedPhotoUriContactsOnly));
-                needsUpdate = true;
-            }
-            if (!TextUtils.equals(updatedInfo.formattedNumber, callLogInfo.formattedNumber)) {
-                values.put(Calls.CACHED_FORMATTED_NUMBER, updatedInfo.formattedNumber);
-                needsUpdate = true;
-            }
-        } else {
-            // No previous values, store all of them.
-            values.put(Calls.CACHED_NAME, updatedInfo.name);
-            values.put(Calls.CACHED_NUMBER_TYPE, updatedInfo.type);
-            values.put(Calls.CACHED_NUMBER_LABEL, updatedInfo.label);
-            values.put(Calls.CACHED_LOOKUP_URI, UriUtils.uriToString(updatedInfo.lookupUri));
-            values.put(Calls.CACHED_MATCHED_NUMBER, updatedInfo.number);
-            values.put(Calls.CACHED_NORMALIZED_NUMBER, updatedInfo.normalizedNumber);
-            values.put(Calls.CACHED_PHOTO_ID, updatedInfo.photoId);
-            values.put(Calls.CACHED_PHOTO_URI, UriUtils.uriToString(
-                    UriUtils.nullForNonContactsUri(updatedInfo.photoUri)));
-            values.put(Calls.CACHED_FORMATTED_NUMBER, updatedInfo.formattedNumber);
-            needsUpdate = true;
-        }
-
-        if (!needsUpdate) return;
-
-        try {
-            if (countryIso == null) {
-                mContext.getContentResolver().update(Calls.CONTENT_URI_WITH_VOICEMAIL, values,
-                        Calls.NUMBER + " = ? AND " + Calls.COUNTRY_ISO + " IS NULL",
-                        new String[]{ number });
-            } else {
-                mContext.getContentResolver().update(Calls.CONTENT_URI_WITH_VOICEMAIL, values,
-                        Calls.NUMBER + " = ? AND " + Calls.COUNTRY_ISO + " = ?",
-                        new String[]{ number, countryIso });
-            }
-        } catch (SQLiteFullException e) {
-            Log.e(TAG, "Unable to update contact info in call log db", e);
-        }
-    }
-
-    /** Returns the contact information as stored in the call log. */
-    private ContactInfo getContactInfoFromCallLog(Cursor c) {
-        ContactInfo info = new ContactInfo();
-        info.lookupUri = UriUtils.parseUriOrNull(c.getString(CallLogQuery.CACHED_LOOKUP_URI));
-        info.name = c.getString(CallLogQuery.CACHED_NAME);
-        info.type = c.getInt(CallLogQuery.CACHED_NUMBER_TYPE);
-        info.label = c.getString(CallLogQuery.CACHED_NUMBER_LABEL);
-        String matchedNumber = c.getString(CallLogQuery.CACHED_MATCHED_NUMBER);
-        info.number = matchedNumber == null ? c.getString(CallLogQuery.NUMBER) : matchedNumber;
-        info.normalizedNumber = c.getString(CallLogQuery.CACHED_NORMALIZED_NUMBER);
-        info.photoId = c.getLong(CallLogQuery.CACHED_PHOTO_ID);
-        info.photoUri = UriUtils.nullForNonContactsUri(
-                UriUtils.parseUriOrNull(c.getString(CallLogQuery.CACHED_PHOTO_URI)));
-        info.formattedNumber = c.getString(CallLogQuery.CACHED_FORMATTED_NUMBER);
-        return info;
-    }
-
     /**
      * Returns the call types for the given number of items in the cursor.
      * <p>
diff --git a/src/com/android/dialer/calllog/ContactInfoHelper.java b/src/com/android/dialer/calllog/ContactInfoHelper.java
index da03b07..8e8aa3c 100644
--- a/src/com/android/dialer/calllog/ContactInfoHelper.java
+++ b/src/com/android/dialer/calllog/ContactInfoHelper.java
@@ -14,9 +14,12 @@
 
 package com.android.dialer.calllog;
 
+import android.content.ContentValues;
 import android.content.Context;
 import android.database.Cursor;
+import android.database.sqlite.SQLiteFullException;
 import android.net.Uri;
+import android.provider.CallLog.Calls;
 import android.provider.ContactsContract;
 import android.provider.ContactsContract.CommonDataKinds.Phone;
 import android.provider.ContactsContract.Contacts;
@@ -24,6 +27,7 @@
 import android.provider.ContactsContract.PhoneLookup;
 import android.telephony.PhoneNumberUtils;
 import android.text.TextUtils;
+import android.util.Log;
 
 import com.android.contacts.common.util.Constants;
 import com.android.contacts.common.util.PhoneNumberHelper;
@@ -41,6 +45,8 @@
  * Utility class to look up the contact information for a given number.
  */
 public class ContactInfoHelper {
+    private static final String TAG = ContactInfoHelper.class.getSimpleName();
+
     private final Context mContext;
     private final String mCurrentCountryIso;
 
@@ -278,6 +284,107 @@
     }
 
     /**
+     * Stores differences between the updated contact info and the current call log contact info.
+     *
+     * @param number The number of the contact.
+     * @param countryIso The country associated with this number.
+     * @param updatedInfo The updated contact info.
+     * @param callLogInfo The call log entry's current contact info.
+     */
+    public void updateCallLogContactInfo(String number, String countryIso, ContactInfo updatedInfo,
+            ContactInfo callLogInfo) {
+        final ContentValues values = new ContentValues();
+        boolean needsUpdate = false;
+
+        if (callLogInfo != null) {
+            if (!TextUtils.equals(updatedInfo.name, callLogInfo.name)) {
+                values.put(Calls.CACHED_NAME, updatedInfo.name);
+                needsUpdate = true;
+            }
+
+            if (updatedInfo.type != callLogInfo.type) {
+                values.put(Calls.CACHED_NUMBER_TYPE, updatedInfo.type);
+                needsUpdate = true;
+            }
+
+            if (!TextUtils.equals(updatedInfo.label, callLogInfo.label)) {
+                values.put(Calls.CACHED_NUMBER_LABEL, updatedInfo.label);
+                needsUpdate = true;
+            }
+
+            if (!UriUtils.areEqual(updatedInfo.lookupUri, callLogInfo.lookupUri)) {
+                values.put(Calls.CACHED_LOOKUP_URI, UriUtils.uriToString(updatedInfo.lookupUri));
+                needsUpdate = true;
+            }
+
+            // Only replace the normalized number if the new updated normalized number isn't empty.
+            if (!TextUtils.isEmpty(updatedInfo.normalizedNumber) &&
+                    !TextUtils.equals(updatedInfo.normalizedNumber, callLogInfo.normalizedNumber)) {
+                values.put(Calls.CACHED_NORMALIZED_NUMBER, updatedInfo.normalizedNumber);
+                needsUpdate = true;
+            }
+
+            if (!TextUtils.equals(updatedInfo.number, callLogInfo.number)) {
+                values.put(Calls.CACHED_MATCHED_NUMBER, updatedInfo.number);
+                needsUpdate = true;
+            }
+
+            if (updatedInfo.photoId != callLogInfo.photoId) {
+                values.put(Calls.CACHED_PHOTO_ID, updatedInfo.photoId);
+                needsUpdate = true;
+            }
+
+            final Uri updatedPhotoUriContactsOnly =
+                    UriUtils.nullForNonContactsUri(updatedInfo.photoUri);
+            if (!UriUtils.areEqual(updatedPhotoUriContactsOnly, callLogInfo.photoUri)) {
+                values.put(Calls.CACHED_PHOTO_URI,
+                        UriUtils.uriToString(updatedPhotoUriContactsOnly));
+                needsUpdate = true;
+            }
+
+            if (!TextUtils.equals(updatedInfo.formattedNumber, callLogInfo.formattedNumber)) {
+                values.put(Calls.CACHED_FORMATTED_NUMBER, updatedInfo.formattedNumber);
+                needsUpdate = true;
+            }
+        } else {
+            // No previous values, store all of them.
+            values.put(Calls.CACHED_NAME, updatedInfo.name);
+            values.put(Calls.CACHED_NUMBER_TYPE, updatedInfo.type);
+            values.put(Calls.CACHED_NUMBER_LABEL, updatedInfo.label);
+            values.put(Calls.CACHED_LOOKUP_URI, UriUtils.uriToString(updatedInfo.lookupUri));
+            values.put(Calls.CACHED_MATCHED_NUMBER, updatedInfo.number);
+            values.put(Calls.CACHED_NORMALIZED_NUMBER, updatedInfo.normalizedNumber);
+            values.put(Calls.CACHED_PHOTO_ID, updatedInfo.photoId);
+            values.put(Calls.CACHED_PHOTO_URI, UriUtils.uriToString(
+                    UriUtils.nullForNonContactsUri(updatedInfo.photoUri)));
+            values.put(Calls.CACHED_FORMATTED_NUMBER, updatedInfo.formattedNumber);
+            needsUpdate = true;
+        }
+
+        if (!needsUpdate) {
+            return;
+        }
+
+        try {
+            if (countryIso == null) {
+                mContext.getContentResolver().update(
+                        Calls.CONTENT_URI_WITH_VOICEMAIL,
+                        values,
+                        Calls.NUMBER + " = ? AND " + Calls.COUNTRY_ISO + " IS NULL",
+                        new String[]{ number });
+            } else {
+                mContext.getContentResolver().update(
+                        Calls.CONTENT_URI_WITH_VOICEMAIL,
+                        values,
+                        Calls.NUMBER + " = ? AND " + Calls.COUNTRY_ISO + " = ?",
+                        new String[]{ number, countryIso });
+            }
+        } catch (SQLiteFullException e) {
+            Log.e(TAG, "Unable to update contact info in call log db", e);
+        }
+    }
+
+    /**
      * Parses the given URI to determine the original lookup key of the contact.
      */
     public static String getLookupKeyFromUri(Uri lookupUri) {
@@ -296,6 +403,29 @@
     }
 
     /**
+     * Returns the contact information stored in an entry of the call log.
+     *
+     * @param c A cursor pointing to an entry in the call log.
+     */
+    public static ContactInfo getContactInfo(Cursor c) {
+        ContactInfo info = new ContactInfo();
+
+        info.lookupUri = UriUtils.parseUriOrNull(c.getString(CallLogQuery.CACHED_LOOKUP_URI));
+        info.name = c.getString(CallLogQuery.CACHED_NAME);
+        info.type = c.getInt(CallLogQuery.CACHED_NUMBER_TYPE);
+        info.label = c.getString(CallLogQuery.CACHED_NUMBER_LABEL);
+        String matchedNumber = c.getString(CallLogQuery.CACHED_MATCHED_NUMBER);
+        info.number = matchedNumber == null ? c.getString(CallLogQuery.NUMBER) : matchedNumber;
+        info.normalizedNumber = c.getString(CallLogQuery.CACHED_NORMALIZED_NUMBER);
+        info.photoId = c.getLong(CallLogQuery.CACHED_PHOTO_ID);
+        info.photoUri = UriUtils.nullForNonContactsUri(
+                UriUtils.parseUriOrNull(c.getString(CallLogQuery.CACHED_PHOTO_URI)));
+        info.formattedNumber = c.getString(CallLogQuery.CACHED_FORMATTED_NUMBER);
+
+        return info;
+    }
+
+    /**
      * Given a contact's sourceType, return true if the contact is a business
      *
      * @param sourceType sourceType of the contact. This is usually populated by
diff --git a/src/com/android/dialer/contactinfo/ContactInfoRequest.java b/src/com/android/dialer/contactinfo/ContactInfoRequest.java
new file mode 100644
index 0000000..ec5c119
--- /dev/null
+++ b/src/com/android/dialer/contactinfo/ContactInfoRequest.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dialer.contactinfo;
+
+import android.text.TextUtils;
+
+import com.android.dialer.calllog.ContactInfo;
+import com.google.common.base.Objects;
+
+/**
+ * A request for contact details for the given number, used by the ContactInfoCache.
+ */
+public final class ContactInfoRequest {
+    /** The number to look-up. */
+    public final String number;
+    /** The country in which a call to or from this number was placed or received. */
+    public final String countryIso;
+    /** The cached contact information stored in the call log. */
+    public final ContactInfo callLogInfo;
+
+    public ContactInfoRequest(String number, String countryIso, ContactInfo callLogInfo) {
+        this.number = number;
+        this.countryIso = countryIso;
+        this.callLogInfo = callLogInfo;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) return true;
+        if (obj == null) return false;
+        if (!(obj instanceof ContactInfoRequest)) return false;
+
+        ContactInfoRequest other = (ContactInfoRequest) obj;
+
+        if (!TextUtils.equals(number, other.number)) return false;
+        if (!TextUtils.equals(countryIso, other.countryIso)) return false;
+        if (!Objects.equal(callLogInfo, other.callLogInfo)) return false;
+
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((callLogInfo == null) ? 0 : callLogInfo.hashCode());
+        result = prime * result + ((countryIso == null) ? 0 : countryIso.hashCode());
+        result = prime * result + ((number == null) ? 0 : number.hashCode());
+        return result;
+    }
+}
diff --git a/src/com/android/dialer/contactinfo/NumberWithCountryIso.java b/src/com/android/dialer/contactinfo/NumberWithCountryIso.java
new file mode 100644
index 0000000..1383fb7
--- /dev/null
+++ b/src/com/android/dialer/contactinfo/NumberWithCountryIso.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dialer.contactinfo;
+
+import android.text.TextUtils;
+
+/**
+ * Stores a phone number of a call with the country code where it originally occurred. This object
+ * is used as a key in the {@code ContactInfoCache}.
+ *
+ * The country does not necessarily specify the country of the phone number itself, but rather
+ * it is the country in which the user was in when the call was placed or received.
+ */
+public final class NumberWithCountryIso {
+    public final String number;
+    public final String countryIso;
+
+    public NumberWithCountryIso(String number, String countryIso) {
+        this.number = number;
+        this.countryIso = countryIso;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (o == null) return false;
+        if (!(o instanceof NumberWithCountryIso)) return false;
+        NumberWithCountryIso other = (NumberWithCountryIso) o;
+        return TextUtils.equals(number, other.number)
+                && TextUtils.equals(countryIso, other.countryIso);
+    }
+
+    @Override
+    public int hashCode() {
+        int numberHashCode = number == null ? 0 : number.hashCode();
+        int countryHashCode = countryIso == null ? 0 : countryIso.hashCode();
+
+        return numberHashCode ^ countryHashCode;
+    }
+}