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;
231c85bef1f4ee97a3443d130bdff178ba4db1539fJay Shraunerimport android.location.Country;
247ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Leeimport android.location.CountryDetector;
257ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Leeimport android.net.Uri;
267ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Leeimport android.provider.ContactsContract.CommonDataKinds.Phone;
277ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Leeimport android.provider.ContactsContract.Data;
287ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Leeimport android.provider.ContactsContract.PhoneLookup;
297ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Leeimport android.provider.ContactsContract.RawContacts;
307ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Leeimport android.telephony.PhoneNumberUtils;
317ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Leeimport android.telephony.TelephonyManager;
327ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Leeimport android.text.TextUtils;
337ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee
347ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Leeimport com.android.i18n.phonenumbers.geocoding.PhoneNumberOfflineGeocoder;
357ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Leeimport com.android.i18n.phonenumbers.NumberParseException;
367ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Leeimport com.android.i18n.phonenumbers.PhoneNumberUtil;
377ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Leeimport com.android.i18n.phonenumbers.Phonenumber.PhoneNumber;
387ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee
397ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Leeimport java.util.Locale;
407ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee
417ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee
427ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee/**
437ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee * Looks up caller information for the given phone number.
447ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee *
457ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee * {@hide}
467ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee */
477ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Leepublic class CallerInfo {
487ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    private static final String TAG = "CallerInfo";
497ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee
507ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    /**
517ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * Please note that, any one of these member variables can be null,
527ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * and any accesses to them should be prepared to handle such a case.
537ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     *
547ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * Also, it is implied that phoneNumber is more often populated than
557ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * name is, (think of calls being dialed/received using numbers where
567ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * names are not known to the device), so phoneNumber should serve as
577ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * a dependable fallback when name is unavailable.
587ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     *
597ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * One other detail here is that this CallerInfo object reflects
607ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * information found on a connection, it is an OUTPUT that serves
617ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * mainly to display information to the user.  In no way is this object
627ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * used as input to make a connection, so we can choose to display
637ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * whatever human-readable text makes sense to the user for a
647ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * connection.  This is especially relevant for the phone number field,
657ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * since it is the one field that is most likely exposed to the user.
667ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     *
677ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * As an example:
687ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     *   1. User dials "911"
697ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     *   2. Device recognizes that this is an emergency number
707ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     *   3. We use the "Emergency Number" string instead of "911" in the
717ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     *     phoneNumber field.
727ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     *
737ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * What we're really doing here is treating phoneNumber as an essential
747ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * field here, NOT name.  We're NOT always guaranteed to have a name
757ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * for a connection, but the number should be displayable.
767ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     */
777ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    public String name;
787ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    public String phoneNumber;
797ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    public String normalizedNumber;
80101bed44998ff35c3a56f431345fac5c8229ec0eJay Shrauner    public String forwardingNumber;
817ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    public String geoDescription;
827ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee
837ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    public String cnapName;
847ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    public int numberPresentation;
857ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    public int namePresentation;
867ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    public boolean contactExists;
877ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee
887ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    public String phoneLabel;
897ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    /* Split up the phoneLabel into number type and label name */
907ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    public int    numberType;
917ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    public String numberLabel;
927ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee
937ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    public int photoResource;
947ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    public long person_id;
957ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    public boolean needUpdate;
967ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    public Uri contactRefUri;
977ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee
987ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    // fields to hold individual contact preference data,
997ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    // including the send to voicemail flag and the ringtone
1007ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    // uri reference.
1017ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    public Uri contactRingtoneUri;
1027ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    public boolean shouldSendToVoicemail;
1037ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee
1047ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    /**
1057ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * Drawable representing the caller image.  This is essentially
1067ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * a cache for the image data tied into the connection /
1077ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * callerinfo object.
1087ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     *
1097ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * This might be a high resolution picture which is more suitable
1107ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * for full-screen image view than for smaller icons used in some
1117ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * kinds of notifications.
1127ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     *
1137ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * The {@link #isCachedPhotoCurrent} flag indicates if the image
1147ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * data needs to be reloaded.
1157ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     */
1167ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    public Drawable cachedPhoto;
1177ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    /**
1187ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * Bitmap representing the caller image which has possibly lower
1197ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * resolution than {@link #cachedPhoto} and thus more suitable for
1207ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * icons (like notification icons).
1217ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     *
1227ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * In usual cases this is just down-scaled image of {@link #cachedPhoto}.
1237ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * If the down-scaling fails, this will just become null.
1247ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     *
1257ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * The {@link #isCachedPhotoCurrent} flag indicates if the image
1267ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * data needs to be reloaded.
1277ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     */
1287ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    public Bitmap cachedPhotoIcon;
1297ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    /**
1307ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * Boolean which indicates if {@link #cachedPhoto} and
1317ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * {@link #cachedPhotoIcon} is fresh enough. If it is false,
1327ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * those images aren't pointing to valid objects.
1337ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     */
1347ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    public boolean isCachedPhotoCurrent;
1357ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee
1367ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    private boolean mIsEmergency;
1377ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    private boolean mIsVoiceMail;
1387ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee
1397ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    public CallerInfo() {
1407ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        // TODO: Move all the basic initialization here?
1417ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        mIsEmergency = false;
1427ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        mIsVoiceMail = false;
1437ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    }
1447ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee
1457ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    /**
1467ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * getCallerInfo given a Cursor.
1477ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * @param context the context used to retrieve string constants
1487ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * @param contactRef the URI to attach to this CallerInfo object
1497ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * @param cursor the first object in the cursor is used to build the CallerInfo object.
1507ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * @return the CallerInfo which contains the caller id for the given
1517ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * number. The returned CallerInfo is null if no number is supplied.
1527ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     */
1537ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    public static CallerInfo getCallerInfo(Context context, Uri contactRef, Cursor cursor) {
1547ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        CallerInfo info = new CallerInfo();
1557ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        info.photoResource = 0;
1567ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        info.phoneLabel = null;
1577ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        info.numberType = 0;
1587ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        info.numberLabel = null;
1597ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        info.cachedPhoto = null;
1607ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        info.isCachedPhotoCurrent = false;
1617ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        info.contactExists = false;
1627ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee
1631a7f2bcab2d2023f2ee4cfb0bc57bc265b5aab87Chiao Cheng        Log.v(TAG, "getCallerInfo() based on cursor...");
1647ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee
1657ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        if (cursor != null) {
1667ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee            if (cursor.moveToFirst()) {
1677ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                // TODO: photo_id is always available but not taken
1687ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                // care of here. Maybe we should store it in the
1697ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                // CallerInfo object as well.
1707ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee
1717ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                int columnIndex;
1727ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee
1737ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                // Look for the name
1747ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                columnIndex = cursor.getColumnIndex(PhoneLookup.DISPLAY_NAME);
1757ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                if (columnIndex != -1) {
1767ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                    info.name = cursor.getString(columnIndex);
1777ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                }
1787ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee
1797ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                // Look for the number
1807ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                columnIndex = cursor.getColumnIndex(PhoneLookup.NUMBER);
1817ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                if (columnIndex != -1) {
1827ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                    info.phoneNumber = cursor.getString(columnIndex);
1837ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                }
1847ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee
1857ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                // Look for the normalized number
1867ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                columnIndex = cursor.getColumnIndex(PhoneLookup.NORMALIZED_NUMBER);
1877ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                if (columnIndex != -1) {
1887ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                    info.normalizedNumber = cursor.getString(columnIndex);
1897ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                }
1907ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee
1917ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                // Look for the label/type combo
1927ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                columnIndex = cursor.getColumnIndex(PhoneLookup.LABEL);
1937ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                if (columnIndex != -1) {
1947ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                    int typeColumnIndex = cursor.getColumnIndex(PhoneLookup.TYPE);
1957ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                    if (typeColumnIndex != -1) {
1967ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                        info.numberType = cursor.getInt(typeColumnIndex);
1977ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                        info.numberLabel = cursor.getString(columnIndex);
1987ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                        info.phoneLabel = Phone.getDisplayLabel(context,
1997ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                                info.numberType, info.numberLabel)
2007ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                                .toString();
2017ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                    }
2027ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                }
2037ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee
2047ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                // Look for the person_id.
2057ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                columnIndex = getColumnIndexForPersonId(contactRef, cursor);
2067ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                if (columnIndex != -1) {
2077ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                    info.person_id = cursor.getLong(columnIndex);
2081a7f2bcab2d2023f2ee4cfb0bc57bc265b5aab87Chiao Cheng                    Log.v(TAG, "==> got info.person_id: " + info.person_id);
2097ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                } else {
2107ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                    // No valid columnIndex, so we can't look up person_id.
2111a7f2bcab2d2023f2ee4cfb0bc57bc265b5aab87Chiao Cheng                    Log.v(TAG, "Couldn't find person_id column for " + contactRef);
2127ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                    // Watch out: this means that anything that depends on
2137ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                    // person_id will be broken (like contact photo lookups in
2147ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                    // the in-call UI, for example.)
2157ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                }
2167ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee
2177ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                // look for the custom ringtone, create from the string stored
2187ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                // in the database.
2197ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                columnIndex = cursor.getColumnIndex(PhoneLookup.CUSTOM_RINGTONE);
2207ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                if ((columnIndex != -1) && (cursor.getString(columnIndex) != null)) {
2217ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                    info.contactRingtoneUri = Uri.parse(cursor.getString(columnIndex));
2227ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                } else {
2237ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                    info.contactRingtoneUri = null;
2247ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                }
2257ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee
2267ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                // look for the send to voicemail flag, set it to true only
2277ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                // under certain circumstances.
2287ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                columnIndex = cursor.getColumnIndex(PhoneLookup.SEND_TO_VOICEMAIL);
2297ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                info.shouldSendToVoicemail = (columnIndex != -1) &&
2307ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                        ((cursor.getInt(columnIndex)) == 1);
2317ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                info.contactExists = true;
2327ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee            }
2337ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee            cursor.close();
2347ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        }
2357ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee
2367ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        info.needUpdate = false;
2377ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        info.name = normalize(info.name);
2387ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        info.contactRefUri = contactRef;
2397ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee
2407ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        return info;
2417ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    }
2427ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee
2437ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    /**
2447ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * getCallerInfo given a URI, look up in the call-log database
2457ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * for the uri unique key.
2467ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * @param context the context used to get the ContentResolver
2477ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * @param contactRef the URI used to lookup caller id
2487ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * @return the CallerInfo which contains the caller id for the given
2497ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * number. The returned CallerInfo is null if no number is supplied.
2507ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     */
2517ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    public static CallerInfo getCallerInfo(Context context, Uri contactRef) {
2527ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee
2537ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        return getCallerInfo(context, contactRef,
2547ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                context.getContentResolver().query(contactRef, null, null, null, null));
2557ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    }
2567ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee
2577ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    /**
2587ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * getCallerInfo given a phone number, look up in the call-log database
2597ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * for the matching caller id info.
2607ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * @param context the context used to get the ContentResolver
2617ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * @param number the phone number used to lookup caller id
2627ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * @return the CallerInfo which contains the caller id for the given
2637ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * number. The returned CallerInfo is null if no number is supplied. If
2647ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * a matching number is not found, then a generic caller info is returned,
2657ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * with all relevant fields empty or null.
2667ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     */
2677ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    public static CallerInfo getCallerInfo(Context context, String number) {
2681a7f2bcab2d2023f2ee4cfb0bc57bc265b5aab87Chiao Cheng        Log.v(TAG, "getCallerInfo() based on number...");
2697ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee
2707ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        if (TextUtils.isEmpty(number)) {
2717ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee            return null;
2727ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        }
2737ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee
2747ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        // Change the callerInfo number ONLY if it is an emergency number
2757ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        // or if it is the voicemail number.  If it is either, take a
2767ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        // shortcut and skip the query.
2777ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        if (PhoneNumberUtils.isLocalEmergencyNumber(number, context)) {
2787ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee            return new CallerInfo().markAsEmergency(context);
2797ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        } else if (PhoneNumberUtils.isVoiceMailNumber(number)) {
2807ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee            return new CallerInfo().markAsVoiceMail();
2817ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        }
2827ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee
2837ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        Uri contactUri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, Uri.encode(number));
2847ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee
2857ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        CallerInfo info = getCallerInfo(context, contactUri);
2867ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        info = doSecondaryLookupIfNecessary(context, number, info);
2877ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee
2887ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        // if no query results were returned with a viable number,
2897ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        // fill in the original number value we used to query with.
2907ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        if (TextUtils.isEmpty(info.phoneNumber)) {
2917ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee            info.phoneNumber = number;
2927ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        }
2937ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee
2947ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        return info;
2957ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    }
2967ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee
2977ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    /**
2987ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * Performs another lookup if previous lookup fails and it's a SIP call
2997ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * and the peer's username is all numeric. Look up the username as it
3007ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * could be a PSTN number in the contact database.
3017ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     *
3027ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * @param context the query context
3037ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * @param number the original phone number, could be a SIP URI
3047ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * @param previousResult the result of previous lookup
3057ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * @return previousResult if it's not the case
3067ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     */
3077ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    static CallerInfo doSecondaryLookupIfNecessary(Context context,
3087ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee            String number, CallerInfo previousResult) {
3097ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        if (!previousResult.contactExists
3107ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                && PhoneNumberUtils.isUriNumber(number)) {
3117ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee            String username = PhoneNumberUtils.getUsernameFromUriNumber(number);
3127ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee            if (PhoneNumberUtils.isGlobalPhoneNumber(username)) {
3137ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                previousResult = getCallerInfo(context,
3147ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                        Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI,
3157ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                                Uri.encode(username)));
3167ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee            }
3177ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        }
3187ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        return previousResult;
3197ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    }
3207ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee
3217ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    /**
3227ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * getCallerId: a convenience method to get the caller id for a given
3237ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * number.
3247ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     *
3257ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * @param context the context used to get the ContentResolver.
3267ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * @param number a phone number.
3277ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * @return if the number belongs to a contact, the contact's name is
3287ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * returned; otherwise, the number itself is returned.
3297ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     *
3307ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * TODO NOTE: This MAY need to refer to the Asynchronous Query API
3317ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * [startQuery()], instead of getCallerInfo, but since it looks like
3327ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * it is only being used by the provider calls in the messaging app:
3337ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     *   1. android.provider.Telephony.Mms.getDisplayAddress()
3347ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     *   2. android.provider.Telephony.Sms.getDisplayAddress()
3357ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * We may not need to make the change.
3367ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     */
3377ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    public static String getCallerId(Context context, String number) {
3387ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        CallerInfo info = getCallerInfo(context, number);
3397ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        String callerID = null;
3407ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee
3417ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        if (info != null) {
3427ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee            String name = info.name;
3437ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee
3447ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee            if (!TextUtils.isEmpty(name)) {
3457ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                callerID = name;
3467ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee            } else {
3477ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                callerID = number;
3487ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee            }
3497ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        }
3507ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee
3517ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        return callerID;
3527ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    }
3537ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee
3547ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    // Accessors
3557ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee
3567ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    /**
3577ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * @return true if the caller info is an emergency number.
3587ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     */
3597ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    public boolean isEmergencyNumber() {
3607ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        return mIsEmergency;
3617ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    }
3627ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee
3637ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    /**
3647ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * @return true if the caller info is a voicemail number.
3657ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     */
3667ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    public boolean isVoiceMailNumber() {
3677ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        return mIsVoiceMail;
3687ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    }
3697ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee
3707ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    /**
3717ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * Mark this CallerInfo as an emergency call.
3727ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * @param context To lookup the localized 'Emergency Number' string.
3737ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * @return this instance.
3747ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     */
3757ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    // TODO: Note we're setting the phone number here (refer to
3767ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    // javadoc comments at the top of CallerInfo class) to a localized
3777ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    // string 'Emergency Number'. This is pretty bad because we are
3787ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    // making UI work here instead of just packaging the data. We
3797ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    // should set the phone number to the dialed number and name to
3807ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    // 'Emergency Number' and let the UI make the decision about what
3817ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    // should be displayed.
3827ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    /* package */ CallerInfo markAsEmergency(Context context) {
383bf5cba07639082553097a4e4e24050718817ed96Christine Chen        phoneNumber = context.getString(R.string.emergency_call_dialog_number_for_display);
384bf5cba07639082553097a4e4e24050718817ed96Christine Chen        photoResource = 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) {
5631c85bef1f4ee97a3443d130bdff178ba4db1539fJay Shrauner        String countryIso = null;
5641c85bef1f4ee97a3443d130bdff178ba4db1539fJay Shrauner        CountryDetector detector = (CountryDetector) context.getSystemService(
5651c85bef1f4ee97a3443d130bdff178ba4db1539fJay Shrauner                Context.COUNTRY_DETECTOR);
5661c85bef1f4ee97a3443d130bdff178ba4db1539fJay Shrauner        if (detector != null) {
5671c85bef1f4ee97a3443d130bdff178ba4db1539fJay Shrauner            Country country = detector.detectCountry();
5681c85bef1f4ee97a3443d130bdff178ba4db1539fJay Shrauner            if (country != null) {
5691c85bef1f4ee97a3443d130bdff178ba4db1539fJay Shrauner                countryIso = country.getCountryIso();
5701c85bef1f4ee97a3443d130bdff178ba4db1539fJay Shrauner            } else {
5711c85bef1f4ee97a3443d130bdff178ba4db1539fJay Shrauner                Log.e(TAG, "CountryDetector.detectCountry() returned null.");
5721c85bef1f4ee97a3443d130bdff178ba4db1539fJay Shrauner            }
5731c85bef1f4ee97a3443d130bdff178ba4db1539fJay Shrauner        }
5741c85bef1f4ee97a3443d130bdff178ba4db1539fJay Shrauner        if (countryIso == null) {
5751c85bef1f4ee97a3443d130bdff178ba4db1539fJay Shrauner            countryIso = locale.getCountry();
5761c85bef1f4ee97a3443d130bdff178ba4db1539fJay Shrauner            Log.w(TAG, "No CountryDetector; falling back to countryIso based on locale: "
5771a7f2bcab2d2023f2ee4cfb0bc57bc265b5aab87Chiao Cheng                    + countryIso);
5781c85bef1f4ee97a3443d130bdff178ba4db1539fJay Shrauner        }
5791c85bef1f4ee97a3443d130bdff178ba4db1539fJay Shrauner        return countryIso;
5801c85bef1f4ee97a3443d130bdff178ba4db1539fJay Shrauner    }
5811c85bef1f4ee97a3443d130bdff178ba4db1539fJay Shrauner
5821c85bef1f4ee97a3443d130bdff178ba4db1539fJay Shrauner    protected static String getCurrentCountryIso(Context context) {
5831c85bef1f4ee97a3443d130bdff178ba4db1539fJay Shrauner        return getCurrentCountryIso(context, Locale.getDefault());
5847ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    }
5857ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee
5867ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    /**
5877ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     * @return a string debug representation of this instance.
5887ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee     */
5897ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    @Override
5907ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    public String toString() {
5917ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        // Warning: never check in this file with VERBOSE_DEBUG = true
5927ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        // because that will result in PII in the system log.
5937ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        final boolean VERBOSE_DEBUG = false;
5947ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee
5957ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        if (VERBOSE_DEBUG) {
5967ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee            return new StringBuilder(384)
5977ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                    .append(super.toString() + " { ")
5987ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                    .append("\nname: " + name)
5997ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                    .append("\nphoneNumber: " + phoneNumber)
6007ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                    .append("\nnormalizedNumber: " + normalizedNumber)
601101bed44998ff35c3a56f431345fac5c8229ec0eJay Shrauner                    .append("\forwardingNumber: " + forwardingNumber)
6027ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                    .append("\ngeoDescription: " + geoDescription)
6037ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                    .append("\ncnapName: " + cnapName)
6047ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                    .append("\nnumberPresentation: " + numberPresentation)
6057ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                    .append("\nnamePresentation: " + namePresentation)
6067ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                    .append("\ncontactExists: " + contactExists)
6077ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                    .append("\nphoneLabel: " + phoneLabel)
6087ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                    .append("\nnumberType: " + numberType)
6097ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                    .append("\nnumberLabel: " + numberLabel)
6107ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                    .append("\nphotoResource: " + photoResource)
6117ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                    .append("\nperson_id: " + person_id)
6127ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                    .append("\nneedUpdate: " + needUpdate)
6137ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                    .append("\ncontactRefUri: " + contactRefUri)
6147ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                    .append("\ncontactRingtoneUri: " + contactRefUri)
6157ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                    .append("\nshouldSendToVoicemail: " + shouldSendToVoicemail)
6167ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                    .append("\ncachedPhoto: " + cachedPhoto)
6177ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                    .append("\nisCachedPhotoCurrent: " + isCachedPhotoCurrent)
6187ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                    .append("\nemergency: " + mIsEmergency)
6197ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                    .append("\nvoicemail " + mIsVoiceMail)
6207ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                    .append(" }")
6217ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                    .toString();
6227ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        } else {
6237ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee            return new StringBuilder(128)
6247ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                    .append(super.toString() + " { ")
6257ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                    .append("name " + ((name == null) ? "null" : "non-null"))
6267ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                    .append(", phoneNumber " + ((phoneNumber == null) ? "null" : "non-null"))
6277ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                    .append(" }")
6287ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee                    .toString();
6297ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee        }
6307ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee    }
6317ef707319c0e3563ff92a772ba53cb5dca0e3ae1Yorke Lee}
632