RecipientAlternatesAdapter.java revision 9c17ab5f3bf0f88e3641faf98931c4f9e7d65366
1/* 2 * Copyright (C) 2011 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.ex.chips; 18 19import android.content.Context; 20import android.database.Cursor; 21import android.text.util.Rfc822Token; 22import android.text.util.Rfc822Tokenizer; 23import android.util.Log; 24import android.view.LayoutInflater; 25import android.view.View; 26import android.view.ViewGroup; 27import android.widget.CursorAdapter; 28import android.widget.ImageView; 29import android.widget.TextView; 30 31import com.android.ex.chips.Queries.Query; 32import java.util.HashMap; 33 34/** 35 * RecipientAlternatesAdapter backs the RecipientEditTextView for managing contacts 36 * queried by email or by phone number. 37 */ 38public class RecipientAlternatesAdapter extends CursorAdapter { 39 static final int MAX_LOOKUPS = 50; 40 private final LayoutInflater mLayoutInflater; 41 42 private final long mCurrentId; 43 44 private int mCheckedItemPosition = -1; 45 46 private OnCheckedItemChangedListener mCheckedItemChangedListener; 47 48 private static final String TAG = "RecipAlternates"; 49 50 public static final int QUERY_TYPE_EMAIL = 0; 51 public static final int QUERY_TYPE_PHONE = 1; 52 private Query mQuery; 53 54 public static HashMap<String, RecipientEntry> getMatchingRecipients(Context context, 55 String[] inAddresses) { 56 return getMatchingRecipients(context, inAddresses, QUERY_TYPE_EMAIL); 57 } 58 59 /** 60 * Get a HashMap of address to RecipientEntry that contains all contact 61 * information for a contact with the provided address, if one exists. This 62 * may block the UI, so run it in an async task. 63 * 64 * @param context Context. 65 * @param inAddresses Array of addresses on which to perform the lookup. 66 * @return HashMap<String,RecipientEntry> 67 */ 68 public static HashMap<String, RecipientEntry> getMatchingRecipients(Context context, 69 String[] inAddresses, int addressType) { 70 Queries.Query query; 71 if (addressType == QUERY_TYPE_EMAIL) { 72 query = Queries.EMAIL; 73 } else { 74 query = Queries.PHONE; 75 } 76 int addressesSize = Math.min(MAX_LOOKUPS, inAddresses.length); 77 String[] addresses = new String[addressesSize]; 78 StringBuilder bindString = new StringBuilder(); 79 // Create the "?" string and set up arguments. 80 for (int i = 0; i < addressesSize; i++) { 81 Rfc822Token[] tokens = Rfc822Tokenizer.tokenize(inAddresses[i].toLowerCase()); 82 addresses[i] = (tokens.length > 0 ? tokens[0].getAddress() : inAddresses[i]); 83 bindString.append("?"); 84 if (i < addressesSize - 1) { 85 bindString.append(","); 86 } 87 } 88 89 if (Log.isLoggable(TAG, Log.DEBUG)) { 90 Log.d(TAG, "Doing reverse lookup for " + addresses.toString()); 91 } 92 93 HashMap<String, RecipientEntry> recipientEntries = new HashMap<String, RecipientEntry>(); 94 Cursor c = context.getContentResolver().query( 95 query.getContentUri(), query.getProjection(), 96 Queries.Query.DESTINATION + " IN (" + bindString.toString() + ")", 97 addresses, 98 null); 99 100 if (c != null) { 101 try { 102 if (c.moveToFirst()) { 103 do { 104 String address = c.getString(Queries.Query.DESTINATION); 105 recipientEntries.put(address, RecipientEntry.constructTopLevelEntry( 106 c.getString(Queries.Query.NAME), 107 c.getString(Queries.Query.DESTINATION), 108 c.getInt(Queries.Query.DESTINATION_TYPE), 109 c.getString(Queries.Query.DESTINATION_LABEL), 110 c.getLong(Queries.Query.CONTACT_ID), 111 c.getLong(Queries.Query.DATA_ID), 112 c.getString(Queries.Query.PHOTO_THUMBNAIL_URI))); 113 if (Log.isLoggable(TAG, Log.DEBUG)) { 114 Log.d(TAG, "Received reverse look up information for " + address 115 + " RESULTS: " 116 + " NAME : " + c.getString(Queries.Query.NAME) 117 + " CONTACT ID : " + c.getLong(Queries.Query.CONTACT_ID) 118 + " ADDRESS :" + c.getString(Queries.Query.DESTINATION)); 119 } 120 } while (c.moveToNext()); 121 } 122 } finally { 123 c.close(); 124 } 125 } 126 return recipientEntries; 127 } 128 129 public RecipientAlternatesAdapter(Context context, long contactId, long currentId, int viewId, 130 OnCheckedItemChangedListener listener) { 131 this(context, contactId, currentId, viewId, QUERY_TYPE_EMAIL, listener); 132 } 133 134 public RecipientAlternatesAdapter(Context context, long contactId, long currentId, int viewId, 135 int queryMode, OnCheckedItemChangedListener listener) { 136 super(context, getCursorForConstruction(context, contactId, queryMode), 0); 137 mLayoutInflater = LayoutInflater.from(context); 138 mCurrentId = currentId; 139 mCheckedItemChangedListener = listener; 140 141 if (queryMode == QUERY_TYPE_EMAIL) { 142 mQuery = Queries.EMAIL; 143 } else if (queryMode == QUERY_TYPE_PHONE) { 144 mQuery = Queries.PHONE; 145 } else { 146 mQuery = Queries.EMAIL; 147 Log.e(TAG, "Unsupported query type: " + queryMode); 148 } 149 } 150 151 private static Cursor getCursorForConstruction(Context context, long contactId, int queryType) { 152 if (queryType == QUERY_TYPE_EMAIL) { 153 return context.getContentResolver().query( 154 Queries.EMAIL.getContentUri(), 155 Queries.EMAIL.getProjection(), 156 Queries.EMAIL.getProjection()[Queries.Query.CONTACT_ID] + " =?", new String[] { 157 String.valueOf(contactId) 158 }, null); 159 } else { 160 return context.getContentResolver().query( 161 Queries.PHONE.getContentUri(), 162 Queries.PHONE.getProjection(), 163 Queries.PHONE.getProjection()[Queries.Query.CONTACT_ID] + " =?", new String[] { 164 String.valueOf(contactId) 165 }, null); 166 } 167 } 168 169 @Override 170 public long getItemId(int position) { 171 Cursor c = getCursor(); 172 if (c.moveToPosition(position)) { 173 c.getLong(Queries.Query.DATA_ID); 174 } 175 return -1; 176 } 177 178 public RecipientEntry getRecipientEntry(int position) { 179 Cursor c = getCursor(); 180 c.moveToPosition(position); 181 return RecipientEntry.constructTopLevelEntry( 182 c.getString(Queries.Query.NAME), 183 c.getString(Queries.Query.DESTINATION), 184 c.getInt(Queries.Query.DESTINATION_TYPE), 185 c.getString(Queries.Query.DESTINATION_LABEL), 186 c.getLong(Queries.Query.CONTACT_ID), 187 c.getLong(Queries.Query.DATA_ID), 188 c.getString(Queries.Query.PHOTO_THUMBNAIL_URI)); 189 } 190 191 @Override 192 public View getView(int position, View convertView, ViewGroup parent) { 193 Cursor cursor = getCursor(); 194 cursor.moveToPosition(position); 195 if (convertView == null) { 196 convertView = newView(); 197 } 198 if (cursor.getLong(Queries.Query.DATA_ID) == mCurrentId) { 199 mCheckedItemPosition = position; 200 if (mCheckedItemChangedListener != null) { 201 mCheckedItemChangedListener.onCheckedItemChanged(mCheckedItemPosition); 202 } 203 } 204 bindView(convertView, convertView.getContext(), cursor); 205 return convertView; 206 } 207 208 // TODO: this is VERY similar to the BaseRecipientAdapter. Can we combine 209 // somehow? 210 @Override 211 public void bindView(View view, Context context, Cursor cursor) { 212 int position = cursor.getPosition(); 213 214 TextView display = (TextView) view.findViewById(android.R.id.title); 215 ImageView imageView = (ImageView) view.findViewById(android.R.id.icon); 216 RecipientEntry entry = getRecipientEntry(position); 217 if (position == 0) { 218 display.setText(cursor.getString(Queries.Query.NAME)); 219 display.setVisibility(View.VISIBLE); 220 // TODO: see if this needs to be done outside the main thread 221 // as it may be too slow to get immediately. 222 imageView.setImageURI(entry.getPhotoThumbnailUri()); 223 imageView.setVisibility(View.VISIBLE); 224 } else { 225 display.setVisibility(View.GONE); 226 imageView.setVisibility(View.GONE); 227 } 228 TextView destination = (TextView) view.findViewById(android.R.id.text1); 229 destination.setText(cursor.getString(Queries.Query.DESTINATION)); 230 231 TextView destinationType = (TextView) view.findViewById(android.R.id.text2); 232 if (destinationType != null) { 233 destinationType.setText(mQuery.getTypeLabel(context.getResources(), 234 cursor.getInt(Queries.Query.DESTINATION_TYPE), 235 cursor.getString(Queries.Query.DESTINATION_LABEL)).toString().toUpperCase()); 236 } 237 } 238 239 @Override 240 public View newView(Context context, Cursor cursor, ViewGroup parent) { 241 return newView(); 242 } 243 244 private View newView() { 245 return mLayoutInflater.inflate(R.layout.chips_recipient_dropdown_item, null); 246 } 247 248 /*package*/ static interface OnCheckedItemChangedListener { 249 public void onCheckedItemChanged(int position); 250 } 251} 252