RecipientAlternatesAdapterpublic class RecipientAlternatesAdapter extends android.widget.CursorAdapter RecipientAlternatesAdapter backs the RecipientEditTextView for managing contacts
queried by email or by phone number. |
Fields Summary |
---|
public static final int | MAX_LOOKUPS | private final long | mCurrentId | private int | mCheckedItemPosition | private OnCheckedItemChangedListener | mCheckedItemChangedListener | private static final String | TAG | public static final int | QUERY_TYPE_EMAIL | public static final int | QUERY_TYPE_PHONE | private final Long | mDirectoryId | private DropdownChipLayouter | mDropdownChipLayouter | private final android.graphics.drawable.StateListDrawable | mDeleteDrawable | private static final Map | sCorrectedPhotoUris |
Constructors Summary |
---|
public RecipientAlternatesAdapter(android.content.Context context, long contactId, Long directoryId, String lookupKey, long currentId, int queryMode, OnCheckedItemChangedListener listener, DropdownChipLayouter dropdownChipLayouter, android.graphics.drawable.StateListDrawable deleteDrawable)
super(context,
getCursorForConstruction(context, contactId, directoryId, lookupKey, queryMode), 0);
mCurrentId = currentId;
mDirectoryId = directoryId;
mCheckedItemChangedListener = listener;
mDropdownChipLayouter = dropdownChipLayouter;
mDeleteDrawable = deleteDrawable;
| public RecipientAlternatesAdapter(android.content.Context context, long contactId, Long directoryId, String lookupKey, long currentId, int queryMode, OnCheckedItemChangedListener listener, DropdownChipLayouter dropdownChipLayouter)
this(context, contactId, directoryId, lookupKey, currentId, queryMode, listener,
dropdownChipLayouter, null);
|
Methods Summary |
---|
public void | bindView(android.view.View view, android.content.Context context, android.database.Cursor cursor)
int position = cursor.getPosition();
RecipientEntry entry = getRecipientEntry(position);
mDropdownChipLayouter.bindView(view, null, entry, position,
AdapterType.RECIPIENT_ALTERNATES, null, mDeleteDrawable);
| private static android.database.Cursor | doQuery(java.lang.CharSequence constraint, int limit, java.lang.Long directoryId, android.accounts.Account account, android.content.ContentResolver resolver, com.android.ex.chips.Queries.Query query)
final Uri.Builder builder = query
.getContentFilterUri()
.buildUpon()
.appendPath(constraint.toString())
.appendQueryParameter(ContactsContract.LIMIT_PARAM_KEY,
String.valueOf(limit + BaseRecipientAdapter.ALLOWANCE_FOR_DUPLICATES));
if (directoryId != null) {
builder.appendQueryParameter(ContactsContract.DIRECTORY_PARAM_KEY,
String.valueOf(directoryId));
}
if (account != null) {
builder.appendQueryParameter(BaseRecipientAdapter.PRIMARY_ACCOUNT_NAME, account.name);
builder.appendQueryParameter(BaseRecipientAdapter.PRIMARY_ACCOUNT_TYPE, account.type);
}
final Cursor cursor = resolver.query(builder.build(), query.getProjection(), null, null,
null);
return cursor;
| static RecipientEntry | getBetterRecipient(RecipientEntry entry1, RecipientEntry entry2)Given two {@link RecipientEntry}s for the same email address, this will return the one that
contains more complete information for display purposes. Defaults to entry2 if
no significant differences are found.
// If only one has passed in, use it
if (entry2 == null) {
return entry1;
}
if (entry1 == null) {
return entry2;
}
// If only one has a display name, use it
if (!TextUtils.isEmpty(entry1.getDisplayName())
&& TextUtils.isEmpty(entry2.getDisplayName())) {
return entry1;
}
if (!TextUtils.isEmpty(entry2.getDisplayName())
&& TextUtils.isEmpty(entry1.getDisplayName())) {
return entry2;
}
// If only one has a display name that is not the same as the destination, use it
if (!TextUtils.equals(entry1.getDisplayName(), entry1.getDestination())
&& TextUtils.equals(entry2.getDisplayName(), entry2.getDestination())) {
return entry1;
}
if (!TextUtils.equals(entry2.getDisplayName(), entry2.getDestination())
&& TextUtils.equals(entry1.getDisplayName(), entry1.getDestination())) {
return entry2;
}
// If only one has a photo, use it
if ((entry1.getPhotoThumbnailUri() != null || entry1.getPhotoBytes() != null)
&& (entry2.getPhotoThumbnailUri() == null && entry2.getPhotoBytes() == null)) {
return entry1;
}
if ((entry2.getPhotoThumbnailUri() != null || entry2.getPhotoBytes() != null)
&& (entry1.getPhotoThumbnailUri() == null && entry1.getPhotoBytes() == null)) {
return entry2;
}
// Go with the second option as a default
return entry2;
| private static android.database.Cursor | getCursorForConstruction(android.content.Context context, long contactId, java.lang.Long directoryId, java.lang.String lookupKey, int queryType)
final Cursor cursor;
final String desiredMimeType;
if (queryType == QUERY_TYPE_EMAIL) {
final Uri uri;
final StringBuilder selection = new StringBuilder();
selection.append(Queries.EMAIL.getProjection()[Queries.Query.CONTACT_ID]);
selection.append(" = ?");
if (directoryId == null || lookupKey == null) {
uri = Queries.EMAIL.getContentUri();
desiredMimeType = null;
} else {
final Uri.Builder builder = Contacts.getLookupUri(contactId, lookupKey).buildUpon();
builder.appendPath(Contacts.Entity.CONTENT_DIRECTORY)
.appendQueryParameter(ContactsContract.DIRECTORY_PARAM_KEY,
String.valueOf(directoryId));
uri = builder.build();
desiredMimeType = ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE;
}
cursor = context.getContentResolver().query(
uri,
Queries.EMAIL.getProjection(),
selection.toString(), new String[] {
String.valueOf(contactId)
}, null);
} else {
final Uri uri;
final StringBuilder selection = new StringBuilder();
selection.append(Queries.PHONE.getProjection()[Queries.Query.CONTACT_ID]);
selection.append(" = ?");
if (lookupKey == null) {
uri = Queries.PHONE.getContentUri();
desiredMimeType = null;
} else {
final Uri.Builder builder = Contacts.getLookupUri(contactId, lookupKey).buildUpon();
builder.appendPath(Contacts.Entity.CONTENT_DIRECTORY)
.appendQueryParameter(ContactsContract.DIRECTORY_PARAM_KEY,
String.valueOf(directoryId));
uri = builder.build();
desiredMimeType = ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE;
}
cursor = context.getContentResolver().query(
uri,
Queries.PHONE.getProjection(),
selection.toString(), new String[] {
String.valueOf(contactId)
}, null);
}
final Cursor resultCursor = removeUndesiredDestinations(cursor, desiredMimeType, lookupKey);
cursor.close();
return resultCursor;
| public long | getItemId(int position)
Cursor c = getCursor();
if (c.moveToPosition(position)) {
c.getLong(Queries.Query.DATA_ID);
}
return -1;
| public static void | getMatchingRecipients(android.content.Context context, BaseRecipientAdapter adapter, java.util.ArrayList inAddresses, android.accounts.Account account, com.android.ex.chips.RecipientAlternatesAdapter$RecipientMatchCallback callback)
getMatchingRecipients(context, adapter, inAddresses, QUERY_TYPE_EMAIL, account, callback);
| public static void | getMatchingRecipients(android.content.Context context, BaseRecipientAdapter adapter, java.util.ArrayList inAddresses, int addressType, android.accounts.Account account, com.android.ex.chips.RecipientAlternatesAdapter$RecipientMatchCallback callback)Get a HashMap of address to RecipientEntry that contains all contact
information for a contact with the provided address, if one exists. This
may block the UI, so run it in an async task.
Queries.Query query;
if (addressType == QUERY_TYPE_EMAIL) {
query = Queries.EMAIL;
} else {
query = Queries.PHONE;
}
int addressesSize = Math.min(MAX_LOOKUPS, inAddresses.size());
HashSet<String> addresses = new HashSet<String>();
StringBuilder bindString = new StringBuilder();
// Create the "?" string and set up arguments.
for (int i = 0; i < addressesSize; i++) {
Rfc822Token[] tokens = Rfc822Tokenizer.tokenize(inAddresses.get(i).toLowerCase());
addresses.add(tokens.length > 0 ? tokens[0].getAddress() : inAddresses.get(i));
bindString.append("?");
if (i < addressesSize - 1) {
bindString.append(",");
}
}
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "Doing reverse lookup for " + addresses.toString());
}
String[] addressArray = new String[addresses.size()];
addresses.toArray(addressArray);
HashMap<String, RecipientEntry> recipientEntries = null;
Cursor c = null;
try {
c = context.getContentResolver().query(
query.getContentUri(),
query.getProjection(),
query.getProjection()[Queries.Query.DESTINATION] + " IN ("
+ bindString.toString() + ")", addressArray, null);
recipientEntries = processContactEntries(c, null /* directoryId */);
callback.matchesFound(recipientEntries);
} finally {
if (c != null) {
c.close();
}
}
final Set<String> matchesNotFound = new HashSet<String>();
getMatchingRecipientsFromDirectoryQueries(context, recipientEntries,
addresses, account, matchesNotFound, query, callback);
getMatchingRecipientsFromExtensionMatcher(adapter, matchesNotFound, callback);
| public static void | getMatchingRecipientsFromDirectoryQueries(android.content.Context context, java.util.Map recipientEntries, java.util.Set addresses, android.accounts.Account account, java.util.Set matchesNotFound, com.android.ex.chips.RecipientAlternatesAdapter$RecipientMatchCallback callback)
getMatchingRecipientsFromDirectoryQueries(
context, recipientEntries, addresses, account,
matchesNotFound, Queries.EMAIL, callback);
| private static void | getMatchingRecipientsFromDirectoryQueries(android.content.Context context, java.util.Map recipientEntries, java.util.Set addresses, android.accounts.Account account, java.util.Set matchesNotFound, com.android.ex.chips.Queries.Query query, com.android.ex.chips.RecipientAlternatesAdapter$RecipientMatchCallback callback)
// See if any entries did not resolve; if so, we need to check other
// directories
if (recipientEntries.size() < addresses.size()) {
final List<DirectorySearchParams> paramsList;
Cursor directoryCursor = null;
try {
directoryCursor = context.getContentResolver().query(DirectoryListQuery.URI,
DirectoryListQuery.PROJECTION, null, null, null);
if (directoryCursor == null) {
paramsList = null;
} else {
paramsList = BaseRecipientAdapter.setupOtherDirectories(context,
directoryCursor, account);
}
} finally {
if (directoryCursor != null) {
directoryCursor.close();
}
}
// Run a directory query for each unmatched recipient.
HashSet<String> unresolvedAddresses = new HashSet<String>();
for (String address : addresses) {
if (!recipientEntries.containsKey(address)) {
unresolvedAddresses.add(address);
}
}
matchesNotFound.addAll(unresolvedAddresses);
if (paramsList != null) {
Cursor directoryContactsCursor = null;
for (String unresolvedAddress : unresolvedAddresses) {
Long directoryId = null;
for (int i = 0; i < paramsList.size(); i++) {
try {
directoryContactsCursor = doQuery(unresolvedAddress, 1,
paramsList.get(i).directoryId, account,
context.getContentResolver(), query);
} finally {
if (directoryContactsCursor != null
&& directoryContactsCursor.getCount() == 0) {
directoryContactsCursor.close();
directoryContactsCursor = null;
} else {
directoryId = paramsList.get(i).directoryId;
break;
}
}
}
if (directoryContactsCursor != null) {
try {
final Map<String, RecipientEntry> entries =
processContactEntries(directoryContactsCursor, directoryId);
for (final String address : entries.keySet()) {
matchesNotFound.remove(address);
}
callback.matchesFound(entries);
} finally {
directoryContactsCursor.close();
}
}
}
}
}
| public static void | getMatchingRecipientsFromExtensionMatcher(BaseRecipientAdapter adapter, java.util.Set matchesNotFound, com.android.ex.chips.RecipientAlternatesAdapter$RecipientMatchCallback callback)
// If no matches found in contact provider or the directories, try the extension
// matcher.
// todo (aalbert): This whole method needs to be in the adapter?
if (adapter != null) {
final Map<String, RecipientEntry> entries =
adapter.getMatchingRecipients(matchesNotFound);
if (entries != null && entries.size() > 0) {
callback.matchesFound(entries);
for (final String address : entries.keySet()) {
matchesNotFound.remove(address);
}
}
}
callback.matchesNotFound(matchesNotFound);
| public RecipientEntry | getRecipientEntry(int position)
Cursor c = getCursor();
c.moveToPosition(position);
return RecipientEntry.constructTopLevelEntry(
c.getString(Queries.Query.NAME),
c.getInt(Queries.Query.DISPLAY_NAME_SOURCE),
c.getString(Queries.Query.DESTINATION),
c.getInt(Queries.Query.DESTINATION_TYPE),
c.getString(Queries.Query.DESTINATION_LABEL),
c.getLong(Queries.Query.CONTACT_ID),
mDirectoryId,
c.getLong(Queries.Query.DATA_ID),
c.getString(Queries.Query.PHOTO_THUMBNAIL_URI),
true,
c.getString(Queries.Query.LOOKUP_KEY));
| public android.view.View | getView(int position, android.view.View convertView, android.view.ViewGroup parent)
Cursor cursor = getCursor();
cursor.moveToPosition(position);
if (convertView == null) {
convertView = mDropdownChipLayouter.newView(AdapterType.RECIPIENT_ALTERNATES);
}
if (cursor.getLong(Queries.Query.DATA_ID) == mCurrentId) {
mCheckedItemPosition = position;
if (mCheckedItemChangedListener != null) {
mCheckedItemChangedListener.onCheckedItemChanged(mCheckedItemPosition);
}
}
bindView(convertView, convertView.getContext(), cursor);
return convertView;
| public android.view.View | newView(android.content.Context context, android.database.Cursor cursor, android.view.ViewGroup parent)
return mDropdownChipLayouter.newView(AdapterType.RECIPIENT_ALTERNATES);
| private static java.util.HashMap | processContactEntries(android.database.Cursor c, java.lang.Long directoryId)
HashMap<String, RecipientEntry> recipientEntries = new HashMap<String, RecipientEntry>();
if (c != null && c.moveToFirst()) {
do {
String address = c.getString(Queries.Query.DESTINATION);
final RecipientEntry newRecipientEntry = RecipientEntry.constructTopLevelEntry(
c.getString(Queries.Query.NAME),
c.getInt(Queries.Query.DISPLAY_NAME_SOURCE),
c.getString(Queries.Query.DESTINATION),
c.getInt(Queries.Query.DESTINATION_TYPE),
c.getString(Queries.Query.DESTINATION_LABEL),
c.getLong(Queries.Query.CONTACT_ID),
directoryId,
c.getLong(Queries.Query.DATA_ID),
c.getString(Queries.Query.PHOTO_THUMBNAIL_URI),
true,
c.getString(Queries.Query.LOOKUP_KEY));
/*
* In certain situations, we may have two results for one address, where one of the
* results is just the email address, and the other has a name and photo, so we want
* to use the better one.
*/
final RecipientEntry recipientEntry =
getBetterRecipient(recipientEntries.get(address), newRecipientEntry);
recipientEntries.put(address, recipientEntry);
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "Received reverse look up information for " + address
+ " RESULTS: "
+ " NAME : " + c.getString(Queries.Query.NAME)
+ " CONTACT ID : " + c.getLong(Queries.Query.CONTACT_ID)
+ " ADDRESS :" + c.getString(Queries.Query.DESTINATION));
}
} while (c.moveToNext());
}
return recipientEntries;
| static android.database.Cursor | removeUndesiredDestinations(android.database.Cursor original, java.lang.String desiredMimeType, java.lang.String lookupKey)
final MatrixCursor result = new MatrixCursor(
original.getColumnNames(), original.getCount());
final HashSet<String> destinationsSeen = new HashSet<String>();
String defaultDisplayName = null;
String defaultPhotoThumbnailUri = null;
int defaultDisplayNameSource = 0;
// Find some nice defaults in case we need them
original.moveToPosition(-1);
while (original.moveToNext()) {
final String mimeType = original.getString(Query.MIME_TYPE);
if (ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE.equals(
mimeType)) {
// Store this data
defaultDisplayName = original.getString(Query.NAME);
defaultPhotoThumbnailUri = original.getString(Query.PHOTO_THUMBNAIL_URI);
defaultDisplayNameSource = original.getInt(Query.DISPLAY_NAME_SOURCE);
break;
}
}
original.moveToPosition(-1);
while (original.moveToNext()) {
if (desiredMimeType != null) {
final String mimeType = original.getString(Query.MIME_TYPE);
if (!desiredMimeType.equals(mimeType)) {
continue;
}
}
final String destination = original.getString(Query.DESTINATION);
if (destinationsSeen.contains(destination)) {
continue;
}
destinationsSeen.add(destination);
final Object[] row = new Object[] {
original.getString(Query.NAME),
original.getString(Query.DESTINATION),
original.getInt(Query.DESTINATION_TYPE),
original.getString(Query.DESTINATION_LABEL),
original.getLong(Query.CONTACT_ID),
original.getLong(Query.DATA_ID),
original.getString(Query.PHOTO_THUMBNAIL_URI),
original.getInt(Query.DISPLAY_NAME_SOURCE),
original.getString(Query.LOOKUP_KEY),
original.getString(Query.MIME_TYPE)
};
if (row[Query.NAME] == null) {
row[Query.NAME] = defaultDisplayName;
}
if (row[Query.PHOTO_THUMBNAIL_URI] == null) {
row[Query.PHOTO_THUMBNAIL_URI] = defaultPhotoThumbnailUri;
}
if ((Integer) row[Query.DISPLAY_NAME_SOURCE] == 0) {
row[Query.DISPLAY_NAME_SOURCE] = defaultDisplayNameSource;
}
if (row[Query.LOOKUP_KEY] == null) {
row[Query.LOOKUP_KEY] = lookupKey;
}
// Ensure we don't have two '?' like content://.../...?account_name=...?sz=...
final String photoThumbnailUri = (String) row[Query.PHOTO_THUMBNAIL_URI];
if (photoThumbnailUri != null) {
if (sCorrectedPhotoUris.containsKey(photoThumbnailUri)) {
row[Query.PHOTO_THUMBNAIL_URI] = sCorrectedPhotoUris.get(photoThumbnailUri);
} else if (photoThumbnailUri.indexOf('?") != photoThumbnailUri.lastIndexOf('?")) {
final String[] parts = photoThumbnailUri.split("\\?");
final StringBuilder correctedUriBuilder = new StringBuilder();
for (int i = 0; i < parts.length; i++) {
if (i == 1) {
correctedUriBuilder.append("?"); // We only want one of these
} else if (i > 1) {
correctedUriBuilder.append("&"); // And we want these elsewhere
}
correctedUriBuilder.append(parts[i]);
}
final String correctedUri = correctedUriBuilder.toString();
sCorrectedPhotoUris.put(photoThumbnailUri, correctedUri);
row[Query.PHOTO_THUMBNAIL_URI] = correctedUri;
}
}
result.addRow(row);
}
return result;
|
|