/** * Queries the appropriate content provider for the contact associated with the number. * * <p>Upon completion it also updates the cache in the call log, if it is different from {@code * callLogInfo}. * * <p>The number might be either a SIP address or a phone number. * * <p>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) { final ContactInfo info = mContactInfoHelper.lookupNumber(number, countryIso); if (info == null) { // The lookup failed, just return without requesting to update the view. return false; } // 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 = mContactInfoCache.getPossiblyExpired(numberCountryIso); final boolean isRemoteSource = info.sourceType != 0; // Don't force redraw if existing info in the cache is equal to {@link ContactInfo#EMPTY} // to avoid updating the data set for every new row that is scrolled into view. // see (https://googleplex-android-review.git.corp.google.com/#/c/166680/) // Exception: Photo uris for contacts from remote sources are not cached in the call log // cache, so we have to force a redraw for these contacts regardless. boolean updated = (existingInfo != ContactInfo.EMPTY || isRemoteSource) && !info.equals(existingInfo); // 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); mCb.updateContactInfo(number, countryIso, info, callLogInfo); return updated; }
/* * Get the number from the Contacts, if available, since sometimes * the number provided by caller id may not be formatted properly * depending on the carrier (roaming) in use at the time of the * incoming call. * Logic : If the caller-id number starts with a "+", use it * Else if the number in the contacts starts with a "+", use that one * Else if the number in the contacts is longer, use that one */ public String getBetterNumberFromContacts(String number, String countryIso) { String matchingNumber = null; // Look in the cache first. If it's not found then query the Phones db NumberWithCountryIso numberCountryIso = new NumberWithCountryIso(number, countryIso); ContactInfo ci = mContactInfoCache.getPossiblyExpired(numberCountryIso); if (ci != null && ci != ContactInfo.EMPTY) { matchingNumber = ci.number; } else { try { Cursor phonesCursor = mContext .getContentResolver() .query( Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, number), PhoneQuery._PROJECTION, null, null, null); if (phonesCursor != null) { if (phonesCursor.moveToFirst()) { matchingNumber = phonesCursor.getString(PhoneQuery.MATCHED_NUMBER); } phonesCursor.close(); } } catch (Exception e) { // Use the number from the call log } } if (!TextUtils.isEmpty(matchingNumber) && (matchingNumber.startsWith("+") || matchingNumber.length() > number.length())) { number = matchingNumber; } return number; }
public void invalidateCache() { mContactInfoCache.expireAll(); // Restart the request-processing thread after the next draw. stopRequestProcessing(); unregisterPreDrawListener(); }
public ContactInfo lookupContact( String number, int numberPresentation, String countryIso, ContactInfo cachedContactInfo) { NumberWithCountryIso numberCountryIso = new NumberWithCountryIso(number, countryIso); ExpirableCache.CachedValue<ContactInfo> cachedInfo = mContactInfoCache.getCachedValue(numberCountryIso); ContactInfo info = cachedInfo == null ? null : cachedInfo.getValue(); if (!PhoneNumberUtilsWrapper.canPlaceCallsTo(number, numberPresentation) || new PhoneNumberUtilsWrapper().isVoicemailNumber(number)) { // If this is a number that cannot be dialed, there is no point in looking up a contact // for it. info = ContactInfo.EMPTY; } else if (cachedInfo == null) { mContactInfoCache.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); // 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); } 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); } if (info == ContactInfo.EMPTY) { // Use the cached contact info from the call log. info = cachedContactInfo; } } return info; }
public CallLogAdapterHelper( Context context, Callback cb, ContactInfoHelper contactInfoHelper, PhoneNumberDisplayHelper phoneNumberHelper) { mContext = context; mCb = cb; mContactInfoHelper = contactInfoHelper; mPhoneNumberDisplayHelper = phoneNumberHelper; mContactInfoCache = ExpirableCache.create(CONTACT_INFO_CACHE_SIZE); mRequests = new LinkedList<ContactInfoRequest>(); }
@VisibleForTesting void injectContactInfoForTest(String number, String countryIso, ContactInfo contactInfo) { NumberWithCountryIso numberCountryIso = new NumberWithCountryIso(number, countryIso); mContactInfoCache.put(numberCountryIso, contactInfo); }