CallerInfo.java revision 101bed44998ff35c3a56f431345fac5c8229ec0e
17ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee/*
27ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee * Copyright (C) 2006 The Android Open Source Project
37ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee *
47ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee * Licensed under the Apache License, Version 2.0 (the "License");
57ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee * you may not use this file except in compliance with the License.
67ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee * You may obtain a copy of the License at
77ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee *
87ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee *      http://www.apache.org/licenses/LICENSE-2.0
97ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee *
107ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee * Unless required by applicable law or agreed to in writing, software
117ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee * distributed under the License is distributed on an "AS IS" BASIS,
127ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
137ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee * See the License for the specific language governing permissions and
147ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee * limitations under the License.
157ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee */
167ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee
177ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Leepackage com.android.incallui;
187ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee
197ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Leeimport android.content.Context;
207ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Leeimport android.database.Cursor;
217ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Leeimport android.graphics.Bitmap;
227ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Leeimport android.graphics.drawable.Drawable;
237ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Leeimport android.location.CountryDetector;
247ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Leeimport android.net.Uri;
257ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Leeimport android.provider.ContactsContract.CommonDataKinds.Phone;
267ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Leeimport android.provider.ContactsContract.Data;
277ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Leeimport android.provider.ContactsContract.PhoneLookup;
287ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Leeimport android.provider.ContactsContract.RawContacts;
297ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Leeimport android.telephony.PhoneNumberUtils;
307ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Leeimport android.telephony.TelephonyManager;
317ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Leeimport android.text.TextUtils;
327ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee
337ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Leeimport com.android.i18n.phonenumbers.geocoding.PhoneNumberOfflineGeocoder;
347ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Leeimport com.android.i18n.phonenumbers.NumberParseException;
357ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Leeimport com.android.i18n.phonenumbers.PhoneNumberUtil;
367ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Leeimport com.android.i18n.phonenumbers.Phonenumber.PhoneNumber;
377ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee
387ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Leeimport java.util.Locale;
397ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee
407ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee
417ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee/**
427ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee * Looks up caller information for the given phone number.
437ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee *
447ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee * {@hide}
457ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee */
467ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Leepublic class CallerInfo {
477ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    private static final String TAG = "CallerInfo";
487ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee
497ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    /**
507ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * Please note that, any one of these member variables can be null,
517ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * and any accesses to them should be prepared to handle such a case.
527ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     *
537ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * Also, it is implied that phoneNumber is more often populated than
547ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * name is, (think of calls being dialed/received using numbers where
557ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * names are not known to the device), so phoneNumber should serve as
567ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * a dependable fallback when name is unavailable.
577ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     *
587ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * One other detail here is that this CallerInfo object reflects
597ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * information found on a connection, it is an OUTPUT that serves
607ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * mainly to display information to the user.  In no way is this object
617ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * used as input to make a connection, so we can choose to display
627ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * whatever human-readable text makes sense to the user for a
637ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * connection.  This is especially relevant for the phone number field,
647ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * since it is the one field that is most likely exposed to the user.
657ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     *
667ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * As an example:
677ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     *   1. User dials "911"
687ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     *   2. Device recognizes that this is an emergency number
697ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     *   3. We use the "Emergency Number" string instead of "911" in the
707ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     *     phoneNumber field.
717ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     *
727ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * What we're really doing here is treating phoneNumber as an essential
737ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * field here, NOT name.  We're NOT always guaranteed to have a name
747ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * for a connection, but the number should be displayable.
757ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     */
767ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    public String name;
777ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    public String phoneNumber;
787ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    public String normalizedNumber;
79101bed44998ff35c3a56f431345fac5c8229ec0eJay Shrauner    public String forwardingNumber;
807ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    public String geoDescription;
817ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee
827ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    public String cnapName;
837ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    public int numberPresentation;
847ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    public int namePresentation;
857ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    public boolean contactExists;
867ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee
877ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    public String phoneLabel;
887ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    /* Split up the phoneLabel into number type and label name */
897ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    public int    numberType;
907ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    public String numberLabel;
917ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee
927ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    public int photoResource;
937ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    public long person_id;
947ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    public boolean needUpdate;
957ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    public Uri contactRefUri;
967ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee
977ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    // fields to hold individual contact preference data,
987ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    // including the send to voicemail flag and the ringtone
997ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    // uri reference.
1007ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    public Uri contactRingtoneUri;
1017ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    public boolean shouldSendToVoicemail;
1027ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee
1037ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    /**
1047ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * Drawable representing the caller image.  This is essentially
1057ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * a cache for the image data tied into the connection /
1067ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * callerinfo object.
1077ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     *
1087ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * This might be a high resolution picture which is more suitable
1097ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * for full-screen image view than for smaller icons used in some
1107ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * kinds of notifications.
1117ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     *
1127ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * The {@link #isCachedPhotoCurrent} flag indicates if the image
1137ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * data needs to be reloaded.
1147ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     */
1157ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    public Drawable cachedPhoto;
1167ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    /**
1177ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * Bitmap representing the caller image which has possibly lower
1187ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * resolution than {@link #cachedPhoto} and thus more suitable for
1197ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * icons (like notification icons).
1207ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     *
1217ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * In usual cases this is just down-scaled image of {@link #cachedPhoto}.
1227ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * If the down-scaling fails, this will just become null.
1237ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     *
1247ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * The {@link #isCachedPhotoCurrent} flag indicates if the image
1257ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * data needs to be reloaded.
1267ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     */
1277ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    public Bitmap cachedPhotoIcon;
1287ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    /**
1297ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * Boolean which indicates if {@link #cachedPhoto} and
1307ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * {@link #cachedPhotoIcon} is fresh enough. If it is false,
1317ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * those images aren't pointing to valid objects.
1327ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     */
1337ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    public boolean isCachedPhotoCurrent;
1347ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee
1357ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    private boolean mIsEmergency;
1367ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    private boolean mIsVoiceMail;
1377ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee
1387ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    public CallerInfo() {
1397ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        // TODO: Move all the basic initialization here?
1407ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        mIsEmergency = false;
1417ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        mIsVoiceMail = false;
1427ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    }
1437ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee
1447ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    /**
1457ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * getCallerInfo given a Cursor.
1467ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * @param context the context used to retrieve string constants
1477ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * @param contactRef the URI to attach to this CallerInfo object
1487ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * @param cursor the first object in the cursor is used to build the CallerInfo object.
1497ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * @return the CallerInfo which contains the caller id for the given
1507ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * number. The returned CallerInfo is null if no number is supplied.
1517ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     */
1527ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    public static CallerInfo getCallerInfo(Context context, Uri contactRef, Cursor cursor) {
1537ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        CallerInfo info = new CallerInfo();
1547ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        info.photoResource = 0;
1557ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        info.phoneLabel = null;
1567ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        info.numberType = 0;
1577ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        info.numberLabel = null;
1587ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        info.cachedPhoto = null;
1597ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        info.isCachedPhotoCurrent = false;
1607ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        info.contactExists = false;
1617ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee
1621a7f2bcab2d2023f2ee4cfb0bc57bc265b5aab87Chiao Cheng        Log.v(TAG, "getCallerInfo() based on cursor...");
1637ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee
1647ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        if (cursor != null) {
1657ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee            if (cursor.moveToFirst()) {
1667ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                // TODO: photo_id is always available but not taken
1677ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                // care of here. Maybe we should store it in the
1687ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                // CallerInfo object as well.
1697ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee
1707ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                int columnIndex;
1717ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee
1727ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                // Look for the name
1737ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                columnIndex = cursor.getColumnIndex(PhoneLookup.DISPLAY_NAME);
1747ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                if (columnIndex != -1) {
1757ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                    info.name = cursor.getString(columnIndex);
1767ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                }
1777ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee
1787ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                // Look for the number
1797ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                columnIndex = cursor.getColumnIndex(PhoneLookup.NUMBER);
1807ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                if (columnIndex != -1) {
1817ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                    info.phoneNumber = cursor.getString(columnIndex);
1827ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                }
1837ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee
1847ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                // Look for the normalized number
1857ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                columnIndex = cursor.getColumnIndex(PhoneLookup.NORMALIZED_NUMBER);
1867ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                if (columnIndex != -1) {
1877ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                    info.normalizedNumber = cursor.getString(columnIndex);
1887ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                }
1897ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee
1907ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                // Look for the label/type combo
1917ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                columnIndex = cursor.getColumnIndex(PhoneLookup.LABEL);
1927ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                if (columnIndex != -1) {
1937ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                    int typeColumnIndex = cursor.getColumnIndex(PhoneLookup.TYPE);
1947ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                    if (typeColumnIndex != -1) {
1957ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                        info.numberType = cursor.getInt(typeColumnIndex);
1967ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                        info.numberLabel = cursor.getString(columnIndex);
1977ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                        info.phoneLabel = Phone.getDisplayLabel(context,
1987ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                                info.numberType, info.numberLabel)
1997ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                                .toString();
2007ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                    }
2017ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                }
2027ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee
2037ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                // Look for the person_id.
2047ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                columnIndex = getColumnIndexForPersonId(contactRef, cursor);
2057ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                if (columnIndex != -1) {
2067ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                    info.person_id = cursor.getLong(columnIndex);
2071a7f2bcab2d2023f2ee4cfb0bc57bc265b5aab87Chiao Cheng                    Log.v(TAG, "==> got info.person_id: " + info.person_id);
2087ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                } else {
2097ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                    // No valid columnIndex, so we can't look up person_id.
2101a7f2bcab2d2023f2ee4cfb0bc57bc265b5aab87Chiao Cheng                    Log.v(TAG, "Couldn't find person_id column for " + contactRef);
2117ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                    // Watch out: this means that anything that depends on
2127ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                    // person_id will be broken (like contact photo lookups in
2137ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                    // the in-call UI, for example.)
2147ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                }
2157ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee
2167ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                // look for the custom ringtone, create from the string stored
2177ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                // in the database.
2187ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                columnIndex = cursor.getColumnIndex(PhoneLookup.CUSTOM_RINGTONE);
2197ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                if ((columnIndex != -1) && (cursor.getString(columnIndex) != null)) {
2207ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                    info.contactRingtoneUri = Uri.parse(cursor.getString(columnIndex));
2217ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                } else {
2227ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                    info.contactRingtoneUri = null;
2237ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                }
2247ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee
2257ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                // look for the send to voicemail flag, set it to true only
2267ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                // under certain circumstances.
2277ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                columnIndex = cursor.getColumnIndex(PhoneLookup.SEND_TO_VOICEMAIL);
2287ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                info.shouldSendToVoicemail = (columnIndex != -1) &&
2297ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                        ((cursor.getInt(columnIndex)) == 1);
2307ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                info.contactExists = true;
2317ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee            }
2327ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee            cursor.close();
2337ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        }
2347ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee
2357ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        info.needUpdate = false;
2367ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        info.name = normalize(info.name);
2377ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        info.contactRefUri = contactRef;
2387ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee
2397ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        return info;
2407ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    }
2417ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee
2427ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    /**
2437ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * getCallerInfo given a URI, look up in the call-log database
2447ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * for the uri unique key.
2457ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * @param context the context used to get the ContentResolver
2467ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * @param contactRef the URI used to lookup caller id
2477ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * @return the CallerInfo which contains the caller id for the given
2487ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * number. The returned CallerInfo is null if no number is supplied.
2497ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     */
2507ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    public static CallerInfo getCallerInfo(Context context, Uri contactRef) {
2517ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee
2527ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        return getCallerInfo(context, contactRef,
2537ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                context.getContentResolver().query(contactRef, null, null, null, null));
2547ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    }
2557ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee
2567ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    /**
2577ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * getCallerInfo given a phone number, look up in the call-log database
2587ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * for the matching caller id info.
2597ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * @param context the context used to get the ContentResolver
2607ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * @param number the phone number used to lookup caller id
2617ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * @return the CallerInfo which contains the caller id for the given
2627ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * number. The returned CallerInfo is null if no number is supplied. If
2637ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * a matching number is not found, then a generic caller info is returned,
2647ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * with all relevant fields empty or null.
2657ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     */
2667ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    public static CallerInfo getCallerInfo(Context context, String number) {
2671a7f2bcab2d2023f2ee4cfb0bc57bc265b5aab87Chiao Cheng        Log.v(TAG, "getCallerInfo() based on number...");
2687ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee
2697ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        if (TextUtils.isEmpty(number)) {
2707ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee            return null;
2717ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        }
2727ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee
2737ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        // Change the callerInfo number ONLY if it is an emergency number
2747ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        // or if it is the voicemail number.  If it is either, take a
2757ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        // shortcut and skip the query.
2767ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        if (PhoneNumberUtils.isLocalEmergencyNumber(number, context)) {
2777ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee            return new CallerInfo().markAsEmergency(context);
2787ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        } else if (PhoneNumberUtils.isVoiceMailNumber(number)) {
2797ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee            return new CallerInfo().markAsVoiceMail();
2807ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        }
2817ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee
2827ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        Uri contactUri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, Uri.encode(number));
2837ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee
2847ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        CallerInfo info = getCallerInfo(context, contactUri);
2857ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        info = doSecondaryLookupIfNecessary(context, number, info);
2867ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee
2877ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        // if no query results were returned with a viable number,
2887ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        // fill in the original number value we used to query with.
2897ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        if (TextUtils.isEmpty(info.phoneNumber)) {
2907ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee            info.phoneNumber = number;
2917ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        }
2927ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee
2937ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        return info;
2947ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    }
2957ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee
2967ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    /**
2977ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * Performs another lookup if previous lookup fails and it's a SIP call
2987ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * and the peer's username is all numeric. Look up the username as it
2997ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * could be a PSTN number in the contact database.
3007ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     *
3017ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * @param context the query context
3027ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * @param number the original phone number, could be a SIP URI
3037ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * @param previousResult the result of previous lookup
3047ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * @return previousResult if it's not the case
3057ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     */
3067ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    static CallerInfo doSecondaryLookupIfNecessary(Context context,
3077ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee            String number, CallerInfo previousResult) {
3087ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        if (!previousResult.contactExists
3097ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                && PhoneNumberUtils.isUriNumber(number)) {
3107ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee            String username = PhoneNumberUtils.getUsernameFromUriNumber(number);
3117ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee            if (PhoneNumberUtils.isGlobalPhoneNumber(username)) {
3127ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                previousResult = getCallerInfo(context,
3137ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                        Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI,
3147ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                                Uri.encode(username)));
3157ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee            }
3167ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        }
3177ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        return previousResult;
3187ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    }
3197ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee
3207ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    /**
3217ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * getCallerId: a convenience method to get the caller id for a given
3227ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * number.
3237ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     *
3247ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * @param context the context used to get the ContentResolver.
3257ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * @param number a phone number.
3267ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * @return if the number belongs to a contact, the contact's name is
3277ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * returned; otherwise, the number itself is returned.
3287ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     *
3297ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * TODO NOTE: This MAY need to refer to the Asynchronous Query API
3307ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * [startQuery()], instead of getCallerInfo, but since it looks like
3317ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * it is only being used by the provider calls in the messaging app:
3327ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     *   1. android.provider.Telephony.Mms.getDisplayAddress()
3337ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     *   2. android.provider.Telephony.Sms.getDisplayAddress()
3347ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * We may not need to make the change.
3357ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     */
3367ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    public static String getCallerId(Context context, String number) {
3377ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        CallerInfo info = getCallerInfo(context, number);
3387ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        String callerID = null;
3397ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee
3407ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        if (info != null) {
3417ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee            String name = info.name;
3427ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee
3437ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee            if (!TextUtils.isEmpty(name)) {
3447ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                callerID = name;
3457ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee            } else {
3467ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                callerID = number;
3477ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee            }
3487ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        }
3497ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee
3507ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        return callerID;
3517ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    }
3527ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee
3537ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    // Accessors
3547ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee
3557ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    /**
3567ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * @return true if the caller info is an emergency number.
3577ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     */
3587ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    public boolean isEmergencyNumber() {
3597ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        return mIsEmergency;
3607ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    }
3617ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee
3627ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    /**
3637ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * @return true if the caller info is a voicemail number.
3647ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     */
3657ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    public boolean isVoiceMailNumber() {
3667ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        return mIsVoiceMail;
3677ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    }
3687ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee
3697ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    /**
3707ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * Mark this CallerInfo as an emergency call.
3717ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * @param context To lookup the localized 'Emergency Number' string.
3727ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * @return this instance.
3737ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     */
3747ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    // TODO: Note we're setting the phone number here (refer to
3757ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    // javadoc comments at the top of CallerInfo class) to a localized
3767ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    // string 'Emergency Number'. This is pretty bad because we are
3777ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    // making UI work here instead of just packaging the data. We
3787ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    // should set the phone number to the dialed number and name to
3797ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    // 'Emergency Number' and let the UI make the decision about what
3807ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    // should be displayed.
3817ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    /* package */ CallerInfo markAsEmergency(Context context) {
3827ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        phoneNumber = context.getString(
3837ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee            com.android.internal.R.string.emergency_call_dialog_number_for_display);
3847ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        photoResource = com.android.internal.R.drawable.picture_emergency;
3857ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        mIsEmergency = true;
3867ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        return this;
3877ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    }
3887ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee
3897ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee
3907ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    /**
3917ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * Mark this CallerInfo as a voicemail call. The voicemail label
3927ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * is obtained from the telephony manager. Caller must hold the
3937ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * READ_PHONE_STATE permission otherwise the phoneNumber will be
3947ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * set to null.
3957ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * @return this instance.
3967ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     */
3977ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    // TODO: As in the emergency number handling, we end up writing a
3987ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    // string in the phone number field.
3997ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    /* package */ CallerInfo markAsVoiceMail() {
4007ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        mIsVoiceMail = true;
4017ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee
4027ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        try {
4037ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee            String voiceMailLabel = TelephonyManager.getDefault().getVoiceMailAlphaTag();
4047ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee
4057ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee            phoneNumber = voiceMailLabel;
4067ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        } catch (SecurityException se) {
4077ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee            // Should never happen: if this process does not have
4087ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee            // permission to retrieve VM tag, it should not have
4097ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee            // permission to retrieve VM number and would not call
4107ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee            // this method.
4117ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee            // Leave phoneNumber untouched.
4121a7f2bcab2d2023f2ee4cfb0bc57bc265b5aab87Chiao Cheng            Log.e(TAG, "Cannot access VoiceMail.", se);
4137ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        }
4147ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        // TODO: There is no voicemail picture?
4157ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        // FIXME: FIND ANOTHER ICON
4167ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        // photoResource = android.R.drawable.badge_voicemail;
4177ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        return this;
4187ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    }
4197ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee
4207ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    private static String normalize(String s) {
4217ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        if (s == null || s.length() > 0) {
4227ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee            return s;
4237ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        } else {
4247ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee            return null;
4257ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        }
4267ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    }
4277ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee
4287ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    /**
4297ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * Returns the column index to use to find the "person_id" field in
4307ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * the specified cursor, based on the contact URI that was originally
4317ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * queried.
4327ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     *
4337ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * This is a helper function for the getCallerInfo() method that takes
4347ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * a Cursor.  Looking up the person_id is nontrivial (compared to all
4357ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * the other CallerInfo fields) since the column we need to use
4367ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * depends on what query we originally ran.
4377ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     *
4387ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * Watch out: be sure to not do any database access in this method, since
4397ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * it's run from the UI thread (see comments below for more info.)
4407ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     *
4417ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * @return the columnIndex to use (with cursor.getLong()) to get the
4427ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * person_id, or -1 if we couldn't figure out what colum to use.
4437ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     *
4447ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * TODO: Add a unittest for this method.  (This is a little tricky to
4457ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * test, since we'll need a live contacts database to test against,
4467ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * preloaded with at least some phone numbers and SIP addresses.  And
4477ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * we'll probably have to hardcode the column indexes we expect, so
4487ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * the test might break whenever the contacts schema changes.  But we
4497ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * can at least make sure we handle all the URI patterns we claim to,
4507ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * and that the mime types match what we expect...)
4517ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     */
4527ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    private static int getColumnIndexForPersonId(Uri contactRef, Cursor cursor) {
4537ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        // TODO: This is pretty ugly now, see bug 2269240 for
4547ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        // more details. The column to use depends upon the type of URL:
4557ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        // - content://com.android.contacts/data/phones ==> use the "contact_id" column
4567ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        // - content://com.android.contacts/phone_lookup ==> use the "_ID" column
4577ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        // - content://com.android.contacts/data ==> use the "contact_id" column
4587ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        // If it's none of the above, we leave columnIndex=-1 which means
4597ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        // that the person_id field will be left unset.
4607ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        //
4617ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        // The logic here *used* to be based on the mime type of contactRef
4627ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        // (for example Phone.CONTENT_ITEM_TYPE would tell us to use the
4637ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        // RawContacts.CONTACT_ID column).  But looking up the mime type requires
4647ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        // a call to context.getContentResolver().getType(contactRef), which
4657ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        // isn't safe to do from the UI thread since it can cause an ANR if
4667ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        // the contacts provider is slow or blocked (like during a sync.)
4677ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        //
4687ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        // So instead, figure out the column to use for person_id by just
4697ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        // looking at the URI itself.
4707ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee
4711a7f2bcab2d2023f2ee4cfb0bc57bc265b5aab87Chiao Cheng        Log.v(TAG, "- getColumnIndexForPersonId: contactRef URI = '"
4721a7f2bcab2d2023f2ee4cfb0bc57bc265b5aab87Chiao Cheng                + contactRef + "'...");
4737ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        // Warning: Do not enable the following logging (due to ANR risk.)
4747ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        // if (VDBG) Rlog.v(TAG, "- MIME type: "
4757ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        //                 + context.getContentResolver().getType(contactRef));
4767ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee
4777ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        String url = contactRef.toString();
4787ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        String columnName = null;
4797ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        if (url.startsWith("content://com.android.contacts/data/phones")) {
4807ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee            // Direct lookup in the Phone table.
4817ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee            // MIME type: Phone.CONTENT_ITEM_TYPE (= "vnd.android.cursor.item/phone_v2")
4821a7f2bcab2d2023f2ee4cfb0bc57bc265b5aab87Chiao Cheng            Log.v(TAG, "'data/phones' URI; using RawContacts.CONTACT_ID");
4837ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee            columnName = RawContacts.CONTACT_ID;
4847ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        } else if (url.startsWith("content://com.android.contacts/data")) {
4857ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee            // Direct lookup in the Data table.
4867ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee            // MIME type: Data.CONTENT_TYPE (= "vnd.android.cursor.dir/data")
4871a7f2bcab2d2023f2ee4cfb0bc57bc265b5aab87Chiao Cheng            Log.v(TAG, "'data' URI; using Data.CONTACT_ID");
4887ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee            // (Note Data.CONTACT_ID and RawContacts.CONTACT_ID are equivalent.)
4897ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee            columnName = Data.CONTACT_ID;
4907ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        } else if (url.startsWith("content://com.android.contacts/phone_lookup")) {
4917ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee            // Lookup in the PhoneLookup table, which provides "fuzzy matching"
4927ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee            // for phone numbers.
4937ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee            // MIME type: PhoneLookup.CONTENT_TYPE (= "vnd.android.cursor.dir/phone_lookup")
4941a7f2bcab2d2023f2ee4cfb0bc57bc265b5aab87Chiao Cheng            Log.v(TAG, "'phone_lookup' URI; using PhoneLookup._ID");
4957ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee            columnName = PhoneLookup._ID;
4967ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        } else {
4971a7f2bcab2d2023f2ee4cfb0bc57bc265b5aab87Chiao Cheng            Log.v(TAG, "Unexpected prefix for contactRef '" + url + "'");
4987ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        }
4997ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        int columnIndex = (columnName != null) ? cursor.getColumnIndex(columnName) : -1;
5001a7f2bcab2d2023f2ee4cfb0bc57bc265b5aab87Chiao Cheng        Log.v(TAG, "==> Using column '" + columnName
5011a7f2bcab2d2023f2ee4cfb0bc57bc265b5aab87Chiao Cheng                + "' (columnIndex = " + columnIndex + ") for person_id lookup...");
5027ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        return columnIndex;
5037ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    }
5047ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee
5057ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    /**
5067ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * Updates this CallerInfo's geoDescription field, based on the raw
5077ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * phone number in the phoneNumber field.
5087ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     *
5097ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * (Note that the various getCallerInfo() methods do *not* set the
5107ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * geoDescription automatically; you need to call this method
5117ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * explicitly to get it.)
5127ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     *
5137ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * @param context the context used to look up the current locale / country
5147ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * @param fallbackNumber if this CallerInfo's phoneNumber field is empty,
5157ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     *        this specifies a fallback number to use instead.
5167ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     */
5177ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    public void updateGeoDescription(Context context, String fallbackNumber) {
5187ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        String number = TextUtils.isEmpty(phoneNumber) ? fallbackNumber : phoneNumber;
5197ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        geoDescription = getGeoDescription(context, number);
5207ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    }
5217ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee
5227ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    /**
5237ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * @return a geographical description string for the specified number.
5247ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * @see com.android.i18n.phonenumbers.PhoneNumberOfflineGeocoder
5257ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     */
5267ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    private static String getGeoDescription(Context context, String number) {
5271a7f2bcab2d2023f2ee4cfb0bc57bc265b5aab87Chiao Cheng        Log.v(TAG, "getGeoDescription('" + number + "')...");
5287ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee
5297ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        if (TextUtils.isEmpty(number)) {
5307ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee            return null;
5317ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        }
5327ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee
5337ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        PhoneNumberUtil util = PhoneNumberUtil.getInstance();
5347ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        PhoneNumberOfflineGeocoder geocoder = PhoneNumberOfflineGeocoder.getInstance();
5357ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee
5367ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        Locale locale = context.getResources().getConfiguration().locale;
5377ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        String countryIso = getCurrentCountryIso(context, locale);
5387ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        PhoneNumber pn = null;
5397ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        try {
5401a7f2bcab2d2023f2ee4cfb0bc57bc265b5aab87Chiao Cheng            Log.v(TAG, "parsing '" + number
5411a7f2bcab2d2023f2ee4cfb0bc57bc265b5aab87Chiao Cheng                    + "' for countryIso '" + countryIso + "'...");
5427ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee            pn = util.parse(number, countryIso);
5431a7f2bcab2d2023f2ee4cfb0bc57bc265b5aab87Chiao Cheng            Log.v(TAG, "- parsed number: " + pn);
5447ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        } catch (NumberParseException e) {
5451a7f2bcab2d2023f2ee4cfb0bc57bc265b5aab87Chiao Cheng            Log.v(TAG, "getGeoDescription: NumberParseException for incoming number '" +
5467ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                    number + "'");
5477ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        }
5487ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee
5497ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        if (pn != null) {
5507ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee            String description = geocoder.getDescriptionForNumber(pn, locale);
5511a7f2bcab2d2023f2ee4cfb0bc57bc265b5aab87Chiao Cheng            Log.v(TAG, "- got description: '" + description + "'");
5527ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee            return description;
5537ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        } else {
5547ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee            return null;
5557ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        }
5567ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    }
5577ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee
5587ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    /**
5597ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * @return The ISO 3166-1 two letters country code of the country the user
5607ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     *         is in.
5617ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     */
5627ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    private static String getCurrentCountryIso(Context context, Locale locale) {
5637ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee      String countryIso;
5647ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee      CountryDetector detector = (CountryDetector) context.getSystemService(
5657ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee          Context.COUNTRY_DETECTOR);
5667ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee      if (detector != null) {
5677ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        countryIso = detector.detectCountry().getCountryIso();
5687ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee      } else {
5697ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        countryIso = locale.getCountry();
5701a7f2bcab2d2023f2ee4cfb0bc57bc265b5aab87Chiao Cheng            Log.v(TAG, "No CountryDetector; falling back to countryIso based on locale: "
5711a7f2bcab2d2023f2ee4cfb0bc57bc265b5aab87Chiao Cheng                    + countryIso);
5727ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee      }
5737ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee      return countryIso;
5747ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    }
5757ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee
5767ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    /**
5777ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * @return a string debug representation of this instance.
5787ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     */
5797ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    @Override
5807ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    public String toString() {
5817ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        // Warning: never check in this file with VERBOSE_DEBUG = true
5827ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        // because that will result in PII in the system log.
5837ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        final boolean VERBOSE_DEBUG = false;
5847ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee
5857ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        if (VERBOSE_DEBUG) {
5867ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee            return new StringBuilder(384)
5877ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                    .append(super.toString() + " { ")
5887ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                    .append("\nname: " + name)
5897ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                    .append("\nphoneNumber: " + phoneNumber)
5907ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                    .append("\nnormalizedNumber: " + normalizedNumber)
591101bed44998ff35c3a56f431345fac5c8229ec0eJay Shrauner                    .append("\forwardingNumber: " + forwardingNumber)
5927ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                    .append("\ngeoDescription: " + geoDescription)
5937ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                    .append("\ncnapName: " + cnapName)
5947ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                    .append("\nnumberPresentation: " + numberPresentation)
5957ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                    .append("\nnamePresentation: " + namePresentation)
5967ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                    .append("\ncontactExists: " + contactExists)
5977ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                    .append("\nphoneLabel: " + phoneLabel)
5987ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                    .append("\nnumberType: " + numberType)
5997ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                    .append("\nnumberLabel: " + numberLabel)
6007ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                    .append("\nphotoResource: " + photoResource)
6017ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                    .append("\nperson_id: " + person_id)
6027ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                    .append("\nneedUpdate: " + needUpdate)
6037ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                    .append("\ncontactRefUri: " + contactRefUri)
6047ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                    .append("\ncontactRingtoneUri: " + contactRefUri)
6057ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                    .append("\nshouldSendToVoicemail: " + shouldSendToVoicemail)
6067ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                    .append("\ncachedPhoto: " + cachedPhoto)
6077ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                    .append("\nisCachedPhotoCurrent: " + isCachedPhotoCurrent)
6087ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                    .append("\nemergency: " + mIsEmergency)
6097ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                    .append("\nvoicemail " + mIsVoiceMail)
6107ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                    .append(" }")
6117ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                    .toString();
6127ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        } else {
6137ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee            return new StringBuilder(128)
6147ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                    .append(super.toString() + " { ")
6157ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                    .append("name " + ((name == null) ? "null" : "non-null"))
6167ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                    .append(", phoneNumber " + ((phoneNumber == null) ? "null" : "non-null"))
6177ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                    .append(" }")
6187ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                    .toString();
6197ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        }
6207ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    }
6217ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee}
622