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