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