Fix collapsing to do fuzzy phone number matching.
-Also use Collapser to collapse the numbers shown in the context menu
from the A-Z list.
Fixes http://b/issue?id=2047514 and http://b/issue?id=2144616
Change-Id: Ice18ecc306c2f30fd1525418bc9f7408c4435a50
diff --git a/src/com/android/contacts/Collapser.java b/src/com/android/contacts/Collapser.java
index db1da1f..3872dfd 100644
--- a/src/com/android/contacts/Collapser.java
+++ b/src/com/android/contacts/Collapser.java
@@ -39,38 +39,42 @@
*/
public interface Collapsible<T> {
public boolean collapseWith(T t);
- public String getCollapseKey();
+ public boolean shouldCollapseWith(T t);
}
/**
* Collapses a list of Collapsible items into a list of collapsed items. Items are collapsed
- * if they produce equal collapseKeys {@Link Collapsible#getCollapseKey()}, and are collapsed
- * through the {@Link Collapsible#doCollapseWith(Object)} function implemented by the data item.
+ * if {@link Collapsible#shouldCollapseWith(Object) return strue, and are collapsed
+ * through the {@Link Collapsible#collapseWith(Object)} function implemented by the data item.
*
* @param list ArrayList of Objects of type <T extends Collapsible<T>> to be collapsed.
*/
public static <T extends Collapsible<T>> void collapseList(ArrayList<T> list) {
- HashMap<String, T> collapseMap = new HashMap<String, T>();
- ArrayList<String> collapseKeys = new ArrayList<String>();
int listSize = list.size();
- for (int j = 0; j < listSize; j++) {
- T entry = list.get(j);
- String collapseKey = entry.getCollapseKey();
- if (!collapseMap.containsKey(collapseKey)) {
- collapseMap.put(collapseKey, entry);
- collapseKeys.add(collapseKey);
- } else {
- collapseMap.get(collapseKey).collapseWith(entry);
+
+ for (int i = 0; i < listSize; i++) {
+ T iItem = list.get(i);
+ if (iItem != null) {
+ for (int j = i + 1; j < listSize; j++) {
+ T jItem = list.get(j);
+ if (jItem != null) {
+ if (iItem.shouldCollapseWith(jItem)) {
+ iItem.collapseWith(jItem);
+ list.set(j, null);
+ }
+ }
+ }
}
}
- if (collapseKeys.size() < listSize) {
- list.clear();
- Iterator<String> itr = collapseKeys.iterator();
- while (itr.hasNext()) {
- list.add(collapseMap.get(itr.next()));
+ // Remove the null items
+ Iterator<T> itr = list.iterator();
+ while (itr.hasNext()) {
+ if (itr.next() == null) {
+ itr.remove();
}
}
+
}
}
diff --git a/src/com/android/contacts/ContactsListActivity.java b/src/com/android/contacts/ContactsListActivity.java
index cc2f02f..fac461f 100644
--- a/src/com/android/contacts/ContactsListActivity.java
+++ b/src/com/android/contacts/ContactsListActivity.java
@@ -1754,7 +1754,7 @@
getColumnIndex(Phone.IS_SUPER_PRIMARY)) != 0) {
// Found super primary, call it.
phone = phonesCursor.
- getString(phonesCursor.getColumnIndex(Phone.NUMBER));
+ getString(phonesCursor.getColumnIndex(Phone.NUMBER));
break;
}
}
diff --git a/src/com/android/contacts/PhoneDisambigDialog.java b/src/com/android/contacts/PhoneDisambigDialog.java
index 58d3721..b727c77 100644
--- a/src/com/android/contacts/PhoneDisambigDialog.java
+++ b/src/com/android/contacts/PhoneDisambigDialog.java
@@ -17,8 +17,9 @@
package com.android.contacts;
import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
+import java.util.List;
+
+import com.android.contacts.Collapser.Collapsible;
import android.app.AlertDialog;
import android.content.ContentUris;
@@ -28,12 +29,13 @@
import android.database.Cursor;
import android.provider.ContactsContract.Data;
import android.provider.ContactsContract.CommonDataKinds.Phone;
+import android.telephony.PhoneNumberUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.CheckBox;
import android.widget.CompoundButton;
-import android.widget.SimpleCursorAdapter;
+import android.widget.ListAdapter;
/**
* Class used for displaying a dialog with a list of phone numbers of which
@@ -47,6 +49,8 @@
private AlertDialog mDialog;
private boolean mSendSms;
private Cursor mPhonesCursor;
+ private ListAdapter mPhonesAdapter;
+ private ArrayList<PhoneItem> mPhoneItemList;
public PhoneDisambigDialog(Context context, Cursor phonesCursor) {
this(context, phonesCursor, false /*make call*/);
@@ -57,6 +61,11 @@
mSendSms = sendSms;
mPhonesCursor = phonesCursor;
+ mPhoneItemList = makePhoneItemsList(phonesCursor);
+ Collapser.collapseList(mPhoneItemList);
+
+ mPhonesAdapter = new PhonesAdapter(mContext, mPhoneItemList);
+
LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(
Context.LAYOUT_INFLATER_SERVICE);
View setPrimaryView = inflater.
@@ -66,9 +75,10 @@
// Need to show disambig dialogue.
AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(mContext).
- setCursor(mPhonesCursor, this, Phone.NUMBER).
- setTitle(sendSms ? R.string.sms_disambig_title : R.string.call_disambig_title).
- setView(setPrimaryView);
+ setAdapter(mPhonesAdapter, this).
+ setTitle(sendSms ?
+ R.string.sms_disambig_title : R.string.call_disambig_title).
+ setView(setPrimaryView);
mDialog = dialogBuilder.create();
}
@@ -77,18 +87,25 @@
* Show the dialog.
*/
public void show() {
+ if (mPhoneItemList.size() == 1) {
+ // If there is only one after collapse, just select it, and close;
+ onClick(mDialog, 0);
+ return;
+ }
mDialog.show();
}
public void onClick(DialogInterface dialog, int which) {
- if (mPhonesCursor.moveToPosition(which)) {
- long id = mPhonesCursor.getLong(mPhonesCursor.getColumnIndex(Data._ID));
- String phone = mPhonesCursor.getString(mPhonesCursor.getColumnIndex(Phone.NUMBER));
+ if (mPhoneItemList.size() > which && which >= 0) {
+ PhoneItem phoneItem = mPhoneItemList.get(which);
+ long id = phoneItem.id;
+ String phone = phoneItem.phoneNumber;
+
if (mMakePrimary) {
ContentValues values = new ContentValues(1);
values.put(Data.IS_SUPER_PRIMARY, 1);
- mContext.getContentResolver().update(ContentUris.withAppendedId(Data.CONTENT_URI, id),
- values, null, null);
+ mContext.getContentResolver().update(ContentUris.
+ withAppendedId(Data.CONTENT_URI, id), values, null, null);
}
if (mSendSms) {
@@ -108,4 +125,56 @@
public void onDismiss(DialogInterface dialog) {
mPhonesCursor.close();
}
+
+ private static class PhonesAdapter extends ArrayAdapter<PhoneItem> {
+
+ public PhonesAdapter(Context context, List<PhoneItem> objects) {
+ super(context, android.R.layout.simple_dropdown_item_1line,
+ android.R.id.text1, objects);
+ }
+ }
+
+ private class PhoneItem implements Collapsible<PhoneItem> {
+
+ String phoneNumber;
+ long id;
+
+ public PhoneItem(String newPhoneNumber, long newId) {
+ phoneNumber = newPhoneNumber;
+ id = newId;
+ }
+
+ public boolean collapseWith(PhoneItem phoneItem) {
+ if (!shouldCollapseWith(phoneItem)) {
+ return false;
+ }
+ // Just keep the number and id we already have.
+ return true;
+ }
+
+ public boolean shouldCollapseWith(PhoneItem phoneItem) {
+ if (PhoneNumberUtils.compare(PhoneDisambigDialog.this.mContext,
+ phoneNumber, phoneItem.phoneNumber)) {
+ return true;
+ }
+ return false;
+ }
+
+ public String toString() {
+ return phoneNumber;
+ }
+ }
+
+ private ArrayList<PhoneItem> makePhoneItemsList(Cursor phonesCursor) {
+ ArrayList<PhoneItem> phoneList = new ArrayList<PhoneItem>();
+
+ phonesCursor.moveToPosition(-1);
+ while (phonesCursor.moveToNext()) {
+ long id = phonesCursor.getLong(phonesCursor.getColumnIndex(Data._ID));
+ String phone = phonesCursor.getString(phonesCursor.getColumnIndex(Phone.NUMBER));
+ phoneList.add(new PhoneItem(phone, id));
+ }
+
+ return phoneList;
+ }
}
diff --git a/src/com/android/contacts/ViewContactActivity.java b/src/com/android/contacts/ViewContactActivity.java
index 8275686..b1910d6 100644
--- a/src/com/android/contacts/ViewContactActivity.java
+++ b/src/com/android/contacts/ViewContactActivity.java
@@ -1154,7 +1154,7 @@
/**
* A basic structure with the data for a contact entry in the list.
*/
- static class ViewEntry extends ContactEntryAdapter.Entry implements Collapsible<ViewEntry> {
+ class ViewEntry extends ContactEntryAdapter.Entry implements Collapsible<ViewEntry> {
public String resPackageName = null;
public int actionIcon = -1;
public boolean isPrimary = false;
@@ -1169,7 +1169,7 @@
public boolean collapseWith(ViewEntry entry) {
// assert equal collapse keys
- if (!getCollapseKey().equals(entry.getCollapseKey())) {
+ if (!shouldCollapseWith(entry)) {
return false;
}
@@ -1201,16 +1201,43 @@
return true;
}
- public String getCollapseKey() {
- StringBuilder hashSb = new StringBuilder();
- hashSb.append(data);
- hashSb.append(mimetype);
- hashSb.append((intent != null && intent.getAction() != null)
- ? intent.getAction() : "");
- hashSb.append((secondaryIntent != null && secondaryIntent.getAction() != null)
- ? secondaryIntent.getAction() : "");
- hashSb.append(actionIcon);
- return hashSb.toString();
+ public boolean shouldCollapseWith(ViewEntry entry) {
+ if (entry == null) {
+ return false;
+ }
+
+ if (Phone.CONTENT_ITEM_TYPE.equals(mimetype)
+ && Phone.CONTENT_ITEM_TYPE.equals(entry.mimetype)) {
+ if (!PhoneNumberUtils.compare(ViewContactActivity.this, data, entry.data)) {
+ return false;
+ }
+ } else {
+ if (!equals(data, entry.data)) {
+ return false;
+ }
+ }
+
+ if (!equals(mimetype, entry.mimetype)
+ || !intentCollapsible(intent, entry.intent)
+ || !intentCollapsible(secondaryIntent, entry.secondaryIntent)
+ || actionIcon != entry.actionIcon) {
+ return false;
+ }
+
+ return true;
+ }
+
+ private boolean equals(Object a, Object b) {
+ return a==b || (a != null && a.equals(b));
+ }
+
+ private boolean intentCollapsible(Intent a, Intent b) {
+ if (a == b) {
+ return true;
+ } else if ((a != null && b != null) && equals(a.getAction(), b.getAction())) {
+ return true;
+ }
+ return false;
}
}