Merge "IMS-VT: Show contact photo view when remote side is on hold." into atel.lnx.2.0-dev
diff --git a/src/com/android/dialer/calllog/CallLogAdapter.java b/src/com/android/dialer/calllog/CallLogAdapter.java
index 8e58a59..6a447a6 100644
--- a/src/com/android/dialer/calllog/CallLogAdapter.java
+++ b/src/com/android/dialer/calllog/CallLogAdapter.java
@@ -536,8 +536,8 @@
             // Lookup contacts with this number
             boolean isConfCallLog = num != null && num.length > 1
                     && DialerUtils.isConferenceURICallLog(phoneNumber, postDialDigits);
-            String queryNumber = isConfCallLog ? phoneNumber : number + postDialDigits;
-            info = mContactInfoCache.getValue(queryNumber,
+            String queryNumber = isConfCallLog ? phoneNumber : number;
+            info = mContactInfoCache.getValue(queryNumber, postDialDigits,
                     countryIso, cachedContactInfo, isConfCallLog);
         }
         CharSequence formattedNumber = info.formattedNumber == null
diff --git a/src/com/android/dialer/calllog/CallLogAsyncTaskUtil.java b/src/com/android/dialer/calllog/CallLogAsyncTaskUtil.java
index 426615a..667d6b9 100644
--- a/src/com/android/dialer/calllog/CallLogAsyncTaskUtil.java
+++ b/src/com/android/dialer/calllog/CallLogAsyncTaskUtil.java
@@ -47,6 +47,7 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Locale;
+import java.util.regex.Pattern;
 
 public class CallLogAsyncTaskUtil {
     private static String TAG = CallLogAsyncTaskUtil.class.getSimpleName();
@@ -209,14 +210,20 @@
                     PhoneNumberUtil.canPlaceCallsTo(number, numberPresentation) && !isVoicemail;
             ContactInfo info = ContactInfo.EMPTY;
 
+            Pattern pattern = Pattern.compile("[,;]");
+            String[] num = pattern.split(number);
+            boolean isConf = num != null && num.length > 1
+                    && DialerUtils.isConferenceURICallLog(number, postDialDigits);
+            String phoneNumber = num != null && num.length > 0 ? num[0] : "";
+            String queryNumber = isConf ? number : phoneNumber;
             if (shouldLookupNumber) {
-                ContactInfo lookupInfo = contactInfoHelper.lookupNumber(number, countryIso,
-                    DialerUtils.isConferenceURICallLog(number, postDialDigits));
+                ContactInfo lookupInfo = contactInfoHelper.lookupNumber(queryNumber, postDialDigits,
+                        countryIso, isConf);
                 info = lookupInfo != null ? lookupInfo : ContactInfo.EMPTY;
             }
 
             PhoneCallDetails details = new PhoneCallDetails(
-                    context, number, numberPresentation, info.formattedNumber,
+                    context, queryNumber, numberPresentation, info.formattedNumber,
                     postDialDigits, isVoicemail);
 
             details.viaNumber = viaNumber;
diff --git a/src/com/android/dialer/calllog/CallLogGroupBuilder.java b/src/com/android/dialer/calllog/CallLogGroupBuilder.java
index aa45029..ab9d535 100644
--- a/src/com/android/dialer/calllog/CallLogGroupBuilder.java
+++ b/src/com/android/dialer/calllog/CallLogGroupBuilder.java
@@ -27,6 +27,9 @@
 import com.android.contacts.common.util.DateUtils;
 import com.android.contacts.common.util.PhoneNumberHelper;
 import com.android.dialer.util.AppCompatConstants;
+import com.android.dialer.util.DialerUtils;
+
+import java.util.regex.Pattern;
 
 /**
  * Groups together calls in the call log.  The primary grouping attempts to group together calls
@@ -130,6 +133,8 @@
         int groupCallType = cursor.getInt(CallLogQuery.CALL_TYPE);
         String groupAccountComponentName = cursor.getString(CallLogQuery.ACCOUNT_COMPONENT_NAME);
         String groupAccountId = cursor.getString(CallLogQuery.ACCOUNT_ID);
+        boolean isGroupConfCallLog = DialerUtils.isConferenceURICallLog(groupNumber,
+                groupPostDialDigits);
         int groupSize = 1;
 
         String number;
@@ -138,6 +143,7 @@
         int callType;
         String accountComponentName;
         String accountId;
+        boolean isNumberConfCallLog = false;
 
         while (cursor.moveToNext()) {
             // Obtain the values for the current call to group.
@@ -149,8 +155,10 @@
             callType = cursor.getInt(CallLogQuery.CALL_TYPE);
             accountComponentName = cursor.getString(CallLogQuery.ACCOUNT_COMPONENT_NAME);
             accountId = cursor.getString(CallLogQuery.ACCOUNT_ID);
+            isNumberConfCallLog = DialerUtils.isConferenceURICallLog(number, numberPostDialDigits);
 
-            final boolean isSameNumber = equalNumbers(groupNumber, number);
+            final boolean isSameNumber = equalNumbers(groupNumber, isGroupConfCallLog,
+                    number, isNumberConfCallLog);
             final boolean isSamePostDialDigits = groupPostDialDigits.equals(numberPostDialDigits);
             final boolean isSameViaNumbers = groupViaNumbers.equals(numberViaNumbers);
             final boolean isSameAccount = isSameAccount(
@@ -184,6 +192,8 @@
                 groupCallType = callType;
                 groupAccountComponentName = accountComponentName;
                 groupAccountId = accountId;
+                isGroupConfCallLog = DialerUtils.isConferenceURICallLog(groupNumber,
+                        groupPostDialDigits);
             }
 
             // Save the day group associated with the current call.
@@ -224,8 +234,27 @@
 
     @VisibleForTesting
     boolean equalNumbers(String number1, String number2) {
+        return equalNumbers(number1, false, number2, false);
+    }
+
+    boolean equalNumbers(String number1, boolean isConf1, String number2, boolean isConf2) {
         if (PhoneNumberHelper.isUriNumber(number1) || PhoneNumberHelper.isUriNumber(number2)) {
             return compareSipAddresses(number1, number2);
+        } else if (isConf1 && isConf2) {
+            Pattern pattern = Pattern.compile("[,;]");
+            String[] num1 = pattern.split(number1);
+            String[] num2 = pattern.split(number2);
+            if (num1 == null || num2 == null || num1.length != num2.length) {
+                return false;
+            }
+            for (int i = 0; i < num1.length; i++) {
+                if (!PhoneNumberUtils.compare(num1[i], num2[i])) {
+                    return false;
+                }
+            }
+            return true;
+        } else if (isConf1 != isConf2) {
+            return false;
         } else {
             return PhoneNumberUtils.compare(number1, number2);
         }
diff --git a/src/com/android/dialer/calllog/ContactInfoHelper.java b/src/com/android/dialer/calllog/ContactInfoHelper.java
index bcc9e2f..ea39d03 100644
--- a/src/com/android/dialer/calllog/ContactInfoHelper.java
+++ b/src/com/android/dialer/calllog/ContactInfoHelper.java
@@ -78,7 +78,7 @@
      */
     @Nullable
     public ContactInfo lookupNumber(String number, String countryIso) {
-        return lookupNumber(number, countryIso, false);
+        return lookupNumber(number, null, countryIso, false);
     }
 
     /**
@@ -90,11 +90,13 @@
      * If an error occurs during the lookup, it returns null.
      *
      * @param number the number to look up
+     * @param postDialString append into number if required
      * @param countryIso the country associated with this number
      * @param isConfUrlLog whether call log is for Conference URL call
      */
     @Nullable
-    public ContactInfo lookupNumber(String number, String countryIso, boolean isConfUrlCallLog) {
+    public ContactInfo lookupNumber(String number, String postDialString, String countryIso,
+            boolean isConfUrlCallLog) {
 
         if (TextUtils.isEmpty(number)) {
             return null;
@@ -109,13 +111,14 @@
                 // If lookup failed, check if the "username" of the SIP address is a phone number.
                 String username = PhoneNumberHelper.getUsernameFromUriNumber(number);
                 if (PhoneNumberUtils.isGlobalPhoneNumber(username)) {
-                    info = queryContactInfoForPhoneNumber(username, countryIso, true,
+                    info = queryContactInfoForPhoneNumber(username, null, countryIso, true,
                             isConfUrlCallLog);
                 }
             }
         } else {
             // Look for a contact that has the given phone number.
-            info = queryContactInfoForPhoneNumber(number, countryIso, false, isConfUrlCallLog);
+            info = queryContactInfoForPhoneNumber(number, postDialString, countryIso,
+                    false, isConfUrlCallLog);
         }
 
         final ContactInfo updatedInfo;
@@ -127,6 +130,9 @@
             if (info == ContactInfo.EMPTY) {
                 // Did not find a matching contact.
                 updatedInfo = new ContactInfo();
+                if (!isConfUrlCallLog && !TextUtils.isEmpty(postDialString)) {
+                    number += postDialString;
+                }
                 updatedInfo.number = number;
                 updatedInfo.formattedNumber = formatPhoneNumber(number, null, countryIso);
                 updatedInfo.normalizedNumber = PhoneNumberUtils.formatNumberToE164(
@@ -265,8 +271,8 @@
      * <p>
      * If the lookup fails for some other reason, it returns null.
      */
-    private ContactInfo queryContactInfoForPhoneNumber(String number, String countryIso,
-            boolean isSip, boolean isConfUrlLog) {
+    private ContactInfo queryContactInfoForPhoneNumber(String number, String postDialString,
+            String countryIso, boolean isSip, boolean isConfUrlLog) {
         if (TextUtils.isEmpty(number)) {
             return null;
         }
@@ -303,6 +309,9 @@
             }
         }
         if (info != null && info != ContactInfo.EMPTY) {
+            if (!isConfUrlLog && TextUtils.isEmpty(postDialString)) {
+                number += postDialString;
+            }
             info.formattedNumber = formatPhoneNumber(number, null, countryIso);
         } else if (mCachedNumberLookupService != null) {
             CachedContactInfo cacheInfo =
diff --git a/src/com/android/dialer/contactinfo/ContactInfoCache.java b/src/com/android/dialer/contactinfo/ContactInfoCache.java
index af30c10..4fd3013 100644
--- a/src/com/android/dialer/contactinfo/ContactInfoCache.java
+++ b/src/com/android/dialer/contactinfo/ContactInfoCache.java
@@ -76,8 +76,8 @@
 
                 if (req != null) {
                     // Process the request. If the lookup succeeds, schedule a redraw.
-                    needRedraw |= queryContactInfo(req.number, req.countryIso, req.callLogInfo,
-                            req.isConf);
+                    needRedraw |= queryContactInfo(req.number, req.postDialString, req.countryIso,
+                            req.callLogInfo, req.isConf);
                 } else {
                     // Throttle redraw rate by only sending them when there are
                     // more requests.
@@ -131,6 +131,7 @@
     private final LinkedList<ContactInfoRequest> mRequests;
 
     private ExpirableCache<NumberWithCountryIso, ContactInfo> mCache;
+    private ExpirableCache<NumberWithCountryIso, ContactInfo> mCacheFor4gConfCall;
 
     private ContactInfoHelper mContactInfoHelper;
     private QueryThread mContactInfoQueryThread;
@@ -143,37 +144,52 @@
 
         mRequests = new LinkedList<ContactInfoRequest>();
         mCache = ExpirableCache.create(CONTACT_INFO_CACHE_SIZE);
+        mCacheFor4gConfCall = ExpirableCache.create(CONTACT_INFO_CACHE_SIZE);
     }
 
     public ContactInfo getValue(String number, String countryIso, ContactInfo cachedContactInfo) {
-        return getValue(number, countryIso, cachedContactInfo, false);
+        return getValue(number, null, countryIso, cachedContactInfo, false);
     }
 
-    public ContactInfo getValue(String number, String countryIso, ContactInfo cachedContactInfo,
-                boolean isConf) {
-        NumberWithCountryIso numberCountryIso = new NumberWithCountryIso(number, countryIso);
-        ExpirableCache.CachedValue<ContactInfo> cachedInfo =
-                mCache.getCachedValue(numberCountryIso);
+    public ContactInfo getValue(String number, String postDialString, String countryIso,
+                ContactInfo cachedContactInfo, boolean isConf) {
+        String phoneNumber = number;
+        if (!isConf && !TextUtils.isEmpty(postDialString)) {
+            phoneNumber += postDialString;
+        }
+        NumberWithCountryIso numberCountryIso = new NumberWithCountryIso(phoneNumber, countryIso);
+        ExpirableCache.CachedValue<ContactInfo> cachedInfo = null;
+        if (isConf) {
+            cachedInfo = mCacheFor4gConfCall.getCachedValue(numberCountryIso);
+        } else {
+            cachedInfo = mCache.getCachedValue(numberCountryIso);
+        }
         ContactInfo info = cachedInfo == null ? null : cachedInfo.getValue();
         if (cachedInfo == null) {
-            mCache.put(numberCountryIso, ContactInfo.EMPTY);
+            if (isConf) {
+                mCacheFor4gConfCall.put(numberCountryIso, ContactInfo.EMPTY);
+            } else {
+                mCache.put(numberCountryIso, ContactInfo.EMPTY);
+            }
             // Use the cached contact info from the call log.
             info = cachedContactInfo;
             // The db request should happen on a non-UI thread.
             // Request the contact details immediately since they are currently missing.
-            enqueueRequest(number, countryIso, cachedContactInfo, true, isConf);
+            enqueueRequest(number, postDialString, countryIso, cachedContactInfo, true, isConf);
             // We will format the phone number when we make the background request.
         } else {
             if (cachedInfo.isExpired()) {
                 // The contact info is no longer up to date, we should request it. However, we
                 // do not need to request them immediately.
-                enqueueRequest(number, countryIso, cachedContactInfo, false, isConf);
+                enqueueRequest(number, postDialString, countryIso,
+                        cachedContactInfo, false, isConf);
             } else if (!callLogInfoMatches(cachedContactInfo, info)) {
                 // The call log information does not match the one we have, look it up again.
                 // We could simply update the call log directly, but that needs to be done in a
                 // background thread, so it is easier to simply request a new lookup, which will, as
                 // a side-effect, update the call log.
-                enqueueRequest(number, countryIso, cachedContactInfo, false, isConf);
+                enqueueRequest(number, postDialString, countryIso,
+                        cachedContactInfo, false, isConf);
             }
 
             if (info == ContactInfo.EMPTY) {
@@ -192,12 +208,15 @@
      *
      * The number might be either a SIP address or a phone number.
      *
+     * @param postDialString if required, append into number
+     * @param isConf determine whether it is a 4g conf call log
      * It returns true if it updated the content of the cache and we should therefore tell the
      * view to update its content.
      */
-    private boolean queryContactInfo(String number, String countryIso, ContactInfo callLogInfo,
-            boolean isConf) {
-        final ContactInfo info = mContactInfoHelper.lookupNumber(number, countryIso, isConf);
+    private boolean queryContactInfo(String number, String postDialString, String countryIso,
+            ContactInfo callLogInfo, boolean isConf) {
+        final ContactInfo info = mContactInfoHelper.lookupNumber(number, postDialString,
+                countryIso, isConf);
 
         if (info == null) {
             // The lookup failed, just return without requesting to update the view.
@@ -206,8 +225,17 @@
 
         // Check the existing entry in the cache: only if it has changed we should update the
         // view.
-        NumberWithCountryIso numberCountryIso = new NumberWithCountryIso(number, countryIso);
-        ContactInfo existingInfo = mCache.getPossiblyExpired(numberCountryIso);
+        String phoneNumber = number;
+        if (!isConf && !TextUtils.isEmpty(postDialString)) {
+            phoneNumber += postDialString;
+        }
+        NumberWithCountryIso numberCountryIso = new NumberWithCountryIso(phoneNumber, countryIso);
+        ContactInfo existingInfo = null;
+        if (isConf) {
+            existingInfo = mCacheFor4gConfCall.getPossiblyExpired(numberCountryIso);
+        } else {
+            existingInfo = mCache.getPossiblyExpired(numberCountryIso);
+        }
 
         final boolean isRemoteSource = info.sourceType != 0;
 
@@ -222,11 +250,21 @@
 
         // 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.
-        mCache.put(numberCountryIso, info);
+        if (isConf) {
+            mCacheFor4gConfCall.put(numberCountryIso, info);
+        } else {
+            mCache.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.
-        mContactInfoHelper.updateCallLogContactInfo(number, countryIso, info, callLogInfo);
+        if (isConf) {
+            mContactInfoHelper.updateCallLogContactInfo(number, countryIso,
+                    info, callLogInfo);
+        } else {
+            mContactInfoHelper.updateCallLogContactInfo(phoneNumber, countryIso,
+                    info, callLogInfo);
+        }
         return updated;
     }
 
@@ -271,6 +309,7 @@
 
     public void invalidate() {
         mCache.expireAll();
+        mCacheFor4gConfCall.expireAll();
         stopRequestProcessing();
     }
 
@@ -300,7 +339,7 @@
      */
     protected void enqueueRequest(String number, String countryIso, ContactInfo callLogInfo,
             boolean immediate) {
-        enqueueRequest(number, countryIso, callLogInfo, immediate, false);
+        enqueueRequest(number, null, countryIso, callLogInfo, immediate, false);
     }
 
     /**
@@ -311,12 +350,13 @@
      * If the {@code immediate} parameter is true, it will start immediately the thread that looks
      * up the contact information (if it has not been already started). Otherwise, it will be
      * started with a delay. See {@link #START_PROCESSING_REQUESTS_DELAY_MILLIS}.
+     * @param postDialString if required, append into number
      * @param isConf indicate whether call log is for Conference Url call
      */
-    protected void enqueueRequest(String number, String countryIso, ContactInfo callLogInfo,
-            boolean immediate, boolean isConf) {
-        ContactInfoRequest request = new ContactInfoRequest(number, countryIso, callLogInfo,
-                isConf);
+    protected void enqueueRequest(String number, String postDialString, String countryIso,
+            ContactInfo callLogInfo, boolean immediate, boolean isConf) {
+        ContactInfoRequest request = new ContactInfoRequest(number, postDialString, countryIso,
+                callLogInfo, isConf);
         synchronized (mRequests) {
             if (!mRequests.contains(request)) {
                 mRequests.add(request);
diff --git a/src/com/android/dialer/contactinfo/ContactInfoRequest.java b/src/com/android/dialer/contactinfo/ContactInfoRequest.java
index 1171dcf..98208bc 100644
--- a/src/com/android/dialer/contactinfo/ContactInfoRequest.java
+++ b/src/com/android/dialer/contactinfo/ContactInfoRequest.java
@@ -32,14 +32,16 @@
     /** The cached contact information stored in the call log. */
     public final ContactInfo callLogInfo;
     public final boolean isConf;
+    public final String postDialString;
 
     public ContactInfoRequest(String number, String countryIso, ContactInfo callLogInfo) {
-        this(number, countryIso, callLogInfo, false);
+        this(number, null, countryIso, callLogInfo, false);
     }
 
-    public ContactInfoRequest(String number, String countryIso, ContactInfo callLogInfo,
-            boolean isConf) {
+    public ContactInfoRequest(String number, String postDialString, String countryIso,
+            ContactInfo callLogInfo, boolean isConf) {
         this.number = number;
+        this.postDialString = postDialString;
         this.countryIso = countryIso;
         this.callLogInfo = callLogInfo;
         this.isConf = isConf;
@@ -54,6 +56,7 @@
         ContactInfoRequest other = (ContactInfoRequest) obj;
 
         if (!TextUtils.equals(number, other.number)) return false;
+        if (!TextUtils.equals(postDialString, other.postDialString)) return false;
         if (!TextUtils.equals(countryIso, other.countryIso)) return false;
         if (!Objects.equal(callLogInfo, other.callLogInfo)) return false;
 
@@ -67,6 +70,7 @@
         result = prime * result + ((callLogInfo == null) ? 0 : callLogInfo.hashCode());
         result = prime * result + ((countryIso == null) ? 0 : countryIso.hashCode());
         result = prime * result + ((number == null) ? 0 : number.hashCode());
+        result = prime * result + ((postDialString == null) ? 0 : postDialString.hashCode());
         return result;
     }
 }