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 */ 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 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 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 */ 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 Phone.CONTACT_ID, 118 }; 119 120 // Table is sorted by number of times contacted and name. If we cannot fit all contacts 121 // in the recognizer, we will at least have the commonly used ones. 122 Cursor cursor = activity.getContentResolver().query( 123 Phone.CONTENT_URI, phonesProjection, 124 Phone.NUMBER + " NOT NULL", null, 125 Phone.LAST_TIME_CONTACTED + " DESC, " + Phone.DISPLAY_NAME + " ASC"); 126 127 final int phoneIdColumn = cursor.getColumnIndexOrThrow(Phone._ID); 128 final int typeColumn = cursor.getColumnIndexOrThrow(Phone.TYPE); 129 final int isPrimaryColumn = cursor.getColumnIndexOrThrow(Phone.IS_PRIMARY); 130 final int labelColumn = cursor.getColumnIndexOrThrow(Phone.LABEL); 131 final int nameColumn = cursor.getColumnIndexOrThrow(Phone.DISPLAY_NAME); 132 final int personIdColumn = cursor.getColumnIndexOrThrow(Phone.CONTACT_ID); 133 134 // pieces of next VoiceContact 135 String name = null; 136 long personId = ID_UNDEFINED; 137 long primaryId = ID_UNDEFINED; 138 long homeId = ID_UNDEFINED; 139 long mobileId = ID_UNDEFINED; 140 long workId = ID_UNDEFINED; 141 long otherId = ID_UNDEFINED; 142 143 // loop over phone table 144 for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) { 145 long phoneIdAtCursor = cursor.getLong(phoneIdColumn); 146 int typeAtCursor = cursor.getInt(typeColumn); 147 long isPrimaryAtCursor = cursor.getLong(isPrimaryColumn); 148 String labelAtCursor = cursor.getString(labelColumn); 149 String nameAtCursor = cursor.getString(nameColumn); 150 long personIdAtCursor = cursor.getLong(personIdColumn); 151 152 /* 153 if (Config.LOGD) { 154 Log.d(TAG, "phoneId=" + phoneIdAtCursor 155 + " type=" + typeAtCursor 156 + " isPrimary=" + isPrimaryAtCursor 157 + " label=" + labelAtCursor 158 + " name=" + nameAtCursor 159 + " personId=" + personIdAtCursor 160 ); 161 } 162 */ 163 164 // encountered a new name, so generate current VoiceContact 165 if (name != null && !name.equals(nameAtCursor)) { 166 contacts.add(new VoiceContact(name, personId, primaryId, 167 homeId, mobileId, workId, otherId)); 168 name = null; 169 } 170 171 // start accumulating pieces for a new VoiceContact 172 if (name == null) { 173 name = nameAtCursor; 174 personId = personIdAtCursor; 175 primaryId = ID_UNDEFINED; 176 homeId = ID_UNDEFINED; 177 mobileId = ID_UNDEFINED; 178 workId = ID_UNDEFINED; 179 otherId = ID_UNDEFINED; 180 } 181 182 // if labeled, then patch to HOME/MOBILE/WORK/OTHER 183 if (typeAtCursor == Phone.TYPE_CUSTOM && 184 labelAtCursor != null) { 185 String label = labelAtCursor.toLowerCase(); 186 if (label.contains("home") || label.contains("house")) { 187 typeAtCursor = Phone.TYPE_HOME; 188 } 189 else if (label.contains("mobile") || label.contains("cell")) { 190 typeAtCursor = Phone.TYPE_MOBILE; 191 } 192 else if (label.contains("work") || label.contains("office")) { 193 typeAtCursor = Phone.TYPE_WORK; 194 } 195 else if (label.contains("other")) { 196 typeAtCursor = Phone.TYPE_OTHER; 197 } 198 } 199 200 // save the home, mobile, or work phone id 201 switch (typeAtCursor) { 202 case Phone.TYPE_HOME: 203 homeId = phoneIdAtCursor; 204 if (isPrimaryAtCursor != 0) { 205 primaryId = phoneIdAtCursor; 206 } 207 break; 208 case Phone.TYPE_MOBILE: 209 mobileId = phoneIdAtCursor; 210 if (isPrimaryAtCursor != 0) { 211 primaryId = phoneIdAtCursor; 212 } 213 break; 214 case Phone.TYPE_WORK: 215 workId = phoneIdAtCursor; 216 if (isPrimaryAtCursor != 0) { 217 primaryId = phoneIdAtCursor; 218 } 219 break; 220 case Phone.TYPE_OTHER: 221 otherId = phoneIdAtCursor; 222 if (isPrimaryAtCursor != 0) { 223 primaryId = phoneIdAtCursor; 224 } 225 break; 226 } 227 } 228 229 // generate the last VoiceContact 230 if (name != null) { 231 contacts.add(new VoiceContact(name, personId, primaryId, 232 homeId, mobileId, workId, otherId)); 233 } 234 235 // clean up cursor 236 cursor.close(); 237 238 if (Config.LOGD) Log.d(TAG, "VoiceContact.getVoiceContacts " + contacts.size()); 239 240 return contacts; 241 } 242 243 /** 244 * @param contactsFile File containing a list of names, 245 * one per line. 246 * @return a List of {@link VoiceContact} in a File. 247 */ 248 public static List<VoiceContact> getVoiceContactsFromFile(File contactsFile) { 249 if (Config.LOGD) Log.d(TAG, "getVoiceContactsFromFile " + contactsFile); 250 251 List<VoiceContact> contacts = new ArrayList<VoiceContact>(); 252 253 // read from a file 254 BufferedReader br = null; 255 try { 256 br = new BufferedReader(new FileReader(contactsFile), 8192); 257 String name; 258 for (int id = 1; (name = br.readLine()) != null; id++) { 259 contacts.add(new VoiceContact(name, id, ID_UNDEFINED, 260 ID_UNDEFINED, ID_UNDEFINED, ID_UNDEFINED, ID_UNDEFINED)); 261 } 262 } 263 catch (IOException e) { 264 if (Config.LOGD) Log.d(TAG, "getVoiceContactsFromFile failed " + e); 265 } 266 finally { 267 try { 268 br.close(); 269 } catch (IOException e) { 270 if (Config.LOGD) Log.d(TAG, "getVoiceContactsFromFile failed during close " + e); 271 } 272 } 273 274 if (Config.LOGD) Log.d(TAG, "getVoiceContactsFromFile " + contacts.size()); 275 276 return contacts; 277 } 278 279 /** 280 * @param activity The VoiceDialerActivity instance. 281 * @return String of last number dialed. 282 */ 283 public static String redialNumber(Activity activity) { 284 Cursor cursor = activity.getContentResolver().query( 285 CallLog.Calls.CONTENT_URI, 286 new String[] { CallLog.Calls.NUMBER }, 287 CallLog.Calls.TYPE + "=" + CallLog.Calls.OUTGOING_TYPE, 288 null, 289 CallLog.Calls.DEFAULT_SORT_ORDER + " LIMIT 1"); 290 String number = null; 291 if (cursor.getCount() >= 1) { 292 cursor.moveToNext(); 293 int column = cursor.getColumnIndexOrThrow(CallLog.Calls.NUMBER); 294 number = cursor.getString(column); 295 } 296 cursor.close(); 297 298 if (Config.LOGD) Log.d(TAG, "redialNumber " + number); 299 300 return number; 301 } 302 303 } 304