diff options
author | Treehugger Robot <treehugger-gerrit@google.com> | 2017-12-07 20:24:31 +0000 |
---|---|---|
committer | Gerrit Code Review <noreply-gerritcodereview@google.com> | 2017-12-07 20:24:31 +0000 |
commit | f39d23184df8a5d7a18efc0c8a8ddb512b791629 (patch) | |
tree | 528814968666ae1a5e11bf5b61da7b1d636e5d2c | |
parent | 24fc672b885d8a155568515cf1ab1085a1a9ab21 (diff) | |
parent | 4e815f9cb92f868e173017dcc9a1783324d27886 (diff) |
Merge "Removed timestamps from PhoneLookup APIs."
4 files changed, 116 insertions, 100 deletions
diff --git a/java/com/android/dialer/calllog/datasources/phonelookup/PhoneLookupDataSource.java b/java/com/android/dialer/calllog/datasources/phonelookup/PhoneLookupDataSource.java index b3bbf3cbd..7a7f2070b 100644 --- a/java/com/android/dialer/calllog/datasources/phonelookup/PhoneLookupDataSource.java +++ b/java/com/android/dialer/calllog/datasources/phonelookup/PhoneLookupDataSource.java @@ -18,7 +18,6 @@ package com.android.dialer.calllog.datasources.phonelookup; import android.content.ContentValues; import android.content.Context; -import android.content.SharedPreferences; import android.database.Cursor; import android.support.annotation.MainThread; import android.support.annotation.WorkerThread; @@ -34,8 +33,6 @@ import com.android.dialer.phonelookup.PhoneLookup; import com.android.dialer.phonelookup.PhoneLookupInfo; import com.android.dialer.phonelookup.database.contract.PhoneLookupHistoryContract.PhoneLookupHistory; import com.android.dialer.phonenumberproto.DialerPhoneNumberUtil; -import com.android.dialer.storage.Unencrypted; -import com.google.auto.value.AutoValue; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Maps; @@ -54,15 +51,12 @@ import javax.inject.Inject; * numbers. */ public final class PhoneLookupDataSource implements CallLogDataSource { - private static final String PREF_LAST_TIMESTAMP_PROCESSED = "phoneLookupLastTimestampProcessed"; private final PhoneLookup phoneLookup; - private final SharedPreferences sharedPreferences; @Inject - PhoneLookupDataSource(PhoneLookup phoneLookup, @Unencrypted SharedPreferences sharedPreferences) { + PhoneLookupDataSource(PhoneLookup phoneLookup) { this.phoneLookup = phoneLookup; - this.sharedPreferences = sharedPreferences; } @WorkerThread @@ -71,15 +65,11 @@ public final class PhoneLookupDataSource implements CallLogDataSource { ImmutableSet<DialerPhoneNumber> uniqueDialerPhoneNumbers = queryDistinctDialerPhoneNumbersFromAnnotatedCallLog(appContext); - long lastTimestampProcessedSharedPrefValue = - sharedPreferences.getLong(PREF_LAST_TIMESTAMP_PROCESSED, 0L); try { // TODO(zachh): Would be good to rework call log architecture to properly use futures. // TODO(zachh): Consider how individual lookups should behave wrt timeouts/exceptions and // handle appropriately here. - return phoneLookup - .isDirty(uniqueDialerPhoneNumbers, lastTimestampProcessedSharedPrefValue) - .get(); + return phoneLookup.isDirty(uniqueDialerPhoneNumbers).get(); } catch (InterruptedException | ExecutionException e) { throw new IllegalStateException(e); } @@ -101,16 +91,12 @@ public final class PhoneLookupDataSource implements CallLogDataSource { * <li>For inserts, uses the contents of PhoneLookupHistory to populate the fields of the * provided mutations. (Note that at this point, data may not be fully up-to-date, but the * next steps will take care of that.) - * <li>Uses all of the numbers from AnnotatedCallLog along with the callLogLastUpdated timestamp - * to invoke CompositePhoneLookup:bulkUpdate + * <li>Uses all of the numbers from AnnotatedCallLog to invoke CompositePhoneLookup:bulkUpdate * <li>Looks through the results of bulkUpdate * <ul> - * <li>For each number, checks if the original PhoneLookupInfo differs from the new one or - * if the lastModified date from PhoneLookupInfo table is newer than - * callLogLastUpdated. + * <li>For each number, checks if the original PhoneLookupInfo differs from the new one * <li>If so, it applies the update to the mutations and (in onSuccessfulFill) writes the - * new value back to the PhoneLookupHistory along with current time as the - * lastModified date. + * new value back to the PhoneLookupHistory. * </ul> * </ul> */ @@ -119,36 +105,23 @@ public final class PhoneLookupDataSource implements CallLogDataSource { public void fill(Context appContext, CallLogMutations mutations) { Map<DialerPhoneNumber, Set<Long>> annotatedCallLogIdsByNumber = queryIdAndNumberFromAnnotatedCallLog(appContext); - Map<DialerPhoneNumber, PhoneLookupInfoAndTimestamp> originalPhoneLookupHistoryDataByNumber = + ImmutableMap<DialerPhoneNumber, PhoneLookupInfo> originalPhoneLookupInfosByNumber = queryPhoneLookupHistoryForNumbers(appContext, annotatedCallLogIdsByNumber.keySet()); ImmutableMap.Builder<Long, PhoneLookupInfo> originalPhoneLookupHistoryDataByAnnotatedCallLogId = ImmutableMap.builder(); - for (Entry<DialerPhoneNumber, PhoneLookupInfoAndTimestamp> entry : - originalPhoneLookupHistoryDataByNumber.entrySet()) { + for (Entry<DialerPhoneNumber, PhoneLookupInfo> entry : + originalPhoneLookupInfosByNumber.entrySet()) { DialerPhoneNumber dialerPhoneNumber = entry.getKey(); - PhoneLookupInfoAndTimestamp phoneLookupInfoAndTimestamp = entry.getValue(); + PhoneLookupInfo phoneLookupInfo = entry.getValue(); for (Long id : annotatedCallLogIdsByNumber.get(dialerPhoneNumber)) { - originalPhoneLookupHistoryDataByAnnotatedCallLogId.put( - id, phoneLookupInfoAndTimestamp.phoneLookupInfo()); + originalPhoneLookupHistoryDataByAnnotatedCallLogId.put(id, phoneLookupInfo); } } populateInserts(originalPhoneLookupHistoryDataByAnnotatedCallLogId.build(), mutations); - ImmutableMap<DialerPhoneNumber, PhoneLookupInfo> originalPhoneLookupInfosByNumber = - ImmutableMap.copyOf( - Maps.transformValues( - originalPhoneLookupHistoryDataByNumber, - PhoneLookupInfoAndTimestamp::phoneLookupInfo)); - - long lastTimestampProcessedSharedPrefValue = - sharedPreferences.getLong(PREF_LAST_TIMESTAMP_PROCESSED, 0L); - // TODO(zachh): Push last timestamp processed down into each individual lookup. ImmutableMap<DialerPhoneNumber, PhoneLookupInfo> updatedInfoMap; try { - updatedInfoMap = - phoneLookup - .bulkUpdate(originalPhoneLookupInfosByNumber, lastTimestampProcessedSharedPrefValue) - .get(); + updatedInfoMap = phoneLookup.bulkUpdate(originalPhoneLookupInfosByNumber).get(); } catch (InterruptedException | ExecutionException e) { throw new IllegalStateException(e); } @@ -156,10 +129,7 @@ public final class PhoneLookupDataSource implements CallLogDataSource { for (Entry<DialerPhoneNumber, PhoneLookupInfo> entry : updatedInfoMap.entrySet()) { DialerPhoneNumber dialerPhoneNumber = entry.getKey(); PhoneLookupInfo upToDateInfo = entry.getValue(); - long numberLastModified = - originalPhoneLookupHistoryDataByNumber.get(dialerPhoneNumber).lastModified(); - if (numberLastModified > lastTimestampProcessedSharedPrefValue - || !originalPhoneLookupInfosByNumber.get(dialerPhoneNumber).equals(upToDateInfo)) { + if (!originalPhoneLookupInfosByNumber.get(dialerPhoneNumber).equals(upToDateInfo)) { for (Long id : annotatedCallLogIdsByNumber.get(dialerPhoneNumber)) { rowsToUpdate.put(id, upToDateInfo); } @@ -171,7 +141,7 @@ public final class PhoneLookupDataSource implements CallLogDataSource { @WorkerThread @Override public void onSuccessfulFill(Context appContext) { - // TODO(zachh): Implementation. + // TODO(zachh): Update PhoneLookupHistory. } @WorkerThread @@ -275,7 +245,7 @@ public final class PhoneLookupDataSource implements CallLogDataSource { return idsByNumber; } - private Map<DialerPhoneNumber, PhoneLookupInfoAndTimestamp> queryPhoneLookupHistoryForNumbers( + private ImmutableMap<DialerPhoneNumber, PhoneLookupInfo> queryPhoneLookupHistoryForNumbers( Context appContext, Set<DialerPhoneNumber> uniqueDialerPhoneNumbers) { DialerPhoneNumberUtil dialerPhoneNumberUtil = new DialerPhoneNumberUtil(PhoneNumberUtil.getInstance()); @@ -291,16 +261,14 @@ public final class PhoneLookupDataSource implements CallLogDataSource { String selection = PhoneLookupHistory.NORMALIZED_NUMBER + " in (" + TextUtils.join(",", questionMarks) + ")"; - Map<String, PhoneLookupInfoAndTimestamp> normalizedNumberToInfoMap = new ArrayMap<>(); + Map<String, PhoneLookupInfo> normalizedNumberToInfoMap = new ArrayMap<>(); try (Cursor cursor = appContext .getContentResolver() .query( PhoneLookupHistory.CONTENT_URI, new String[] { - PhoneLookupHistory.NORMALIZED_NUMBER, - PhoneLookupHistory.PHONE_LOOKUP_INFO, - PhoneLookupHistory.LAST_MODIFIED + PhoneLookupHistory.NORMALIZED_NUMBER, PhoneLookupHistory.PHONE_LOOKUP_INFO, }, selection, normalizedNumbers, @@ -316,7 +284,6 @@ public final class PhoneLookupDataSource implements CallLogDataSource { cursor.getColumnIndexOrThrow(PhoneLookupHistory.NORMALIZED_NUMBER); int phoneLookupInfoColumn = cursor.getColumnIndexOrThrow(PhoneLookupHistory.PHONE_LOOKUP_INFO); - int lastModifiedColumn = cursor.getColumnIndexOrThrow(PhoneLookupHistory.LAST_MODIFIED); do { String normalizedNumber = cursor.getString(normalizedNumberColumn); PhoneLookupInfo phoneLookupInfo; @@ -325,27 +292,25 @@ public final class PhoneLookupDataSource implements CallLogDataSource { } catch (InvalidProtocolBufferException e) { throw new IllegalStateException(e); } - long lastModified = cursor.getLong(lastModifiedColumn); - normalizedNumberToInfoMap.put( - normalizedNumber, PhoneLookupInfoAndTimestamp.create(phoneLookupInfo, lastModified)); + normalizedNumberToInfoMap.put(normalizedNumber, phoneLookupInfo); } while (cursor.moveToNext()); } } // We have the required information in normalizedNumberToInfoMap but it's keyed by normalized // number instead of DialerPhoneNumber. Build and return a new map keyed by DialerPhoneNumber. - return Maps.asMap( - uniqueDialerPhoneNumbers, - (dialerPhoneNumber) -> { - String normalizedNumber = dialerPhoneNumberToNormalizedNumbers.get(dialerPhoneNumber); - PhoneLookupInfoAndTimestamp infoAndTimestamp = - normalizedNumberToInfoMap.get(normalizedNumber); - // If data is cleared or for other reasons, the PhoneLookupHistory may not contain an - // entry for a number. Just use an empty value for that case. - return infoAndTimestamp == null - ? PhoneLookupInfoAndTimestamp.create(PhoneLookupInfo.getDefaultInstance(), 0L) - : infoAndTimestamp; - }); + return ImmutableMap.copyOf( + Maps.asMap( + uniqueDialerPhoneNumbers, + (dialerPhoneNumber) -> { + String normalizedNumber = dialerPhoneNumberToNormalizedNumbers.get(dialerPhoneNumber); + PhoneLookupInfo phoneLookupInfo = normalizedNumberToInfoMap.get(normalizedNumber); + // If data is cleared or for other reasons, the PhoneLookupHistory may not contain an + // entry for a number. Just use an empty value for that case. + return phoneLookupInfo == null + ? PhoneLookupInfo.getDefaultInstance() + : phoneLookupInfo; + })); } private static void populateInserts( @@ -418,16 +383,4 @@ public final class PhoneLookupDataSource implements CallLogDataSource { } return ""; } - - @AutoValue - abstract static class PhoneLookupInfoAndTimestamp { - abstract PhoneLookupInfo phoneLookupInfo(); - - abstract long lastModified(); - - static PhoneLookupInfoAndTimestamp create(PhoneLookupInfo phoneLookupInfo, long lastModified) { - return new AutoValue_PhoneLookupDataSource_PhoneLookupInfoAndTimestamp( - phoneLookupInfo, lastModified); - } - } } diff --git a/java/com/android/dialer/phonelookup/PhoneLookup.java b/java/com/android/dialer/phonelookup/PhoneLookup.java index 66f166d6d..183277569 100644 --- a/java/com/android/dialer/phonelookup/PhoneLookup.java +++ b/java/com/android/dialer/phonelookup/PhoneLookup.java @@ -27,8 +27,8 @@ import com.google.common.util.concurrent.ListenableFuture; * Provides operations related to retrieving information about phone numbers. * * <p>Some operations defined by this interface are generally targeted towards specific use cases; - * for example {@link #isDirty(ImmutableSet, long)} and {@link #bulkUpdate(ImmutableMap, long)} are - * generally intended to be used by the call log. + * for example {@link #isDirty(ImmutableSet)}, {@link #bulkUpdate(ImmutableMap)}, and {@link + * #onSuccessfulBulkUpdate()} are generally intended to be used by the call log. */ public interface PhoneLookup { @@ -43,14 +43,14 @@ public interface PhoneLookup { /** * Returns a future which returns true if the information for any of the provided phone numbers - * has changed since {@code lastModified} according to this {@link PhoneLookup}. + * has changed, usually since {@link #onSuccessfulBulkUpdate()} was last invoked. */ - ListenableFuture<Boolean> isDirty( - ImmutableSet<DialerPhoneNumber> phoneNumbers, long lastModified); + ListenableFuture<Boolean> isDirty(ImmutableSet<DialerPhoneNumber> phoneNumbers); /** - * Given a set of existing information and a timestamp, returns a set of information with any - * changes made since the timestamp according to this {@link PhoneLookup}. + * Performs a bulk update of this {@link PhoneLookup}. The returned map must contain the exact + * same keys as the provided map. Most implementations will rely on last modified timestamps to + * efficiently only update the data which needs to be updated. * * <p>If there are no changes required, it is valid for this method to simply return the provided * {@code existingInfoMap}. @@ -59,5 +59,15 @@ public interface PhoneLookup { * deleted) the returned map should contain an empty {@link PhoneLookupInfo} for that number. */ ListenableFuture<ImmutableMap<DialerPhoneNumber, PhoneLookupInfo>> bulkUpdate( - ImmutableMap<DialerPhoneNumber, PhoneLookupInfo> existingInfoMap, long lastModified); + ImmutableMap<DialerPhoneNumber, PhoneLookupInfo> existingInfoMap); + + /** + * Called when the results of the {@link #bulkUpdate(ImmutableMap)} have been applied by the + * caller. + * + * <p>Typically implementations will use this to store a "last processed" timestamp so that future + * invocations of {@link #isDirty(ImmutableSet)} and {@link #bulkUpdate(ImmutableMap)} can be + * efficiently implemented. + */ + ListenableFuture<Void> onSuccessfulBulkUpdate(); } diff --git a/java/com/android/dialer/phonelookup/composite/CompositePhoneLookup.java b/java/com/android/dialer/phonelookup/composite/CompositePhoneLookup.java index 59a845774..520c46f9e 100644 --- a/java/com/android/dialer/phonelookup/composite/CompositePhoneLookup.java +++ b/java/com/android/dialer/phonelookup/composite/CompositePhoneLookup.java @@ -70,11 +70,10 @@ public final class CompositePhoneLookup implements PhoneLookup { } @Override - public ListenableFuture<Boolean> isDirty( - ImmutableSet<DialerPhoneNumber> phoneNumbers, long lastModified) { + public ListenableFuture<Boolean> isDirty(ImmutableSet<DialerPhoneNumber> phoneNumbers) { List<ListenableFuture<Boolean>> futures = new ArrayList<>(); for (PhoneLookup phoneLookup : phoneLookups) { - futures.add(phoneLookup.isDirty(phoneNumbers, lastModified)); + futures.add(phoneLookup.isDirty(phoneNumbers)); } // Executes all child lookups (possibly in parallel), completing when the first composite lookup // which returns "true" completes, and cancels the others. @@ -90,11 +89,11 @@ public final class CompositePhoneLookup implements PhoneLookup { */ @Override public ListenableFuture<ImmutableMap<DialerPhoneNumber, PhoneLookupInfo>> bulkUpdate( - ImmutableMap<DialerPhoneNumber, PhoneLookupInfo> existingInfoMap, long lastModified) { + ImmutableMap<DialerPhoneNumber, PhoneLookupInfo> existingInfoMap) { List<ListenableFuture<ImmutableMap<DialerPhoneNumber, PhoneLookupInfo>>> futures = new ArrayList<>(); for (PhoneLookup phoneLookup : phoneLookups) { - futures.add(phoneLookup.bulkUpdate(existingInfoMap, lastModified)); + futures.add(phoneLookup.bulkUpdate(existingInfoMap)); } return Futures.transform( Futures.allAsList(futures), @@ -118,4 +117,14 @@ public final class CompositePhoneLookup implements PhoneLookup { }, MoreExecutors.directExecutor()); } + + @Override + public ListenableFuture<Void> onSuccessfulBulkUpdate() { + List<ListenableFuture<Void>> futures = new ArrayList<>(); + for (PhoneLookup phoneLookup : phoneLookups) { + futures.add(phoneLookup.onSuccessfulBulkUpdate()); + } + return Futures.transform( + Futures.allAsList(futures), unused -> null, MoreExecutors.directExecutor()); + } } diff --git a/java/com/android/dialer/phonelookup/cp2/Cp2PhoneLookup.java b/java/com/android/dialer/phonelookup/cp2/Cp2PhoneLookup.java index 4ebd401c3..307f998ea 100644 --- a/java/com/android/dialer/phonelookup/cp2/Cp2PhoneLookup.java +++ b/java/com/android/dialer/phonelookup/cp2/Cp2PhoneLookup.java @@ -17,11 +17,13 @@ package com.android.dialer.phonelookup.cp2; import android.content.Context; +import android.content.SharedPreferences; import android.database.Cursor; import android.provider.ContactsContract.CommonDataKinds.Phone; import android.provider.ContactsContract.Contacts; import android.provider.ContactsContract.DeletedContacts; import android.support.annotation.NonNull; +import android.support.annotation.Nullable; import android.support.v4.util.ArrayMap; import android.support.v4.util.ArraySet; import android.telecom.Call; @@ -33,6 +35,7 @@ import com.android.dialer.phonelookup.PhoneLookup; import com.android.dialer.phonelookup.PhoneLookupInfo; import com.android.dialer.phonelookup.PhoneLookupInfo.Cp2Info; import com.android.dialer.phonelookup.PhoneLookupInfo.Cp2Info.Cp2ContactInfo; +import com.android.dialer.storage.Unencrypted; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.common.util.concurrent.ListenableFuture; @@ -46,6 +49,9 @@ import javax.inject.Inject; /** PhoneLookup implementation for local contacts. */ public final class Cp2PhoneLookup implements PhoneLookup { + private static final String PREF_LAST_TIMESTAMP_PROCESSED = + "cp2PhoneLookupLastTimestampProcessed"; + private static final String[] CP2_INFO_PROJECTION = new String[] { Phone.DISPLAY_NAME_PRIMARY, // 0 @@ -64,10 +70,14 @@ public final class Cp2PhoneLookup implements PhoneLookup { private static final int CP2_INFO_CONTACT_ID_INDEX = 5; private final Context appContext; + private final SharedPreferences sharedPreferences; + @Nullable private Long currentLastTimestampProcessed; @Inject - Cp2PhoneLookup(@ApplicationContext Context appContext) { + Cp2PhoneLookup( + @ApplicationContext Context appContext, @Unencrypted SharedPreferences sharedPreferences) { this.appContext = appContext; + this.sharedPreferences = sharedPreferences; } @Override @@ -76,14 +86,13 @@ public final class Cp2PhoneLookup implements PhoneLookup { } @Override - public ListenableFuture<Boolean> isDirty( - ImmutableSet<DialerPhoneNumber> phoneNumbers, long lastModified) { + public ListenableFuture<Boolean> isDirty(ImmutableSet<DialerPhoneNumber> phoneNumbers) { // TODO(calderwoodra): consider a different thread pool - return MoreExecutors.newDirectExecutorService() - .submit(() -> isDirtyInternal(phoneNumbers, lastModified)); + return MoreExecutors.newDirectExecutorService().submit(() -> isDirtyInternal(phoneNumbers)); } - private boolean isDirtyInternal(ImmutableSet<DialerPhoneNumber> phoneNumbers, long lastModified) { + private boolean isDirtyInternal(ImmutableSet<DialerPhoneNumber> phoneNumbers) { + long lastModified = sharedPreferences.getLong(PREF_LAST_TIMESTAMP_PROCESSED, 0L); return contactsUpdated(queryPhoneTableForContactIds(phoneNumbers), lastModified) || contactsDeleted(lastModified); } @@ -149,7 +158,12 @@ public final class Cp2PhoneLookup implements PhoneLookup { return appContext .getContentResolver() - .query(Contacts.CONTENT_URI, new String[] {Contacts._ID}, where, args, null); + .query( + Contacts.CONTENT_URI, + new String[] {Contacts._ID, Contacts.CONTACT_LAST_UPDATED_TIMESTAMP}, + where, + args, + null); } /** Returns true if any contacts were deleted after {@code lastModified}. */ @@ -169,13 +183,16 @@ public final class Cp2PhoneLookup implements PhoneLookup { @Override public ListenableFuture<ImmutableMap<DialerPhoneNumber, PhoneLookupInfo>> bulkUpdate( - ImmutableMap<DialerPhoneNumber, PhoneLookupInfo> existingInfoMap, long lastModified) { + ImmutableMap<DialerPhoneNumber, PhoneLookupInfo> existingInfoMap) { return MoreExecutors.newDirectExecutorService() - .submit(() -> bulkUpdateInternal(existingInfoMap, lastModified)); + .submit(() -> bulkUpdateInternal(existingInfoMap)); } private ImmutableMap<DialerPhoneNumber, PhoneLookupInfo> bulkUpdateInternal( - ImmutableMap<DialerPhoneNumber, PhoneLookupInfo> existingInfoMap, long lastModified) { + ImmutableMap<DialerPhoneNumber, PhoneLookupInfo> existingInfoMap) { + currentLastTimestampProcessed = null; + long lastModified = sharedPreferences.getLong(PREF_LAST_TIMESTAMP_PROCESSED, 0L); + // Build a set of each DialerPhoneNumber that was associated with a contact, and is no longer // associated with that same contact. Set<DialerPhoneNumber> deletedPhoneNumbers = @@ -214,6 +231,21 @@ public final class Cp2PhoneLookup implements PhoneLookup { return newInfoMapBuilder.build(); } + @Override + public ListenableFuture<Void> onSuccessfulBulkUpdate() { + return MoreExecutors.newDirectExecutorService() + .submit( + () -> { + if (currentLastTimestampProcessed != null) { + sharedPreferences + .edit() + .putLong(PREF_LAST_TIMESTAMP_PROCESSED, currentLastTimestampProcessed) + .apply(); + } + return null; + }); + } + /** * 1. get all contact ids. if the id is unset, add the number to the list of contacts to look up. * 2. reduce our list of contact ids to those that were updated after lastModified. 3. Now we have @@ -261,12 +293,18 @@ public final class Cp2PhoneLookup implements PhoneLookup { // after lastModified, such that Contacts._ID is in our set of contact IDs we build above. try (Cursor cursor = queryContactsTableForContacts(contactIds, lastModified)) { int contactIdIndex = cursor.getColumnIndex(Contacts._ID); + int lastUpdatedIndex = cursor.getColumnIndex(Contacts.CONTACT_LAST_UPDATED_TIMESTAMP); cursor.moveToPosition(-1); while (cursor.moveToNext()) { // Find the DialerPhoneNumber for each contact id and add it to our updated numbers set. // These, along with our number not associated with any Cp2ContactInfo need to be updated. long contactId = cursor.getLong(contactIdIndex); updatedNumbers.addAll(getDialerPhoneNumber(existingInfoMap, contactId)); + long lastUpdatedTimestamp = cursor.getLong(lastUpdatedIndex); + if (currentLastTimestampProcessed == null + || currentLastTimestampProcessed < lastUpdatedTimestamp) { + currentLastTimestampProcessed = lastUpdatedTimestamp; + } } } @@ -379,7 +417,7 @@ public final class Cp2PhoneLookup implements PhoneLookup { .getContentResolver() .query( DeletedContacts.CONTENT_URI, - new String[] {DeletedContacts.CONTACT_ID}, + new String[] {DeletedContacts.CONTACT_ID, DeletedContacts.CONTACT_DELETED_TIMESTAMP}, where, args, null); @@ -389,11 +427,17 @@ public final class Cp2PhoneLookup implements PhoneLookup { private Set<DialerPhoneNumber> findDeletedPhoneNumbersIn( ImmutableMap<DialerPhoneNumber, PhoneLookupInfo> existingInfoMap, Cursor cursor) { int contactIdIndex = cursor.getColumnIndexOrThrow(DeletedContacts.CONTACT_ID); + int deletedTimeIndex = cursor.getColumnIndexOrThrow(DeletedContacts.CONTACT_DELETED_TIMESTAMP); Set<DialerPhoneNumber> deletedPhoneNumbers = new ArraySet<>(); cursor.moveToPosition(-1); while (cursor.moveToNext()) { long contactId = cursor.getLong(contactIdIndex); deletedPhoneNumbers.addAll(getDialerPhoneNumber(existingInfoMap, contactId)); + long deletedTime = cursor.getLong(deletedTimeIndex); + if (currentLastTimestampProcessed == null || currentLastTimestampProcessed < deletedTime) { + // TODO(zachh): There's a problem here if a contact for a new row is deleted? + currentLastTimestampProcessed = deletedTime; + } } return deletedPhoneNumbers; } |