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;
34343b96e3995da4038b614384dcdad8a6494b4bc4Nitin Srivastavaimport com.android.bluetooth.Utils;
35343b96e3995da4038b614384dcdad8a6494b4bc4Nitin Srivastava
366c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
376c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xieimport java.util.HashMap;
386c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
396c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie/**
406c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie * Helper for managing phonebook presentation over AT commands
416c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie * @hide
426c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie */
436c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xiepublic class AtPhonebook {
446c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie    private static final String TAG = "BluetoothAtPhonebook";
456c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie    private static final boolean DBG = false;
466c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
476c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie    /** The projection to use when querying the call log database in response
486c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie     *  to AT+CPBR for the MC, RC, and DC phone books (missed, received, and
496c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie     *   dialed calls respectively)
506c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie     */
516c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie    private static final String[] CALLS_PROJECTION = new String[] {
529674eb043aeb1474aa23ddd0739e3b8f05432630Jay Shrauner        Calls._ID, Calls.NUMBER, Calls.NUMBER_PRESENTATION
536c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie    };
546c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
556c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie    /** The projection to use when querying the contacts database in response
566c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie     *   to AT+CPBR for the ME phonebook (saved phone numbers).
576c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie     */
586c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie    private static final String[] PHONES_PROJECTION = new String[] {
596c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        Phone._ID, Phone.DISPLAY_NAME, Phone.NUMBER, Phone.TYPE
606c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie    };
616c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
626c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie    /** Android supports as many phonebook entries as the flash can hold, but
636c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie     *  BT periphals don't. Limit the number we'll report. */
646c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie    private static final int MAX_PHONEBOOK_SIZE = 16384;
656c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
666c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie    private static final String OUTGOING_CALL_WHERE = Calls.TYPE + "=" + Calls.OUTGOING_TYPE;
676c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie    private static final String INCOMING_CALL_WHERE = Calls.TYPE + "=" + Calls.INCOMING_TYPE;
686c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie    private static final String MISSED_CALL_WHERE = Calls.TYPE + "=" + Calls.MISSED_TYPE;
696c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie    private static final String VISIBLE_PHONEBOOK_WHERE = Phone.IN_VISIBLE_GROUP + "=1";
706c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
716c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie    private class PhonebookResult {
726c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        public Cursor  cursor; // result set of last query
736c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        public int     numberColumn;
749674eb043aeb1474aa23ddd0739e3b8f05432630Jay Shrauner        public int     numberPresentationColumn;
756c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        public int     typeColumn;
766c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        public int     nameColumn;
776c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie    };
786c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
7974ae04c73312403e89db0f8e9bd9601d403b4783fredc    private Context mContext;
8074ae04c73312403e89db0f8e9bd9601d403b4783fredc    private ContentResolver mContentResolver;
81405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T    private HeadsetStateMachine mStateMachine;
826c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie    private String mCurrentPhonebook;
836c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie    private String mCharacterSet = "UTF-8";
846c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
856c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie    private int mCpbrIndex1, mCpbrIndex2;
866c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie    private boolean mCheckingAccessPermission;
876c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
886c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie    // package and class name to which we send intent to check phone book access permission
896c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie    private static final String ACCESS_AUTHORITY_PACKAGE = "com.android.settings";
906c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie    private static final String ACCESS_AUTHORITY_CLASS =
916c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        "com.android.settings.bluetooth.BluetoothPermissionRequest";
926c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie    private static final String BLUETOOTH_ADMIN_PERM = android.Manifest.permission.BLUETOOTH_ADMIN;
936c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
946c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie    private final HashMap<String, PhonebookResult> mPhonebooks =
956c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie            new HashMap<String, PhonebookResult>(4);
966c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
97405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T    final int TYPE_UNKNOWN = -1;
98405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T    final int TYPE_READ = 0;
99405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T    final int TYPE_SET = 1;
100405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T    final int TYPE_TEST = 2;
101405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T
102405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T    public AtPhonebook(Context context, HeadsetStateMachine headsetState) {
1036c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        mContext = context;
10474ae04c73312403e89db0f8e9bd9601d403b4783fredc        mContentResolver = context.getContentResolver();
105405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T        mStateMachine = headsetState;
1066c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        mPhonebooks.put("DC", new PhonebookResult());  // dialled calls
1076c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        mPhonebooks.put("RC", new PhonebookResult());  // received calls
1086c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        mPhonebooks.put("MC", new PhonebookResult());  // missed calls
1096c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        mPhonebooks.put("ME", new PhonebookResult());  // mobile phonebook
1106c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
1116c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        mCurrentPhonebook = "ME";  // default to mobile phonebook
1126c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
1136c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        mCpbrIndex1 = mCpbrIndex2 = -1;
1146c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        mCheckingAccessPermission = false;
1156c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie    }
1166c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
11774ae04c73312403e89db0f8e9bd9601d403b4783fredc    public void cleanup() {
11874ae04c73312403e89db0f8e9bd9601d403b4783fredc        mPhonebooks.clear();
11974ae04c73312403e89db0f8e9bd9601d403b4783fredc    }
12074ae04c73312403e89db0f8e9bd9601d403b4783fredc
1216c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie    /** Returns the last dialled number, or null if no numbers have been called */
1226c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie    public String getLastDialledNumber() {
1236c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        String[] projection = {Calls.NUMBER};
12474ae04c73312403e89db0f8e9bd9601d403b4783fredc        Cursor cursor = mContentResolver.query(Calls.CONTENT_URI, projection,
1256c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie                Calls.TYPE + "=" + Calls.OUTGOING_TYPE, null, Calls.DEFAULT_SORT_ORDER +
1266c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie                " LIMIT 1");
1276c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        if (cursor == null) return null;
1286c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
1296c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        if (cursor.getCount() < 1) {
1306c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie            cursor.close();
1316c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie            return null;
1326c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        }
1336c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        cursor.moveToNext();
1346c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        int column = cursor.getColumnIndexOrThrow(Calls.NUMBER);
1356c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        String number = cursor.getString(column);
1366c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        cursor.close();
1376c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        return number;
1386c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie    }
1396c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
140405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T    public boolean getCheckingAccessPermission() {
141405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T        return mCheckingAccessPermission;
142405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T    }
143405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T
144fc9bed1b79edf77082f5baa21aa68d791a102ea4Edward Jee    public void setCheckingAccessPermission(boolean checkingAccessPermission) {
145fc9bed1b79edf77082f5baa21aa68d791a102ea4Edward Jee        mCheckingAccessPermission = checkingAccessPermission;
146405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T    }
147405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T
148405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T    public void setCpbrIndex(int cpbrIndex) {
149405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T        mCpbrIndex1 = mCpbrIndex2 = cpbrIndex;
150405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T    }
151405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T
152343b96e3995da4038b614384dcdad8a6494b4bc4Nitin Srivastava    private byte[] getByteAddress(BluetoothDevice device) {
153343b96e3995da4038b614384dcdad8a6494b4bc4Nitin Srivastava        return Utils.getBytesFromAddress(device.getAddress());
154343b96e3995da4038b614384dcdad8a6494b4bc4Nitin Srivastava    }
155343b96e3995da4038b614384dcdad8a6494b4bc4Nitin Srivastava
156343b96e3995da4038b614384dcdad8a6494b4bc4Nitin Srivastava    public void handleCscsCommand(String atString, int type, BluetoothDevice device)
157405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T    {
158405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T        log("handleCscsCommand - atString = " +atString);
159405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T        // Select Character Set
160405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T        int atCommandResult = HeadsetHalConstants.AT_RESPONSE_ERROR;
161405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T        int atCommandErrorCode = -1;
162405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T        String atCommandResponse = null;
163405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T        switch (type) {
164405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T            case TYPE_READ: // Read
165405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                log("handleCscsCommand - Read Command");
166405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                atCommandResponse = "+CSCS: \"" + mCharacterSet + "\"";
167405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                atCommandResult = HeadsetHalConstants.AT_RESPONSE_OK;
168405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                break;
169405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T            case TYPE_TEST: // Test
170405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                log("handleCscsCommand - Test Command");
171405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                atCommandResponse = ( "+CSCS: (\"UTF-8\",\"IRA\",\"GSM\")");
172405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                atCommandResult = HeadsetHalConstants.AT_RESPONSE_OK;
173405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                break;
174405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T            case TYPE_SET: // Set
175405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                log("handleCscsCommand - Set Command");
176405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                String[] args = atString.split("=");
177405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                if (args.length < 2 || !(args[1] instanceof String)) {
178343b96e3995da4038b614384dcdad8a6494b4bc4Nitin Srivastava                    mStateMachine.atResponseCodeNative(atCommandResult,
179343b96e3995da4038b614384dcdad8a6494b4bc4Nitin Srivastava                           atCommandErrorCode, getByteAddress(device));
180405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                    break;
181405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                }
182405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                String characterSet = ((atString.split("="))[1]);
183405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                characterSet = characterSet.replace("\"", "");
184405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                if (characterSet.equals("GSM") || characterSet.equals("IRA") ||
185405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                    characterSet.equals("UTF-8") || characterSet.equals("UTF8")) {
186405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                    mCharacterSet = characterSet;
187405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                    atCommandResult = HeadsetHalConstants.AT_RESPONSE_OK;
188405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                } else {
189405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                    atCommandErrorCode = BluetoothCmeError.OPERATION_NOT_SUPPORTED;
190405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                }
191405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                break;
192405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T            case TYPE_UNKNOWN:
193405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T            default:
194405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                log("handleCscsCommand - Invalid chars");
195405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                atCommandErrorCode = BluetoothCmeError.TEXT_HAS_INVALID_CHARS;
1966c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        }
197405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T        if (atCommandResponse != null)
198343b96e3995da4038b614384dcdad8a6494b4bc4Nitin Srivastava            mStateMachine.atResponseStringNative(atCommandResponse, getByteAddress(device));
199343b96e3995da4038b614384dcdad8a6494b4bc4Nitin Srivastava        mStateMachine.atResponseCodeNative(atCommandResult, atCommandErrorCode,
200343b96e3995da4038b614384dcdad8a6494b4bc4Nitin Srivastava                                         getByteAddress(device));
201405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T    }
2026c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
203343b96e3995da4038b614384dcdad8a6494b4bc4Nitin Srivastava    public void handleCpbsCommand(String atString, int type, BluetoothDevice device) {
204405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T        // Select PhoneBook memory Storage
205405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T        log("handleCpbsCommand - atString = " +atString);
206405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T        int atCommandResult = HeadsetHalConstants.AT_RESPONSE_ERROR;
207405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T        int atCommandErrorCode = -1;
208405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T        String atCommandResponse = null;
209405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T        switch (type) {
210405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T            case TYPE_READ: // Read
211405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                log("handleCpbsCommand - read command");
212405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                // Return current size and max size
213405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                if ("SM".equals(mCurrentPhonebook)) {
214405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                    atCommandResponse = "+CPBS: \"SM\",0," + getMaxPhoneBookSize(0);
215405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                    atCommandResult = HeadsetHalConstants.AT_RESPONSE_OK;
216405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                    break;
217405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                }
218405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                PhonebookResult pbr = getPhonebookResult(mCurrentPhonebook, true);
219405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                if (pbr == null) {
220405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                    atCommandErrorCode = BluetoothCmeError.OPERATION_NOT_SUPPORTED;
221405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                    break;
2226c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie                }
223405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                int size = pbr.cursor.getCount();
224405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                atCommandResponse = "+CPBS: \"" + mCurrentPhonebook + "\"," + size + "," + getMaxPhoneBookSize(size);
22515d36984a79d6e35c659edb0efdf929f0b526bd5Fred                pbr.cursor.close();
22615d36984a79d6e35c659edb0efdf929f0b526bd5Fred                pbr.cursor = null;
227405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                atCommandResult = HeadsetHalConstants.AT_RESPONSE_OK;
228405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                break;
229405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T            case TYPE_TEST: // Test
230405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                log("handleCpbsCommand - test command");
231405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                atCommandResponse = ("+CPBS: (\"ME\",\"SM\",\"DC\",\"RC\",\"MC\")");
232405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                atCommandResult = HeadsetHalConstants.AT_RESPONSE_OK;
233405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                break;
234405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T            case TYPE_SET: // Set
235405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                log("handleCpbsCommand - set command");
236405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                String[] args = atString.split("=");
237405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                // Select phonebook memory
238405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                if (args.length < 2 || !(args[1] instanceof String)) {
239d1e5ee9cd1c68ad8eeca61700fe56638d7f3edd4Nigel Hannam                    atCommandErrorCode = BluetoothCmeError.OPERATION_NOT_SUPPORTED;
240405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                    break;
241405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                }
242405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                String pb = ((String)args[1]).trim();
243405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                while (pb.endsWith("\"")) pb = pb.substring(0, pb.length() - 1);
244405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                while (pb.startsWith("\"")) pb = pb.substring(1, pb.length());
245405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                if (getPhonebookResult(pb, false) == null && !"SM".equals(pb)) {
246405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                   if (DBG) log("Dont know phonebook: '" + pb + "'");
247405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                   atCommandErrorCode = BluetoothCmeError.OPERATION_NOT_ALLOWED;
248405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                   break;
249405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                }
250405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                mCurrentPhonebook = pb;
251405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                atCommandResult = HeadsetHalConstants.AT_RESPONSE_OK;
252405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                break;
253405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T            case TYPE_UNKNOWN:
254405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T            default:
255405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                log("handleCpbsCommand - invalid chars");
256405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                atCommandErrorCode = BluetoothCmeError.TEXT_HAS_INVALID_CHARS;
257405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T        }
258405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T        if (atCommandResponse != null)
259343b96e3995da4038b614384dcdad8a6494b4bc4Nitin Srivastava            mStateMachine.atResponseStringNative(atCommandResponse, getByteAddress(device));
260343b96e3995da4038b614384dcdad8a6494b4bc4Nitin Srivastava        mStateMachine.atResponseCodeNative(atCommandResult, atCommandErrorCode,
261343b96e3995da4038b614384dcdad8a6494b4bc4Nitin Srivastava                                             getByteAddress(device));
262405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T    }
2636c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
264405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T    public void handleCpbrCommand(String atString, int type, BluetoothDevice remoteDevice) {
265405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T        log("handleCpbrCommand - atString = " +atString);
266405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T        int atCommandResult = HeadsetHalConstants.AT_RESPONSE_ERROR;
267405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T        int atCommandErrorCode = -1;
268405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T        String atCommandResponse = null;
269405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T        switch (type) {
270405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T            case TYPE_TEST: // Test
271405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                /* Ideally we should return the maximum range of valid index's
272405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                 * for the selected phone book, but this causes problems for the
273405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                 * Parrot CK3300. So instead send just the range of currently
274405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                 * valid index's.
275405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                 */
276405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                log("handleCpbrCommand - test command");
277405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                int size;
278405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                if ("SM".equals(mCurrentPhonebook)) {
279405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                    size = 0;
280405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                } else {
281405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                    PhonebookResult pbr = getPhonebookResult(mCurrentPhonebook, true); //false);
282405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                    if (pbr == null) {
283405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                        atCommandErrorCode = BluetoothCmeError.OPERATION_NOT_ALLOWED;
284343b96e3995da4038b614384dcdad8a6494b4bc4Nitin Srivastava                        mStateMachine.atResponseCodeNative(atCommandResult,
285343b96e3995da4038b614384dcdad8a6494b4bc4Nitin Srivastava                           atCommandErrorCode, getByteAddress(remoteDevice));
286405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                        break;
287405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                    }
288405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                    size = pbr.cursor.getCount();
289405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                    log("handleCpbrCommand - size = "+size);
29015d36984a79d6e35c659edb0efdf929f0b526bd5Fred                    pbr.cursor.close();
29115d36984a79d6e35c659edb0efdf929f0b526bd5Fred                    pbr.cursor = null;
292405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                }
293405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                if (size == 0) {
294405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                    /* Sending "+CPBR: (1-0)" can confused some carkits, send "1-1" * instead */
295405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                    size = 1;
296405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                }
297405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                atCommandResponse = "+CPBR: (1-" + size + "),30,30";
298405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                atCommandResult = HeadsetHalConstants.AT_RESPONSE_OK;
299405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                if (atCommandResponse != null)
300343b96e3995da4038b614384dcdad8a6494b4bc4Nitin Srivastava                    mStateMachine.atResponseStringNative(atCommandResponse,
301343b96e3995da4038b614384dcdad8a6494b4bc4Nitin Srivastava                                         getByteAddress(remoteDevice));
302343b96e3995da4038b614384dcdad8a6494b4bc4Nitin Srivastava                mStateMachine.atResponseCodeNative(atCommandResult, atCommandErrorCode,
303343b96e3995da4038b614384dcdad8a6494b4bc4Nitin Srivastava                                         getByteAddress(remoteDevice));
304405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                break;
305405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T            // Read PhoneBook Entries
306405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T            case TYPE_READ:
307405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T            case TYPE_SET: // Set & read
308405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                // Phone Book Read Request
309405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                // AT+CPBR=<index1>[,<index2>]
310405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                log("handleCpbrCommand - set/read command");
311405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                if (mCpbrIndex1 != -1) {
312405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                   /* handling a CPBR at the moment, reject this CPBR command */
313405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                   atCommandErrorCode = BluetoothCmeError.OPERATION_NOT_ALLOWED;
314343b96e3995da4038b614384dcdad8a6494b4bc4Nitin Srivastava                   mStateMachine.atResponseCodeNative(atCommandResult, atCommandErrorCode,
315343b96e3995da4038b614384dcdad8a6494b4bc4Nitin Srivastava                                         getByteAddress(remoteDevice));
316405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                   break;
317405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                }
318405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                // Parse indexes
319405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                int index1;
320405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                int index2;
321405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                if ((atString.split("=")).length < 2) {
322343b96e3995da4038b614384dcdad8a6494b4bc4Nitin Srivastava                    mStateMachine.atResponseCodeNative(atCommandResult, atCommandErrorCode,
323343b96e3995da4038b614384dcdad8a6494b4bc4Nitin Srivastava                                         getByteAddress(remoteDevice));
324405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                    break;
325405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                }
326405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                String atCommand = (atString.split("="))[1];
327405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                String[] indices = atCommand.split(",");
328405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                for(int i = 0; i < indices.length; i++)
329be38be94c0a2faf3802b596be5b3ab568d6d85a4zzy                    //replace AT command separator ';' from the index if any
330be38be94c0a2faf3802b596be5b3ab568d6d85a4zzy                    indices[i] = indices[i].replace(';', ' ').trim();
331405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                try {
332405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                    index1 = Integer.parseInt(indices[0]);
333405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                    if (indices.length == 1)
334405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                        index2 = index1;
335405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                    else
336405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                        index2 = Integer.parseInt(indices[1]);
337405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                }
338405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                catch (Exception e) {
339be38be94c0a2faf3802b596be5b3ab568d6d85a4zzy                    log("handleCpbrCommand - exception - invalid chars: " + e.toString());
340405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                    atCommandErrorCode = BluetoothCmeError.TEXT_HAS_INVALID_CHARS;
341343b96e3995da4038b614384dcdad8a6494b4bc4Nitin Srivastava                    mStateMachine.atResponseCodeNative(atCommandResult, atCommandErrorCode,
342343b96e3995da4038b614384dcdad8a6494b4bc4Nitin Srivastava                                         getByteAddress(remoteDevice));
343405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                    break;
344405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                }
345405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                mCpbrIndex1 = index1;
346405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                mCpbrIndex2 = index2;
347405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                mCheckingAccessPermission = true;
348405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T
349fc9bed1b79edf77082f5baa21aa68d791a102ea4Edward Jee                int permission = checkAccessPermission(remoteDevice);
350fc9bed1b79edf77082f5baa21aa68d791a102ea4Edward Jee                if (permission == BluetoothDevice.ACCESS_ALLOWED) {
351405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                    mCheckingAccessPermission = false;
352343b96e3995da4038b614384dcdad8a6494b4bc4Nitin Srivastava                    atCommandResult = processCpbrCommand(remoteDevice);
353405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                    mCpbrIndex1 = mCpbrIndex2 = -1;
354343b96e3995da4038b614384dcdad8a6494b4bc4Nitin Srivastava                    mStateMachine.atResponseCodeNative(atCommandResult, atCommandErrorCode,
355343b96e3995da4038b614384dcdad8a6494b4bc4Nitin Srivastava                                         getByteAddress(remoteDevice));
356405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                    break;
357fc9bed1b79edf77082f5baa21aa68d791a102ea4Edward Jee                } else if (permission == BluetoothDevice.ACCESS_REJECTED) {
358fc9bed1b79edf77082f5baa21aa68d791a102ea4Edward Jee                    mCheckingAccessPermission = false;
359fc9bed1b79edf77082f5baa21aa68d791a102ea4Edward Jee                    mCpbrIndex1 = mCpbrIndex2 = -1;
360fc9bed1b79edf77082f5baa21aa68d791a102ea4Edward Jee                    mStateMachine.atResponseCodeNative(HeadsetHalConstants.AT_RESPONSE_ERROR,
361fc9bed1b79edf77082f5baa21aa68d791a102ea4Edward Jee                            BluetoothCmeError.AG_FAILURE, getByteAddress(remoteDevice));
362405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                }
363fc9bed1b79edf77082f5baa21aa68d791a102ea4Edward Jee                // If checkAccessPermission(remoteDevice) has returned
364fc9bed1b79edf77082f5baa21aa68d791a102ea4Edward Jee                // BluetoothDevice.ACCESS_UNKNOWN, we will continue the process in
365fc9bed1b79edf77082f5baa21aa68d791a102ea4Edward Jee                // HeadsetStateMachine.handleAccessPermissionResult(Intent) once HeadsetService
366fc9bed1b79edf77082f5baa21aa68d791a102ea4Edward Jee                // receives BluetoothDevice.ACTION_CONNECTION_ACCESS_REPLY from Settings app.
367405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                break;
368fc9bed1b79edf77082f5baa21aa68d791a102ea4Edward Jee            case TYPE_UNKNOWN:
369fc9bed1b79edf77082f5baa21aa68d791a102ea4Edward Jee            default:
370fc9bed1b79edf77082f5baa21aa68d791a102ea4Edward Jee                log("handleCpbrCommand - invalid chars");
371fc9bed1b79edf77082f5baa21aa68d791a102ea4Edward Jee                atCommandErrorCode = BluetoothCmeError.TEXT_HAS_INVALID_CHARS;
372fc9bed1b79edf77082f5baa21aa68d791a102ea4Edward Jee                mStateMachine.atResponseCodeNative(atCommandResult, atCommandErrorCode,
373fc9bed1b79edf77082f5baa21aa68d791a102ea4Edward Jee                        getByteAddress(remoteDevice));
3746c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        }
3756c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie    }
3766c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
3776c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie    /** Get the most recent result for the given phone book,
3786c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie     *  with the cursor ready to go.
3796c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie     *  If force then re-query that phonebook
3806c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie     *  Returns null if the cursor is not ready
3816c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie     */
3826c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie    private synchronized PhonebookResult getPhonebookResult(String pb, boolean force) {
3836c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        if (pb == null) {
3846c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie            return null;
3856c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        }
3866c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        PhonebookResult pbr = mPhonebooks.get(pb);
3876c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        if (pbr == null) {
3886c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie            pbr = new PhonebookResult();
3896c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        }
3906c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        if (force || pbr.cursor == null) {
3916c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie            if (!queryPhonebook(pb, pbr)) {
3926c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie                return null;
3936c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie            }
3946c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        }
3956c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
3966c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        return pbr;
3976c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie    }
3986c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
3996c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie    private synchronized boolean queryPhonebook(String pb, PhonebookResult pbr) {
4006c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        String where;
4016c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        boolean ancillaryPhonebook = true;
4026c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
4036c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        if (pb.equals("ME")) {
4046c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie            ancillaryPhonebook = false;
4056c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie            where = VISIBLE_PHONEBOOK_WHERE;
4066c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        } else if (pb.equals("DC")) {
4076c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie            where = OUTGOING_CALL_WHERE;
4086c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        } else if (pb.equals("RC")) {
4096c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie            where = INCOMING_CALL_WHERE;
4106c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        } else if (pb.equals("MC")) {
4116c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie            where = MISSED_CALL_WHERE;
4126c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        } else {
4136c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie            return false;
4146c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        }
4156c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
4166c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        if (pbr.cursor != null) {
4176c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie            pbr.cursor.close();
4186c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie            pbr.cursor = null;
4196c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        }
4206c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
4216c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        if (ancillaryPhonebook) {
42274ae04c73312403e89db0f8e9bd9601d403b4783fredc            pbr.cursor = mContentResolver.query(
4236c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie                    Calls.CONTENT_URI, CALLS_PROJECTION, where, null,
4246c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie                    Calls.DEFAULT_SORT_ORDER + " LIMIT " + MAX_PHONEBOOK_SIZE);
4256c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie            if (pbr.cursor == null) return false;
4266c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
4276c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie            pbr.numberColumn = pbr.cursor.getColumnIndexOrThrow(Calls.NUMBER);
4289674eb043aeb1474aa23ddd0739e3b8f05432630Jay Shrauner            pbr.numberPresentationColumn =
4299674eb043aeb1474aa23ddd0739e3b8f05432630Jay Shrauner                    pbr.cursor.getColumnIndexOrThrow(Calls.NUMBER_PRESENTATION);
4306c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie            pbr.typeColumn = -1;
4316c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie            pbr.nameColumn = -1;
4326c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        } else {
43374ae04c73312403e89db0f8e9bd9601d403b4783fredc            pbr.cursor = mContentResolver.query(Phone.CONTENT_URI, PHONES_PROJECTION,
4346c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie                    where, null, Phone.NUMBER + " LIMIT " + MAX_PHONEBOOK_SIZE);
4356c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie            if (pbr.cursor == null) return false;
4366c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
4376c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie            pbr.numberColumn = pbr.cursor.getColumnIndex(Phone.NUMBER);
4389674eb043aeb1474aa23ddd0739e3b8f05432630Jay Shrauner            pbr.numberPresentationColumn = -1;
4396c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie            pbr.typeColumn = pbr.cursor.getColumnIndex(Phone.TYPE);
4406c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie            pbr.nameColumn = pbr.cursor.getColumnIndex(Phone.DISPLAY_NAME);
4416c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        }
4426c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        Log.i(TAG, "Refreshed phonebook " + pb + " with " + pbr.cursor.getCount() + " results");
4436c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        return true;
4446c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie    }
4456c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
4466c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie    synchronized void resetAtState() {
4476c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        mCharacterSet = "UTF-8";
4486c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        mCpbrIndex1 = mCpbrIndex2 = -1;
4496c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        mCheckingAccessPermission = false;
4506c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie    }
4516c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
4526c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie    private synchronized int getMaxPhoneBookSize(int currSize) {
4536c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        // some car kits ignore the current size and request max phone book
4546c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        // size entries. Thus, it takes a long time to transfer all the
4556c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        // entries. Use a heuristic to calculate the max phone book size
4566c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        // considering future expansion.
4576c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        // maxSize = currSize + currSize / 2 rounded up to nearest power of 2
4586c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        // If currSize < 100, use 100 as the currSize
4596c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
4606c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        int maxSize = (currSize < 100) ? 100 : currSize;
4616c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        maxSize += maxSize / 2;
4626c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        return roundUpToPowerOfTwo(maxSize);
4636c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie    }
4646c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
4656c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie    private int roundUpToPowerOfTwo(int x) {
4666c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        x |= x >> 1;
4676c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        x |= x >> 2;
4686c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        x |= x >> 4;
4696c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        x |= x >> 8;
4706c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        x |= x >> 16;
4716c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        return x + 1;
4726c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie    }
4736c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
4746c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie    // process CPBR command after permission check
475343b96e3995da4038b614384dcdad8a6494b4bc4Nitin Srivastava    /*package*/ int processCpbrCommand(BluetoothDevice device)
4766c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie    {
477405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T        log("processCpbrCommand");
478405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T        int atCommandResult = HeadsetHalConstants.AT_RESPONSE_ERROR;
479405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T        int atCommandErrorCode = -1;
480405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T        String atCommandResponse = null;
481405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T        StringBuilder response = new StringBuilder();
482405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T        String record;
483405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T
4846c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        // Shortcut SM phonebook
4856c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        if ("SM".equals(mCurrentPhonebook)) {
486405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T            atCommandResult = HeadsetHalConstants.AT_RESPONSE_OK;
487405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T            return atCommandResult;
4886c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        }
4896c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
4906c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        // Check phonebook
491405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T        PhonebookResult pbr = getPhonebookResult(mCurrentPhonebook, true); //false);
4926c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        if (pbr == null) {
493405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T            atCommandErrorCode = BluetoothCmeError.OPERATION_NOT_ALLOWED;
494405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T            return atCommandResult;
4956c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        }
4966c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
4976c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        // More sanity checks
4986c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        // Send OK instead of ERROR if these checks fail.
4996c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        // When we send error, certain kits like BMW disconnect the
5006c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        // Handsfree connection.
5016c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        if (pbr.cursor.getCount() == 0 || mCpbrIndex1 <= 0 || mCpbrIndex2 < mCpbrIndex1  ||
5026c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie            mCpbrIndex2 > pbr.cursor.getCount() || mCpbrIndex1 > pbr.cursor.getCount()) {
503405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T            atCommandResult = HeadsetHalConstants.AT_RESPONSE_OK;
504405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T            return atCommandResult;
5056c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        }
5066c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
5076c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        // Process
508405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T        atCommandResult = HeadsetHalConstants.AT_RESPONSE_OK;
5096c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        int errorDetected = -1; // no error
5106c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        pbr.cursor.moveToPosition(mCpbrIndex1 - 1);
511405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T        log("mCpbrIndex1 = "+mCpbrIndex1+ " and mCpbrIndex2 = "+mCpbrIndex2);
5126c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        for (int index = mCpbrIndex1; index <= mCpbrIndex2; index++) {
5136c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie            String number = pbr.cursor.getString(pbr.numberColumn);
5146c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie            String name = null;
5156c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie            int type = -1;
51609b09c15dcd853d452b24d46a3c81ca63fa090eaMatthew Xie            if (pbr.nameColumn == -1 && number != null && number.length() > 0) {
5176c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie                // try caller id lookup
5186c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie                // TODO: This code is horribly inefficient. I saw it
5196c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie                // take 7 seconds to process 100 missed calls.
52074ae04c73312403e89db0f8e9bd9601d403b4783fredc                Cursor c = mContentResolver.
5216c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie                    query(Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, number),
5226c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie                          new String[] {PhoneLookup.DISPLAY_NAME, PhoneLookup.TYPE},
5236c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie                          null, null, null);
5246c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie                if (c != null) {
5256c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie                    if (c.moveToFirst()) {
5266c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie                        name = c.getString(0);
5276c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie                        type = c.getInt(1);
5286c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie                    }
5296c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie                    c.close();
5306c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie                }
5316c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie                if (DBG && name == null) log("Caller ID lookup failed for " + number);
5326c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
533abf19e783556a93cfdd33468454a309ed347bfc4Zhihai Xu            } else if (pbr.nameColumn != -1) {
5346c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie                name = pbr.cursor.getString(pbr.nameColumn);
535abf19e783556a93cfdd33468454a309ed347bfc4Zhihai Xu            } else {
536abf19e783556a93cfdd33468454a309ed347bfc4Zhihai Xu                log("processCpbrCommand: empty name and number");
5376c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie            }
5386c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie            if (name == null) name = "";
5396c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie            name = name.trim();
5406c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie            if (name.length() > 28) name = name.substring(0, 28);
5416c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
5426c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie            if (pbr.typeColumn != -1) {
5436c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie                type = pbr.cursor.getInt(pbr.typeColumn);
5446c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie                name = name + "/" + getPhoneType(type);
5456c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie            }
5466c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
5476c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie            if (number == null) number = "";
5486c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie            int regionType = PhoneNumberUtils.toaFromString(number);
5496c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
5506c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie            number = number.trim();
5516c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie            number = PhoneNumberUtils.stripSeparators(number);
5526c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie            if (number.length() > 30) number = number.substring(0, 30);
5539674eb043aeb1474aa23ddd0739e3b8f05432630Jay Shrauner            int numberPresentation = Calls.PRESENTATION_ALLOWED;
5549674eb043aeb1474aa23ddd0739e3b8f05432630Jay Shrauner            if (pbr.numberPresentationColumn != -1) {
5559674eb043aeb1474aa23ddd0739e3b8f05432630Jay Shrauner                numberPresentation = pbr.cursor.getInt(pbr.numberPresentationColumn);
5569674eb043aeb1474aa23ddd0739e3b8f05432630Jay Shrauner            }
5579674eb043aeb1474aa23ddd0739e3b8f05432630Jay Shrauner            if (numberPresentation != Calls.PRESENTATION_ALLOWED) {
5586c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie                number = "";
5599674eb043aeb1474aa23ddd0739e3b8f05432630Jay Shrauner                // TODO: there are 3 types of numbers should have resource
5609674eb043aeb1474aa23ddd0739e3b8f05432630Jay Shrauner                // strings for: unknown, private, and payphone
561405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                name = mContext.getString(R.string.unknownNumber);
5626c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie            }
5636c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
5646c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie            // TODO(): Handle IRA commands. It's basically
5656c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie            // a 7 bit ASCII character set.
5666c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie            if (!name.equals("") && mCharacterSet.equals("GSM")) {
5676c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie                byte[] nameByte = GsmAlphabet.stringToGsm8BitPacked(name);
5686c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie                if (nameByte == null) {
569405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T                    name = mContext.getString(R.string.unknownNumber);
5706c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie                } else {
5716c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie                    name = new String(nameByte);
5726c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie                }
5736c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie            }
5746c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
575405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T            record = "+CPBR: " + index + ",\"" + number + "\"," + regionType + ",\"" + name + "\"";
576405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T            record = record + "\r\n\r\n";
577405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T            atCommandResponse = record;
578405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T            log("processCpbrCommand - atCommandResponse = "+atCommandResponse);
579343b96e3995da4038b614384dcdad8a6494b4bc4Nitin Srivastava            mStateMachine.atResponseStringNative(atCommandResponse, getByteAddress(device));
5806c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie            if (!pbr.cursor.moveToNext()) {
5816c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie                break;
5826c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie            }
5836c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        }
58415d36984a79d6e35c659edb0efdf929f0b526bd5Fred        if(pbr != null && pbr.cursor != null) {
58515d36984a79d6e35c659edb0efdf929f0b526bd5Fred            pbr.cursor.close();
58615d36984a79d6e35c659edb0efdf929f0b526bd5Fred            pbr.cursor = null;
58715d36984a79d6e35c659edb0efdf929f0b526bd5Fred        }
588405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T        return atCommandResult;
589405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T    }
590405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T
591fc9bed1b79edf77082f5baa21aa68d791a102ea4Edward Jee    /**
592fc9bed1b79edf77082f5baa21aa68d791a102ea4Edward Jee     * Checks if the remote device has premission to read our phone book.
593fc9bed1b79edf77082f5baa21aa68d791a102ea4Edward Jee     * If the return value is {@link BluetoothDevice#ACCESS_UNKNOWN}, it means this method has sent
594fc9bed1b79edf77082f5baa21aa68d791a102ea4Edward Jee     * an Intent to Settings application to ask user preference.
595fc9bed1b79edf77082f5baa21aa68d791a102ea4Edward Jee     *
596fc9bed1b79edf77082f5baa21aa68d791a102ea4Edward Jee     * @return {@link BluetoothDevice#ACCESS_UNKNOWN}, {@link BluetoothDevice#ACCESS_ALLOWED} or
597fc9bed1b79edf77082f5baa21aa68d791a102ea4Edward Jee     *         {@link BluetoothDevice#ACCESS_REJECTED}.
598fc9bed1b79edf77082f5baa21aa68d791a102ea4Edward Jee     */
599fc9bed1b79edf77082f5baa21aa68d791a102ea4Edward Jee    private int checkAccessPermission(BluetoothDevice remoteDevice) {
600405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T        log("checkAccessPermission");
601fc9bed1b79edf77082f5baa21aa68d791a102ea4Edward Jee        int permission = remoteDevice.getPhonebookAccessPermission();
602fc9bed1b79edf77082f5baa21aa68d791a102ea4Edward Jee
603fc9bed1b79edf77082f5baa21aa68d791a102ea4Edward Jee        if (permission == BluetoothDevice.ACCESS_UNKNOWN) {
604fc9bed1b79edf77082f5baa21aa68d791a102ea4Edward Jee            log("checkAccessPermission - ACTION_CONNECTION_ACCESS_REQUEST");
605fc9bed1b79edf77082f5baa21aa68d791a102ea4Edward Jee            Intent intent = new Intent(BluetoothDevice.ACTION_CONNECTION_ACCESS_REQUEST);
606fc9bed1b79edf77082f5baa21aa68d791a102ea4Edward Jee            intent.setClassName(ACCESS_AUTHORITY_PACKAGE, ACCESS_AUTHORITY_CLASS);
607fc9bed1b79edf77082f5baa21aa68d791a102ea4Edward Jee            intent.putExtra(BluetoothDevice.EXTRA_ACCESS_REQUEST_TYPE,
608fc9bed1b79edf77082f5baa21aa68d791a102ea4Edward Jee            BluetoothDevice.REQUEST_TYPE_PHONEBOOK_ACCESS);
609fc9bed1b79edf77082f5baa21aa68d791a102ea4Edward Jee            intent.putExtra(BluetoothDevice.EXTRA_DEVICE, remoteDevice);
610fc9bed1b79edf77082f5baa21aa68d791a102ea4Edward Jee            // Leave EXTRA_PACKAGE_NAME and EXTRA_CLASS_NAME field empty.
611fc9bed1b79edf77082f5baa21aa68d791a102ea4Edward Jee            // BluetoothHandsfree's broadcast receiver is anonymous, cannot be targeted.
612fc9bed1b79edf77082f5baa21aa68d791a102ea4Edward Jee            mContext.sendOrderedBroadcast(intent, BLUETOOTH_ADMIN_PERM);
613405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T        }
614405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T
615fc9bed1b79edf77082f5baa21aa68d791a102ea4Edward Jee        return permission;
6166c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie    }
6176c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
6186c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie    private static String getPhoneType(int type) {
6196c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        switch (type) {
6206c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie            case Phone.TYPE_HOME:
6216c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie                return "H";
6226c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie            case Phone.TYPE_MOBILE:
6236c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie                return "M";
6246c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie            case Phone.TYPE_WORK:
6256c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie                return "W";
6266c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie            case Phone.TYPE_FAX_HOME:
6276c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie            case Phone.TYPE_FAX_WORK:
6286c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie                return "F";
6296c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie            case Phone.TYPE_OTHER:
6306c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie            case Phone.TYPE_CUSTOM:
6316c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie            default:
6326c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie                return "O";
6336c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        }
6346c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie    }
6356c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie
6366c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie    private static void log(String msg) {
6376c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie        Log.d(TAG, msg);
6386c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie    }
6396c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie}
640