summaryrefslogtreecommitdiff
path: root/java/com/android/dialer/phonelookup
diff options
context:
space:
mode:
authorcalderwoodra <calderwoodra@google.com>2017-10-25 23:16:35 -0700
committerEric Erfanian <erfanian@google.com>2017-10-26 16:39:29 +0000
commit65c21801bf47cf24e2755445545bedabc0f393bf (patch)
tree510aa70e1d1421be75f8f5cea57a6fce51427cbc /java/com/android/dialer/phonelookup
parent94df7203674f12ff90d768467a307ed01601565d (diff)
Cp2 Phonelookup isDirty implementation.
Checks if a cp2 contact has been modified or deleted. Bug: 67605130,64099602 Test: Cp2PhoneLookupTest PiperOrigin-RevId: 173499443 Change-Id: I1fa267c05732fba09f00113232d4370b159aa735
Diffstat (limited to 'java/com/android/dialer/phonelookup')
-rw-r--r--java/com/android/dialer/phonelookup/cp2/Cp2PhoneLookup.java125
1 files changed, 121 insertions, 4 deletions
diff --git a/java/com/android/dialer/phonelookup/cp2/Cp2PhoneLookup.java b/java/com/android/dialer/phonelookup/cp2/Cp2PhoneLookup.java
index 323ec7c65..a3d97c64e 100644
--- a/java/com/android/dialer/phonelookup/cp2/Cp2PhoneLookup.java
+++ b/java/com/android/dialer/phonelookup/cp2/Cp2PhoneLookup.java
@@ -16,21 +16,138 @@
package com.android.dialer.phonelookup.cp2;
+import android.content.Context;
+import android.database.Cursor;
+import android.provider.ContactsContract.CommonDataKinds.Phone;
+import android.provider.ContactsContract.Contacts;
+import android.provider.ContactsContract.DeletedContacts;
+import android.support.v4.util.ArraySet;
import com.android.dialer.DialerPhoneNumber;
+import com.android.dialer.common.concurrent.DialerExecutors;
import com.android.dialer.phonelookup.PhoneLookup;
import com.android.dialer.phonelookup.PhoneLookupInfo;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.MoreExecutors;
+import java.util.Set;
-/** TODO(calderwoodra) */
-final class Cp2PhoneLookup implements PhoneLookup {
+/** PhoneLookup implementation for local contacts. */
+public final class Cp2PhoneLookup implements PhoneLookup {
+
+ private final Context context;
+
+ Cp2PhoneLookup(Context context) {
+ this.context = context;
+ }
@Override
public ListenableFuture<Boolean> isDirty(
ImmutableSet<DialerPhoneNumber> phoneNumbers, long lastModified) {
- // TODO(calderwoodra)
- return null;
+ // TODO(calderwoodra): consider a different thread pool
+ return MoreExecutors.listeningDecorator(DialerExecutors.getLowPriorityThreadPool(context))
+ .submit(() -> isDirtyInternal(phoneNumbers, lastModified));
+ }
+
+ private boolean isDirtyInternal(ImmutableSet<DialerPhoneNumber> phoneNumbers, long lastModified) {
+ return contactsUpdated(getContactIdsFromPhoneNumbers(phoneNumbers), lastModified)
+ || contactsDeleted(lastModified);
+ }
+
+ /** Returns set of contact ids that correspond to {@code phoneNumbers} if the contact exists. */
+ private Set<Long> getContactIdsFromPhoneNumbers(ImmutableSet<DialerPhoneNumber> phoneNumbers) {
+ Set<Long> contactIds = new ArraySet<>();
+ try (Cursor cursor =
+ context
+ .getContentResolver()
+ .query(
+ Phone.CONTENT_URI,
+ new String[] {Phone.CONTACT_ID},
+ columnInSetWhereStatement(Phone.NORMALIZED_NUMBER, phoneNumbers.size()),
+ contactIdsSelectionArgs(phoneNumbers),
+ null)) {
+ cursor.moveToPosition(-1);
+ while (cursor.moveToNext()) {
+ contactIds.add(cursor.getLong(0 /* columnIndex */));
+ }
+ }
+ return contactIds;
+ }
+
+ private static String[] contactIdsSelectionArgs(ImmutableSet<DialerPhoneNumber> phoneNumbers) {
+ String[] args = new String[phoneNumbers.size()];
+ int i = 0;
+ for (DialerPhoneNumber phoneNumber : phoneNumbers) {
+ args[i++] = getNormalizedNumber(phoneNumber);
+ }
+ return args;
+ }
+
+ private static String getNormalizedNumber(DialerPhoneNumber phoneNumber) {
+ // TODO(calderwoodra): implement normalization logic that matches contacts.
+ return phoneNumber.getRawInput().getNumber();
+ }
+
+ /** Returns true if any contacts were modified after {@code lastModified}. */
+ private boolean contactsUpdated(Set<Long> contactIds, long lastModified) {
+ try (Cursor cursor =
+ context
+ .getContentResolver()
+ .query(
+ Contacts.CONTENT_URI,
+ new String[] {Contacts._ID},
+ contactsIsDirtyWhereStatement(contactIds.size()),
+ contactsIsDirtySelectionArgs(lastModified, contactIds),
+ null)) {
+ return cursor.getCount() > 0;
+ }
+ }
+
+ private static String contactsIsDirtyWhereStatement(int numberOfContactIds) {
+ StringBuilder where = new StringBuilder();
+ // Filter to after last modified time
+ where.append(Contacts.CONTACT_LAST_UPDATED_TIMESTAMP).append(" > ?");
+
+ // Filter based only on contacts we care about
+ where.append(" AND ").append(columnInSetWhereStatement(Contacts._ID, numberOfContactIds));
+ return where.toString();
+ }
+
+ private String[] contactsIsDirtySelectionArgs(long lastModified, Set<Long> contactIds) {
+ String[] args = new String[contactIds.size() + 1];
+ args[0] = Long.toString(lastModified);
+ int i = 1;
+ for (Long contactId : contactIds) {
+ args[i++] = Long.toString(contactId);
+ }
+ return args;
+ }
+
+ /** Returns true if any contacts were deleted after {@code lastModified}. */
+ private boolean contactsDeleted(long lastModified) {
+ try (Cursor cursor =
+ context
+ .getContentResolver()
+ .query(
+ DeletedContacts.CONTENT_URI,
+ new String[] {DeletedContacts.CONTACT_DELETED_TIMESTAMP},
+ DeletedContacts.CONTACT_DELETED_TIMESTAMP + " > ?",
+ new String[] {Long.toString(lastModified)},
+ null)) {
+ return cursor.getCount() > 0;
+ }
+ }
+
+ private static String columnInSetWhereStatement(String columnName, int setSize) {
+ StringBuilder where = new StringBuilder();
+ where.append(columnName).append(" IN (");
+ for (int i = 0; i < setSize; i++) {
+ if (i != 0) {
+ where.append(", ");
+ }
+ where.append("?");
+ }
+ return where.append(")").toString();
}
@Override