Home | History | Annotate | Download | only in voicedialer
      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