1 /* 2 * Copyright (C) 2007 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 17 package com.android.voicedialer; 18 19 import android.app.Activity; 20 import android.database.Cursor; 21 import android.database.DatabaseUtils; 22 import android.provider.ContactsContract.CommonDataKinds.Phone; 23 import android.provider.CallLog; 24 import android.util.Config; 25 import android.util.Log; 26 import java.io.BufferedReader; 27 import java.io.File; 28 import java.io.FileReader; 29 import java.io.IOException; 30 import java.util.ArrayList; 31 import java.util.List; 32 33 34 /** 35 * This class represents a person who may be called via the VoiceDialer app. 36 * The person has a name and a list of phones (home, mobile, work, other). 37 */ 38 public class VoiceContact { 39 private static final String TAG = "VoiceContact"; 40 41 /** 42 * Corresponding row doesn't exist. 43 */ 44 public static final long ID_UNDEFINED = -1; 45 46 public final String mName; 47 public final long mContactId; 48 public final long mPrimaryId; 49 public final long mHomeId; 50 public final long mMobileId; 51 public final long mWorkId; 52 public final long mOtherId; 53 54 /** 55 * Constructor. 56 * 57 * @param name person's name. 58 * @param contactId ID in person table. 59 * @param primaryId primary ID in phone table. 60 * @param homeId home ID in phone table. 61 * @param mobileId mobile ID in phone table. 62 * @param workId work ID in phone table. 63 * @param otherId other ID in phone table. 64 */ VoiceContact(String name, long contactId, long primaryId, long homeId, long mobileId, long workId,long otherId)65 private VoiceContact(String name, long contactId, long primaryId, 66 long homeId, long mobileId, long workId,long otherId) { 67 mName = name; 68 mContactId = contactId; 69 mPrimaryId = primaryId; 70 mHomeId = homeId; 71 mMobileId = mobileId; 72 mWorkId = workId; 73 mOtherId = otherId; 74 } 75 76 @Override hashCode()77 public int hashCode() { 78 final int LARGE_PRIME = 1610612741; 79 int hash = 0; 80 hash = LARGE_PRIME * (hash + (int)mContactId); 81 hash = LARGE_PRIME * (hash + (int)mPrimaryId); 82 hash = LARGE_PRIME * (hash + (int)mHomeId); 83 hash = LARGE_PRIME * (hash + (int)mMobileId); 84 hash = LARGE_PRIME * (hash + (int)mWorkId); 85 hash = LARGE_PRIME * (hash + (int)mOtherId); 86 return mName.hashCode() + hash; 87 } 88 89 @Override toString()90 public String toString() { 91 return "mName=" + mName 92 + " mPersonId=" + mContactId 93 + " mPrimaryId=" + mPrimaryId 94 + " mHomeId=" + mHomeId 95 + " mMobileId=" + mMobileId 96 + " mWorkId=" + mWorkId 97 + " mOtherId=" + mOtherId; 98 } 99 100 /** 101 * @param activity The VoiceDialerActivity instance. 102 * @return List of {@link VoiceContact} from 103 * the contact list content provider. 104 */ getVoiceContacts(Activity activity)105 public static List<VoiceContact> getVoiceContacts(Activity activity) { 106 if (Config.LOGD) Log.d(TAG, "VoiceContact.getVoiceContacts"); 107 108 List<VoiceContact> contacts = new ArrayList<VoiceContact>(); 109 110 String[] phonesProjection = new String[] { 111 Phone._ID, 112 Phone.TYPE, 113 Phone.IS_PRIMARY, 114 // TODO: handle type != 0,1,2, and use LABEL 115 Phone.LABEL, 116 Phone.DISPLAY_NAME, 117 //Contacts.Phones.NUMBER, 118 Phone.CONTACT_ID, 119 }; 120 121 // Table is sorted by number of times contacted and name. If we cannot fit all contacts 122 // in the recognizer, we will at least have the commonly used ones. 123 Cursor cursor = activity.getContentResolver().query( 124 Phone.CONTENT_URI, phonesProjection, 125 Phone.NUMBER + " NOT NULL", null, 126 Phone.LAST_TIME_CONTACTED + " DESC"); 127 128 final int phoneIdColumn = cursor.getColumnIndexOrThrow(Phone._ID); 129 final int typeColumn = cursor.getColumnIndexOrThrow(Phone.TYPE); 130 final int isPrimaryColumn = cursor.getColumnIndexOrThrow(Phone.IS_PRIMARY); 131 int labelColumn = cursor.getColumnIndexOrThrow(Phone.LABEL); 132 final int nameColumn = cursor.getColumnIndexOrThrow(Phone.DISPLAY_NAME); 133 //final int numberColumn = cursor.getColumnIndexOrThrow(Contacts.Phones.NUMBER); 134 final int personIdColumn = cursor.getColumnIndexOrThrow(Phone.CONTACT_ID); 135 136 // pieces of next VoiceContact 137 String name = null; 138 long personId = ID_UNDEFINED; 139 long primaryId = ID_UNDEFINED; 140 long homeId = ID_UNDEFINED; 141 long mobileId = ID_UNDEFINED; 142 long workId = ID_UNDEFINED; 143 long otherId = ID_UNDEFINED; 144 145 // loop over phone table 146 cursor.moveToFirst(); 147 while (cursor.moveToNext()) { 148 long phoneIdAtCursor = cursor.getLong(phoneIdColumn); 149 int typeAtCursor = cursor.getInt(typeColumn); 150 long isPrimaryAtCursor = cursor.getLong(isPrimaryColumn); 151 String labelAtCursor = cursor.getString(labelColumn); 152 String nameAtCursor = cursor.getString(nameColumn); 153 //String numberAtCursor = cursor.getString(numberColumn); 154 long personIdAtCursor = cursor.getLong(personIdColumn); 155 156 /* 157 if (Config.LOGD) { 158 Log.d(TAG, "phoneId=" + phoneIdAtCursor 159 + " type=" + typeAtCursor 160 + " isPrimary=" + isPrimaryAtCursor 161 + " label=" + labelAtCursor 162 + " name=" + nameAtCursor 163 //+ " number=" + numberAtCursor 164 + " personId=" + personIdAtCursor 165 ); 166 } 167 */ 168 169 // encountered a new name, so generate current VoiceContact 170 if (name != null && !name.equals(nameAtCursor)) { 171 contacts.add(new VoiceContact(name, personId, primaryId, 172 homeId, mobileId, workId, otherId)); 173 name = null; 174 } 175 176 // start accumulating pieces for a new VoiceContact 177 if (name == null) { 178 name = nameAtCursor; 179 personId = personIdAtCursor; 180 primaryId = ID_UNDEFINED; 181 homeId = ID_UNDEFINED; 182 mobileId = ID_UNDEFINED; 183 workId = ID_UNDEFINED; 184 otherId = ID_UNDEFINED; 185 } 186 187 // if labeled, then patch to HOME/MOBILE/WORK/OTHER 188 if (typeAtCursor == Phone.TYPE_CUSTOM && 189 labelAtCursor != null) { 190 String label = labelAtCursor.toLowerCase(); 191 if (label.contains("home") || label.contains("house")) { 192 typeAtCursor = Phone.TYPE_HOME; 193 } 194 else if (label.contains("mobile") || label.contains("cell")) { 195 typeAtCursor = Phone.TYPE_MOBILE; 196 } 197 else if (label.contains("work") || label.contains("office")) { 198 typeAtCursor = Phone.TYPE_WORK; 199 } 200 else if (label.contains("other")) { 201 typeAtCursor = Phone.TYPE_OTHER; 202 } 203 } 204 205 // save the home, mobile, or work phone id 206 switch (typeAtCursor) { 207 case Phone.TYPE_HOME: 208 homeId = phoneIdAtCursor; 209 if (isPrimaryAtCursor != 0) { 210 primaryId = phoneIdAtCursor; 211 } 212 break; 213 case Phone.TYPE_MOBILE: 214 mobileId = phoneIdAtCursor; 215 if (isPrimaryAtCursor != 0) { 216 primaryId = phoneIdAtCursor; 217 } 218 break; 219 case Phone.TYPE_WORK: 220 workId = phoneIdAtCursor; 221 if (isPrimaryAtCursor != 0) { 222 primaryId = phoneIdAtCursor; 223 } 224 break; 225 case Phone.TYPE_OTHER: 226 otherId = phoneIdAtCursor; 227 if (isPrimaryAtCursor != 0) { 228 primaryId = phoneIdAtCursor; 229 } 230 break; 231 } 232 } 233 234 // generate the last VoiceContact 235 if (name != null) { 236 contacts.add(new VoiceContact(name, personId, primaryId, 237 homeId, mobileId, workId, otherId)); 238 } 239 240 // clean up cursor 241 cursor.close(); 242 243 if (Config.LOGD) Log.d(TAG, "VoiceContact.getVoiceContacts " + contacts.size()); 244 245 return contacts; 246 } 247 248 /** 249 * @param contactsFile File containing a list of names, 250 * one per line. 251 * @return a List of {@link VoiceContact} in a File. 252 */ getVoiceContactsFromFile(File contactsFile)253 public static List<VoiceContact> getVoiceContactsFromFile(File contactsFile) { 254 if (Config.LOGD) Log.d(TAG, "getVoiceContactsFromFile " + contactsFile); 255 256 List<VoiceContact> contacts = new ArrayList<VoiceContact>(); 257 258 // read from a file 259 BufferedReader br = null; 260 try { 261 br = new BufferedReader(new FileReader(contactsFile), 8192); 262 String name; 263 for (int id = 1; (name = br.readLine()) != null; id++) { 264 contacts.add(new VoiceContact(name, id, ID_UNDEFINED, 265 ID_UNDEFINED, ID_UNDEFINED, ID_UNDEFINED, ID_UNDEFINED)); 266 } 267 } 268 catch (IOException e) { 269 if (Config.LOGD) Log.d(TAG, "getVoiceContactsFromFile failed " + e); 270 } 271 finally { 272 try { 273 br.close(); 274 } catch (IOException e) { 275 if (Config.LOGD) Log.d(TAG, "getVoiceContactsFromFile failed during close " + e); 276 } 277 } 278 279 if (Config.LOGD) Log.d(TAG, "getVoiceContactsFromFile " + contacts.size()); 280 281 return contacts; 282 } 283 284 /** 285 * @param activity The VoiceDialerActivity instance. 286 * @return String of last number dialed. 287 */ redialNumber(Activity activity)288 public static String redialNumber(Activity activity) { 289 Cursor cursor = activity.getContentResolver().query( 290 CallLog.Calls.CONTENT_URI, 291 new String[] { CallLog.Calls.NUMBER }, 292 CallLog.Calls.TYPE + "=" + CallLog.Calls.OUTGOING_TYPE, 293 null, 294 CallLog.Calls.DEFAULT_SORT_ORDER + " LIMIT 1"); 295 String number = null; 296 if (cursor.getCount() >= 1) { 297 cursor.moveToNext(); 298 int column = cursor.getColumnIndexOrThrow(CallLog.Calls.NUMBER); 299 number = cursor.getString(column); 300 } 301 cursor.close(); 302 303 if (Config.LOGD) Log.d(TAG, "redialNumber " + number); 304 305 return number; 306 } 307 308 } 309