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