16c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie/*
26c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie * Copyright (C) 2008 The Android Open Source Project
36c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie *
46c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie * Licensed under the Apache License, Version 2.0 (the "License");
56c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie * you may not use this file except in compliance with the License.
66c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie * You may obtain a copy of the License at
76c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie *
86c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie *      http://www.apache.org/licenses/LICENSE-2.0
96c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie *
106c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie * Unless required by applicable law or agreed to in writing, software
116c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie * distributed under the License is distributed on an "AS IS" BASIS,
126c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
136c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie * See the License for the specific language governing permissions and
146c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie * limitations under the License.
156c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie */
166c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
176c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xiepackage com.android.bluetooth.hfp;
186c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
19405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi Timport com.android.bluetooth.R;
20405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T
216c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xieimport com.android.internal.telephony.GsmAlphabet;
226c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
236c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xieimport android.bluetooth.BluetoothDevice;
2474ae04c73312403e89db0f8e9bd9601d403b4783fredcimport android.content.ContentResolver;
256c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xieimport android.content.Context;
266c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xieimport android.content.Intent;
276c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xieimport android.database.Cursor;
286c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xieimport android.net.Uri;
296c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xieimport android.provider.CallLog.Calls;
306c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xieimport android.provider.ContactsContract.CommonDataKinds.Phone;
316c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xieimport android.provider.ContactsContract.PhoneLookup;
326c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xieimport android.telephony.PhoneNumberUtils;
336c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xieimport android.util.Log;
346c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
356c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xieimport java.util.HashMap;
366c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
376c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie/**
386c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie * Helper for managing phonebook presentation over AT commands
396c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie * @hide
406c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie */
416c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xiepublic class AtPhonebook {
426c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie    private static final String TAG = "BluetoothAtPhonebook";
436c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie    private static final boolean DBG = false;
446c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
456c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie    /** The projection to use when querying the call log database in response
466c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie     *  to AT+CPBR for the MC, RC, and DC phone books (missed, received, and
476c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie     *   dialed calls respectively)
486c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie     */
496c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie    private static final String[] CALLS_PROJECTION = new String[] {
509674eb043aeb1474aa23ddd0739e3b8f05432630Jay Shrauner        Calls._ID, Calls.NUMBER, Calls.NUMBER_PRESENTATION
516c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie    };
526c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
536c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie    /** The projection to use when querying the contacts database in response
546c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie     *   to AT+CPBR for the ME phonebook (saved phone numbers).
556c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie     */
566c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie    private static final String[] PHONES_PROJECTION = new String[] {
576c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        Phone._ID, Phone.DISPLAY_NAME, Phone.NUMBER, Phone.TYPE
586c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie    };
596c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
606c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie    /** Android supports as many phonebook entries as the flash can hold, but
616c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie     *  BT periphals don't. Limit the number we'll report. */
626c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie    private static final int MAX_PHONEBOOK_SIZE = 16384;
636c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
646c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie    private static final String OUTGOING_CALL_WHERE = Calls.TYPE + "=" + Calls.OUTGOING_TYPE;
656c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie    private static final String INCOMING_CALL_WHERE = Calls.TYPE + "=" + Calls.INCOMING_TYPE;
666c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie    private static final String MISSED_CALL_WHERE = Calls.TYPE + "=" + Calls.MISSED_TYPE;
676c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie    private static final String VISIBLE_PHONEBOOK_WHERE = Phone.IN_VISIBLE_GROUP + "=1";
686c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
696c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie    private class PhonebookResult {
706c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        public Cursor  cursor; // result set of last query
716c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        public int     numberColumn;
729674eb043aeb1474aa23ddd0739e3b8f05432630Jay Shrauner        public int     numberPresentationColumn;
736c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        public int     typeColumn;
746c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        public int     nameColumn;
756c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie    };
766c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
7774ae04c73312403e89db0f8e9bd9601d403b4783fredc    private Context mContext;
7874ae04c73312403e89db0f8e9bd9601d403b4783fredc    private ContentResolver mContentResolver;
79405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T    private HeadsetStateMachine mStateMachine;
806c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie    private String mCurrentPhonebook;
816c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie    private String mCharacterSet = "UTF-8";
826c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
836c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie    private int mCpbrIndex1, mCpbrIndex2;
846c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie    private boolean mCheckingAccessPermission;
856c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
866c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie    // package and class name to which we send intent to check phone book access permission
876c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie    private static final String ACCESS_AUTHORITY_PACKAGE = "com.android.settings";
886c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie    private static final String ACCESS_AUTHORITY_CLASS =
896c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        "com.android.settings.bluetooth.BluetoothPermissionRequest";
906c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie    private static final String BLUETOOTH_ADMIN_PERM = android.Manifest.permission.BLUETOOTH_ADMIN;
916c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
926c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie    private final HashMap<String, PhonebookResult> mPhonebooks =
936c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie            new HashMap<String, PhonebookResult>(4);
946c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
95405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T    final int TYPE_UNKNOWN = -1;
96405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T    final int TYPE_READ = 0;
97405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T    final int TYPE_SET = 1;
98405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T    final int TYPE_TEST = 2;
99405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T
100405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T    public AtPhonebook(Context context, HeadsetStateMachine headsetState) {
1016c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        mContext = context;
10274ae04c73312403e89db0f8e9bd9601d403b4783fredc        mContentResolver = context.getContentResolver();
103405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T        mStateMachine = headsetState;
1046c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        mPhonebooks.put("DC", new PhonebookResult());  // dialled calls
1056c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        mPhonebooks.put("RC", new PhonebookResult());  // received calls
1066c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        mPhonebooks.put("MC", new PhonebookResult());  // missed calls
1076c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        mPhonebooks.put("ME", new PhonebookResult());  // mobile phonebook
1086c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
1096c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        mCurrentPhonebook = "ME";  // default to mobile phonebook
1106c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
1116c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        mCpbrIndex1 = mCpbrIndex2 = -1;
1126c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        mCheckingAccessPermission = false;
1136c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie    }
1146c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
11574ae04c73312403e89db0f8e9bd9601d403b4783fredc    public void cleanup() {
11674ae04c73312403e89db0f8e9bd9601d403b4783fredc        mPhonebooks.clear();
11774ae04c73312403e89db0f8e9bd9601d403b4783fredc    }
11874ae04c73312403e89db0f8e9bd9601d403b4783fredc
1196c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie    /** Returns the last dialled number, or null if no numbers have been called */
1206c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie    public String getLastDialledNumber() {
1216c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        String[] projection = {Calls.NUMBER};
12274ae04c73312403e89db0f8e9bd9601d403b4783fredc        Cursor cursor = mContentResolver.query(Calls.CONTENT_URI, projection,
1236c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie                Calls.TYPE + "=" + Calls.OUTGOING_TYPE, null, Calls.DEFAULT_SORT_ORDER +
1246c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie                " LIMIT 1");
1256c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        if (cursor == null) return null;
1266c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
1276c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        if (cursor.getCount() < 1) {
1286c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie            cursor.close();
1296c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie            return null;
1306c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        }
1316c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        cursor.moveToNext();
1326c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        int column = cursor.getColumnIndexOrThrow(Calls.NUMBER);
1336c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        String number = cursor.getString(column);
1346c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        cursor.close();
1356c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        return number;
1366c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie    }
1376c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
138405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T    public boolean getCheckingAccessPermission() {
139405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T        return mCheckingAccessPermission;
140405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T    }
141405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T
142405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T    public void setCheckingAccessPermission(boolean checkAccessPermission) {
143405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T        mCheckingAccessPermission = checkAccessPermission;
144405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T    }
145405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T
146405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T    public void setCpbrIndex(int cpbrIndex) {
147405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T        mCpbrIndex1 = mCpbrIndex2 = cpbrIndex;
148405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T    }
149405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T
150405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T    public void handleCscsCommand(String atString, int type)
151405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T    {
152405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T        log("handleCscsCommand - atString = " +atString);
153405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T        // Select Character Set
154405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T        int atCommandResult = HeadsetHalConstants.AT_RESPONSE_ERROR;
155405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T        int atCommandErrorCode = -1;
156405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T        String atCommandResponse = null;
157405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T        switch (type) {
158405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T            case TYPE_READ: // Read
159405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                log("handleCscsCommand - Read Command");
160405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                atCommandResponse = "+CSCS: \"" + mCharacterSet + "\"";
161405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                atCommandResult = HeadsetHalConstants.AT_RESPONSE_OK;
162405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                break;
163405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T            case TYPE_TEST: // Test
164405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                log("handleCscsCommand - Test Command");
165405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                atCommandResponse = ( "+CSCS: (\"UTF-8\",\"IRA\",\"GSM\")");
166405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                atCommandResult = HeadsetHalConstants.AT_RESPONSE_OK;
167405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                break;
168405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T            case TYPE_SET: // Set
169405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                log("handleCscsCommand - Set Command");
170405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                String[] args = atString.split("=");
171405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                if (args.length < 2 || !(args[1] instanceof String)) {
172405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                    mStateMachine.atResponseCodeNative(atCommandResult, atCommandErrorCode);
173405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                    break;
174405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                }
175405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                String characterSet = ((atString.split("="))[1]);
176405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                characterSet = characterSet.replace("\"", "");
177405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                if (characterSet.equals("GSM") || characterSet.equals("IRA") ||
178405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                    characterSet.equals("UTF-8") || characterSet.equals("UTF8")) {
179405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                    mCharacterSet = characterSet;
180405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                    atCommandResult = HeadsetHalConstants.AT_RESPONSE_OK;
181405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                } else {
182405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                    atCommandErrorCode = BluetoothCmeError.OPERATION_NOT_SUPPORTED;
183405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                }
184405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                break;
185405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T            case TYPE_UNKNOWN:
186405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T            default:
187405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                log("handleCscsCommand - Invalid chars");
188405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                atCommandErrorCode = BluetoothCmeError.TEXT_HAS_INVALID_CHARS;
1896c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        }
190405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T        if (atCommandResponse != null)
191405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T            mStateMachine.atResponseStringNative(atCommandResponse);
192405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T        mStateMachine.atResponseCodeNative(atCommandResult, atCommandErrorCode);
193405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T    }
1946c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
195405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T    public void handleCpbsCommand(String atString, int type) {
196405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T        // Select PhoneBook memory Storage
197405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T        log("handleCpbsCommand - atString = " +atString);
198405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T        int atCommandResult = HeadsetHalConstants.AT_RESPONSE_ERROR;
199405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T        int atCommandErrorCode = -1;
200405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T        String atCommandResponse = null;
201405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T        switch (type) {
202405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T            case TYPE_READ: // Read
203405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                log("handleCpbsCommand - read command");
204405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                // Return current size and max size
205405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                if ("SM".equals(mCurrentPhonebook)) {
206405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                    atCommandResponse = "+CPBS: \"SM\",0," + getMaxPhoneBookSize(0);
207405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                    atCommandResult = HeadsetHalConstants.AT_RESPONSE_OK;
208405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                    if (atCommandResponse != null)
209405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                        mStateMachine.atResponseStringNative(atCommandResponse);
210405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                    mStateMachine.atResponseCodeNative(atCommandResult, atCommandErrorCode);
211405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                    break;
212405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                }
213405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                PhonebookResult pbr = getPhonebookResult(mCurrentPhonebook, true);
214405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                if (pbr == null) {
215405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                    atCommandErrorCode = BluetoothCmeError.OPERATION_NOT_SUPPORTED;
216405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                    mStateMachine.atResponseCodeNative(atCommandResult, atCommandErrorCode);
217405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                    break;
2186c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie                }
219405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                int size = pbr.cursor.getCount();
220405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                atCommandResponse = "+CPBS: \"" + mCurrentPhonebook + "\"," + size + "," + getMaxPhoneBookSize(size);
22115d36984a79d6e35c659edb0efdf929f0b526bd5Fred                pbr.cursor.close();
22215d36984a79d6e35c659edb0efdf929f0b526bd5Fred                pbr.cursor = null;
223405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                atCommandResult = HeadsetHalConstants.AT_RESPONSE_OK;
224405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                break;
225405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T            case TYPE_TEST: // Test
226405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                log("handleCpbsCommand - test command");
227405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                atCommandResponse = ("+CPBS: (\"ME\",\"SM\",\"DC\",\"RC\",\"MC\")");
228405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                atCommandResult = HeadsetHalConstants.AT_RESPONSE_OK;
229405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                break;
230405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T            case TYPE_SET: // Set
231405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                log("handleCpbsCommand - set command");
232405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                String[] args = atString.split("=");
233405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                // Select phonebook memory
234405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                if (args.length < 2 || !(args[1] instanceof String)) {
235405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                    mStateMachine.atResponseCodeNative(atCommandResult, atCommandErrorCode);
236405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                    break;
237405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                }
238405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                String pb = ((String)args[1]).trim();
239405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                while (pb.endsWith("\"")) pb = pb.substring(0, pb.length() - 1);
240405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                while (pb.startsWith("\"")) pb = pb.substring(1, pb.length());
241405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                if (getPhonebookResult(pb, false) == null && !"SM".equals(pb)) {
242405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                   if (DBG) log("Dont know phonebook: '" + pb + "'");
243405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                   atCommandErrorCode = BluetoothCmeError.OPERATION_NOT_ALLOWED;
244405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                   mStateMachine.atResponseCodeNative(atCommandResult, atCommandErrorCode);
245405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                   break;
246405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                }
247405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                mCurrentPhonebook = pb;
248405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                atCommandResult = HeadsetHalConstants.AT_RESPONSE_OK;
249405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                break;
250405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T            case TYPE_UNKNOWN:
251405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T            default:
252405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                log("handleCpbsCommand - invalid chars");
253405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                atCommandErrorCode = BluetoothCmeError.TEXT_HAS_INVALID_CHARS;
254405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T        }
255405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T        if (atCommandResponse != null)
256405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T            mStateMachine.atResponseStringNative(atCommandResponse);
257405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T        mStateMachine.atResponseCodeNative(atCommandResult, atCommandErrorCode);
258405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T    }
2596c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
260405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T    public void handleCpbrCommand(String atString, int type, BluetoothDevice remoteDevice) {
261405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T        log("handleCpbrCommand - atString = " +atString);
262405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T        int atCommandResult = HeadsetHalConstants.AT_RESPONSE_ERROR;
263405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T        int atCommandErrorCode = -1;
264405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T        String atCommandResponse = null;
265405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T        switch (type) {
266405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T            case TYPE_TEST: // Test
267405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                /* Ideally we should return the maximum range of valid index's
268405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                 * for the selected phone book, but this causes problems for the
269405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                 * Parrot CK3300. So instead send just the range of currently
270405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                 * valid index's.
271405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                 */
272405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                log("handleCpbrCommand - test command");
273405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                int size;
274405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                if ("SM".equals(mCurrentPhonebook)) {
275405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                    size = 0;
276405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                } else {
277405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                    PhonebookResult pbr = getPhonebookResult(mCurrentPhonebook, true); //false);
278405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                    if (pbr == null) {
279405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                        atCommandErrorCode = BluetoothCmeError.OPERATION_NOT_ALLOWED;
280405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                        mStateMachine.atResponseCodeNative(atCommandResult, atCommandErrorCode);
281405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                        break;
282405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                    }
283405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                    size = pbr.cursor.getCount();
284405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                    log("handleCpbrCommand - size = "+size);
28515d36984a79d6e35c659edb0efdf929f0b526bd5Fred                    pbr.cursor.close();
28615d36984a79d6e35c659edb0efdf929f0b526bd5Fred                    pbr.cursor = null;
287405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                }
288405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                if (size == 0) {
289405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                    /* Sending "+CPBR: (1-0)" can confused some carkits, send "1-1" * instead */
290405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                    size = 1;
291405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                }
292405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                atCommandResponse = "+CPBR: (1-" + size + "),30,30";
293405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                atCommandResult = HeadsetHalConstants.AT_RESPONSE_OK;
294405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                if (atCommandResponse != null)
295405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                    mStateMachine.atResponseStringNative(atCommandResponse);
296405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                mStateMachine.atResponseCodeNative(atCommandResult, atCommandErrorCode);
297405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                break;
298405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T            // Read PhoneBook Entries
299405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T            case TYPE_READ:
300405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T            case TYPE_SET: // Set & read
301405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                // Phone Book Read Request
302405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                // AT+CPBR=<index1>[,<index2>]
303405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                log("handleCpbrCommand - set/read command");
304405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                if (mCpbrIndex1 != -1) {
305405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                   /* handling a CPBR at the moment, reject this CPBR command */
306405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                   atCommandErrorCode = BluetoothCmeError.OPERATION_NOT_ALLOWED;
307405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                   mStateMachine.atResponseCodeNative(atCommandResult, atCommandErrorCode);
308405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                   break;
309405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                }
310405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                // Parse indexes
311405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                int index1;
312405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                int index2;
313405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                if ((atString.split("=")).length < 2) {
314405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                    mStateMachine.atResponseCodeNative(atCommandResult, atCommandErrorCode);
315405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                    break;
316405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                }
317405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                String atCommand = (atString.split("="))[1];
318405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                String[] indices = atCommand.split(",");
319405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                for(int i = 0; i < indices.length; i++)
320be38be94c0a2faf3802b596be5b3ab568d6d85a4zzy                    //replace AT command separator ';' from the index if any
321be38be94c0a2faf3802b596be5b3ab568d6d85a4zzy                    indices[i] = indices[i].replace(';', ' ').trim();
322405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                try {
323405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                    index1 = Integer.parseInt(indices[0]);
324405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                    if (indices.length == 1)
325405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                        index2 = index1;
326405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                    else
327405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                        index2 = Integer.parseInt(indices[1]);
328405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                }
329405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                catch (Exception e) {
330be38be94c0a2faf3802b596be5b3ab568d6d85a4zzy                    log("handleCpbrCommand - exception - invalid chars: " + e.toString());
331405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                    atCommandErrorCode = BluetoothCmeError.TEXT_HAS_INVALID_CHARS;
332405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                    mStateMachine.atResponseCodeNative(atCommandResult, atCommandErrorCode);
333405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                    break;
334405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                }
335405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                mCpbrIndex1 = index1;
336405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                mCpbrIndex2 = index2;
337405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                mCheckingAccessPermission = true;
338405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T
339405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                if (checkAccessPermission(remoteDevice)) {
340405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                    mCheckingAccessPermission = false;
341405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                    atCommandResult = processCpbrCommand();
342405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                    mCpbrIndex1 = mCpbrIndex2 = -1;
343405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                    mStateMachine.atResponseCodeNative(atCommandResult, atCommandErrorCode);
344405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                    break;
345405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                }
346405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                // no reponse here, will continue the process in handleAccessPermissionResult
347405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                break;
348405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                case TYPE_UNKNOWN:
349405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                default:
350405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                    log("handleCpbrCommand - invalid chars");
351405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                    atCommandErrorCode = BluetoothCmeError.TEXT_HAS_INVALID_CHARS;
352405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                    mStateMachine.atResponseCodeNative(atCommandResult, atCommandErrorCode);
3536c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        }
3546c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie    }
3556c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
3566c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie    /** Get the most recent result for the given phone book,
3576c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie     *  with the cursor ready to go.
3586c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie     *  If force then re-query that phonebook
3596c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie     *  Returns null if the cursor is not ready
3606c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie     */
3616c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie    private synchronized PhonebookResult getPhonebookResult(String pb, boolean force) {
3626c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        if (pb == null) {
3636c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie            return null;
3646c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        }
3656c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        PhonebookResult pbr = mPhonebooks.get(pb);
3666c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        if (pbr == null) {
3676c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie            pbr = new PhonebookResult();
3686c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        }
3696c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        if (force || pbr.cursor == null) {
3706c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie            if (!queryPhonebook(pb, pbr)) {
3716c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie                return null;
3726c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie            }
3736c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        }
3746c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
3756c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        return pbr;
3766c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie    }
3776c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
3786c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie    private synchronized boolean queryPhonebook(String pb, PhonebookResult pbr) {
3796c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        String where;
3806c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        boolean ancillaryPhonebook = true;
3816c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
3826c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        if (pb.equals("ME")) {
3836c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie            ancillaryPhonebook = false;
3846c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie            where = VISIBLE_PHONEBOOK_WHERE;
3856c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        } else if (pb.equals("DC")) {
3866c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie            where = OUTGOING_CALL_WHERE;
3876c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        } else if (pb.equals("RC")) {
3886c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie            where = INCOMING_CALL_WHERE;
3896c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        } else if (pb.equals("MC")) {
3906c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie            where = MISSED_CALL_WHERE;
3916c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        } else {
3926c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie            return false;
3936c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        }
3946c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
3956c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        if (pbr.cursor != null) {
3966c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie            pbr.cursor.close();
3976c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie            pbr.cursor = null;
3986c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        }
3996c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
4006c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        if (ancillaryPhonebook) {
40174ae04c73312403e89db0f8e9bd9601d403b4783fredc            pbr.cursor = mContentResolver.query(
4026c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie                    Calls.CONTENT_URI, CALLS_PROJECTION, where, null,
4036c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie                    Calls.DEFAULT_SORT_ORDER + " LIMIT " + MAX_PHONEBOOK_SIZE);
4046c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie            if (pbr.cursor == null) return false;
4056c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
4066c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie            pbr.numberColumn = pbr.cursor.getColumnIndexOrThrow(Calls.NUMBER);
4079674eb043aeb1474aa23ddd0739e3b8f05432630Jay Shrauner            pbr.numberPresentationColumn =
4089674eb043aeb1474aa23ddd0739e3b8f05432630Jay Shrauner                    pbr.cursor.getColumnIndexOrThrow(Calls.NUMBER_PRESENTATION);
4096c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie            pbr.typeColumn = -1;
4106c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie            pbr.nameColumn = -1;
4116c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        } else {
41274ae04c73312403e89db0f8e9bd9601d403b4783fredc            pbr.cursor = mContentResolver.query(Phone.CONTENT_URI, PHONES_PROJECTION,
4136c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie                    where, null, Phone.NUMBER + " LIMIT " + MAX_PHONEBOOK_SIZE);
4146c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie            if (pbr.cursor == null) return false;
4156c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
4166c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie            pbr.numberColumn = pbr.cursor.getColumnIndex(Phone.NUMBER);
4179674eb043aeb1474aa23ddd0739e3b8f05432630Jay Shrauner            pbr.numberPresentationColumn = -1;
4186c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie            pbr.typeColumn = pbr.cursor.getColumnIndex(Phone.TYPE);
4196c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie            pbr.nameColumn = pbr.cursor.getColumnIndex(Phone.DISPLAY_NAME);
4206c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        }
4216c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        Log.i(TAG, "Refreshed phonebook " + pb + " with " + pbr.cursor.getCount() + " results");
4226c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        return true;
4236c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie    }
4246c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
4256c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie    synchronized void resetAtState() {
4266c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        mCharacterSet = "UTF-8";
4276c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        mCpbrIndex1 = mCpbrIndex2 = -1;
4286c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        mCheckingAccessPermission = false;
4296c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie    }
4306c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
4316c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie    private synchronized int getMaxPhoneBookSize(int currSize) {
4326c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        // some car kits ignore the current size and request max phone book
4336c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        // size entries. Thus, it takes a long time to transfer all the
4346c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        // entries. Use a heuristic to calculate the max phone book size
4356c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        // considering future expansion.
4366c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        // maxSize = currSize + currSize / 2 rounded up to nearest power of 2
4376c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        // If currSize < 100, use 100 as the currSize
4386c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
4396c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        int maxSize = (currSize < 100) ? 100 : currSize;
4406c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        maxSize += maxSize / 2;
4416c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        return roundUpToPowerOfTwo(maxSize);
4426c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie    }
4436c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
4446c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie    private int roundUpToPowerOfTwo(int x) {
4456c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        x |= x >> 1;
4466c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        x |= x >> 2;
4476c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        x |= x >> 4;
4486c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        x |= x >> 8;
4496c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        x |= x >> 16;
4506c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        return x + 1;
4516c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie    }
4526c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
4536c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie    // process CPBR command after permission check
454405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T    /*package*/ int processCpbrCommand()
4556c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie    {
456405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T        log("processCpbrCommand");
457405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T        int atCommandResult = HeadsetHalConstants.AT_RESPONSE_ERROR;
458405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T        int atCommandErrorCode = -1;
459405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T        String atCommandResponse = null;
460405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T        StringBuilder response = new StringBuilder();
461405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T        String record;
462405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T
4636c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        // Shortcut SM phonebook
4646c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        if ("SM".equals(mCurrentPhonebook)) {
465405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T            atCommandResult = HeadsetHalConstants.AT_RESPONSE_OK;
466405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T            return atCommandResult;
4676c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        }
4686c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
4696c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        // Check phonebook
470405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T        PhonebookResult pbr = getPhonebookResult(mCurrentPhonebook, true); //false);
4716c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        if (pbr == null) {
472405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T            atCommandErrorCode = BluetoothCmeError.OPERATION_NOT_ALLOWED;
473405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T            return atCommandResult;
4746c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        }
4756c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
4766c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        // More sanity checks
4776c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        // Send OK instead of ERROR if these checks fail.
4786c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        // When we send error, certain kits like BMW disconnect the
4796c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        // Handsfree connection.
4806c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        if (pbr.cursor.getCount() == 0 || mCpbrIndex1 <= 0 || mCpbrIndex2 < mCpbrIndex1  ||
4816c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie            mCpbrIndex2 > pbr.cursor.getCount() || mCpbrIndex1 > pbr.cursor.getCount()) {
482405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T            atCommandResult = HeadsetHalConstants.AT_RESPONSE_OK;
483405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T            return atCommandResult;
4846c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        }
4856c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
4866c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        // Process
487405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T        atCommandResult = HeadsetHalConstants.AT_RESPONSE_OK;
4886c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        int errorDetected = -1; // no error
4896c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        pbr.cursor.moveToPosition(mCpbrIndex1 - 1);
490405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T        log("mCpbrIndex1 = "+mCpbrIndex1+ " and mCpbrIndex2 = "+mCpbrIndex2);
4916c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        for (int index = mCpbrIndex1; index <= mCpbrIndex2; index++) {
4926c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie            String number = pbr.cursor.getString(pbr.numberColumn);
4936c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie            String name = null;
4946c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie            int type = -1;
49509b09c15dcd853d452b24d46a3c81ca63fa090eaMatthew Xie            if (pbr.nameColumn == -1 && number != null && number.length() > 0) {
4966c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie                // try caller id lookup
4976c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie                // TODO: This code is horribly inefficient. I saw it
4986c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie                // take 7 seconds to process 100 missed calls.
49974ae04c73312403e89db0f8e9bd9601d403b4783fredc                Cursor c = mContentResolver.
5006c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie                    query(Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, number),
5016c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie                          new String[] {PhoneLookup.DISPLAY_NAME, PhoneLookup.TYPE},
5026c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie                          null, null, null);
5036c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie                if (c != null) {
5046c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie                    if (c.moveToFirst()) {
5056c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie                        name = c.getString(0);
5066c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie                        type = c.getInt(1);
5076c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie                    }
5086c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie                    c.close();
5096c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie                }
5106c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie                if (DBG && name == null) log("Caller ID lookup failed for " + number);
5116c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
512abf19e783556a93cfdd33468454a309ed347bfc4Zhihai Xu            } else if (pbr.nameColumn != -1) {
5136c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie                name = pbr.cursor.getString(pbr.nameColumn);
514abf19e783556a93cfdd33468454a309ed347bfc4Zhihai Xu            } else {
515abf19e783556a93cfdd33468454a309ed347bfc4Zhihai Xu                log("processCpbrCommand: empty name and number");
5166c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie            }
5176c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie            if (name == null) name = "";
5186c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie            name = name.trim();
5196c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie            if (name.length() > 28) name = name.substring(0, 28);
5206c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
5216c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie            if (pbr.typeColumn != -1) {
5226c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie                type = pbr.cursor.getInt(pbr.typeColumn);
5236c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie                name = name + "/" + getPhoneType(type);
5246c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie            }
5256c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
5266c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie            if (number == null) number = "";
5276c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie            int regionType = PhoneNumberUtils.toaFromString(number);
5286c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
5296c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie            number = number.trim();
5306c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie            number = PhoneNumberUtils.stripSeparators(number);
5316c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie            if (number.length() > 30) number = number.substring(0, 30);
5329674eb043aeb1474aa23ddd0739e3b8f05432630Jay Shrauner            int numberPresentation = Calls.PRESENTATION_ALLOWED;
5339674eb043aeb1474aa23ddd0739e3b8f05432630Jay Shrauner            if (pbr.numberPresentationColumn != -1) {
5349674eb043aeb1474aa23ddd0739e3b8f05432630Jay Shrauner                numberPresentation = pbr.cursor.getInt(pbr.numberPresentationColumn);
5359674eb043aeb1474aa23ddd0739e3b8f05432630Jay Shrauner            }
5369674eb043aeb1474aa23ddd0739e3b8f05432630Jay Shrauner            if (numberPresentation != Calls.PRESENTATION_ALLOWED) {
5376c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie                number = "";
5389674eb043aeb1474aa23ddd0739e3b8f05432630Jay Shrauner                // TODO: there are 3 types of numbers should have resource
5399674eb043aeb1474aa23ddd0739e3b8f05432630Jay Shrauner                // strings for: unknown, private, and payphone
540405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                name = mContext.getString(R.string.unknownNumber);
5416c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie            }
5426c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
5436c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie            // TODO(): Handle IRA commands. It's basically
5446c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie            // a 7 bit ASCII character set.
5456c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie            if (!name.equals("") && mCharacterSet.equals("GSM")) {
5466c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie                byte[] nameByte = GsmAlphabet.stringToGsm8BitPacked(name);
5476c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie                if (nameByte == null) {
548405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                    name = mContext.getString(R.string.unknownNumber);
5496c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie                } else {
5506c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie                    name = new String(nameByte);
5516c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie                }
5526c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie            }
5536c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
554405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T            record = "+CPBR: " + index + ",\"" + number + "\"," + regionType + ",\"" + name + "\"";
555405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T            record = record + "\r\n\r\n";
556405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T            atCommandResponse = record;
557405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T            log("processCpbrCommand - atCommandResponse = "+atCommandResponse);
558405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T            mStateMachine.atResponseStringNative(atCommandResponse);
5596c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie            if (!pbr.cursor.moveToNext()) {
5606c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie                break;
5616c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie            }
5626c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        }
56315d36984a79d6e35c659edb0efdf929f0b526bd5Fred        if(pbr != null && pbr.cursor != null) {
56415d36984a79d6e35c659edb0efdf929f0b526bd5Fred            pbr.cursor.close();
56515d36984a79d6e35c659edb0efdf929f0b526bd5Fred            pbr.cursor = null;
56615d36984a79d6e35c659edb0efdf929f0b526bd5Fred        }
567405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T        return atCommandResult;
568405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T    }
569405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T
570405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T    // Check if the remote device has premission to read our phone book
571405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T    // Return true if it has the permission
572405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T    // false if not known and we have sent our Intent to check
573405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T    private boolean checkAccessPermission(BluetoothDevice remoteDevice) {
574405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T        log("checkAccessPermission");
575405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T        boolean trust = remoteDevice.getTrustState();
576405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T
577405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T        if (trust) {
578405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T            return true;
579405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T        }
580405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T
581405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T        log("checkAccessPermission - ACTION_CONNECTION_ACCESS_REQUEST");
582405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T        Intent intent = new Intent(BluetoothDevice.ACTION_CONNECTION_ACCESS_REQUEST);
583405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T        intent.setClassName(ACCESS_AUTHORITY_PACKAGE, ACCESS_AUTHORITY_CLASS);
584405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T        intent.putExtra(BluetoothDevice.EXTRA_ACCESS_REQUEST_TYPE,
585405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T        BluetoothDevice.REQUEST_TYPE_PHONEBOOK_ACCESS);
586405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T        intent.putExtra(BluetoothDevice.EXTRA_DEVICE, remoteDevice);
587405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T        // Leave EXTRA_PACKAGE_NAME and EXTRA_CLASS_NAME field empty
588405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T        // BluetoothHandsfree's broadcast receiver is anonymous, cannot be targeted
589405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T        mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM);
590405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T        return false;
5916c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie    }
5926c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
5936c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie    private static String getPhoneType(int type) {
5946c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        switch (type) {
5956c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie            case Phone.TYPE_HOME:
5966c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie                return "H";
5976c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie            case Phone.TYPE_MOBILE:
5986c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie                return "M";
5996c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie            case Phone.TYPE_WORK:
6006c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie                return "W";
6016c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie            case Phone.TYPE_FAX_HOME:
6026c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie            case Phone.TYPE_FAX_WORK:
6036c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie                return "F";
6046c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie            case Phone.TYPE_OTHER:
6056c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie            case Phone.TYPE_CUSTOM:
6066c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie            default:
6076c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie                return "O";
6086c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        }
6096c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie    }
6106c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
6116c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie    private static void log(String msg) {
6126c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        Log.d(TAG, msg);
6136c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie    }
6146c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie}
615