BluetoothService.java revision a224f70b1efc29d9698da5b5c143251a43838f2b
19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/* 29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2008 The Android Open Source Project 39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); 59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License. 69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at 79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software 119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, 129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and 149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License. 159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/** 189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * TODO: Move this to 19bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly * java/services/com/android/server/BluetoothService.java 209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * and make the contructor package private again. 219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @hide 239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpackage android.server; 269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 27bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pellyimport android.bluetooth.BluetoothAdapter; 28dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganeshimport android.bluetooth.BluetoothClass; 299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.bluetooth.BluetoothDevice; 309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.bluetooth.BluetoothHeadset; 31f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganeshimport android.bluetooth.BluetoothDeviceProfileState; 32f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganeshimport android.bluetooth.BluetoothProfileState; 3324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pellyimport android.bluetooth.BluetoothSocket; 3410eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganeshimport android.bluetooth.BluetoothUuid; 35bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pellyimport android.bluetooth.IBluetooth; 3616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pellyimport android.bluetooth.IBluetoothCallback; 379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.BroadcastReceiver; 389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.ContentResolver; 399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Context; 409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Intent; 419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.IntentFilter; 426e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganeshimport android.content.SharedPreferences; 439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Binder; 449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Handler; 453fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganeshimport android.os.IBinder; 469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Message; 473fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganeshimport android.os.ParcelUuid; 489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.RemoteException; 49105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Projectimport android.os.ServiceManager; 509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.SystemService; 519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.provider.Settings; 529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.Log; 53cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganeshimport android.util.Pair; 549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 55d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganeshimport com.android.internal.app.IBatteryStats; 56d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh 573fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganeshimport java.io.BufferedInputStream; 58c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganeshimport java.io.BufferedReader; 593fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganeshimport java.io.BufferedWriter; 60c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganeshimport java.io.DataInputStream; 61c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganeshimport java.io.File; 629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.FileDescriptor; 633fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganeshimport java.io.FileInputStream; 643fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganeshimport java.io.FileNotFoundException; 65c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganeshimport java.io.FileOutputStream; 663fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganeshimport java.io.FileWriter; 673fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganeshimport java.io.IOException; 68c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganeshimport java.io.InputStreamReader; 699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.PrintWriter; 709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.UnsupportedEncodingException; 719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.ArrayList; 729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.Arrays; 739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.HashMap; 7416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pellyimport java.util.Iterator; 759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.Map; 769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 77bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pellypublic class BluetoothService extends IBluetooth.Stub { 78bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly private static final String TAG = "BluetoothService"; 799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final boolean DBG = true; 809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mNativeData; 829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private BluetoothEventLoop mEventLoop; 839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private boolean mIsAirplaneSensitive; 8444303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey private boolean mIsAirplaneToggleable; 85105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project private int mBluetoothState; 86997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly private boolean mRestart = false; // need to call enable() after disable() 87bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly private boolean mIsDiscovering; 88997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly 89bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly private BluetoothAdapter mAdapter; // constant after init() 90997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly private final BondState mBondState = new BondState(); // local cache of bondings 91105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project private final IBatteryStats mBatteryStats; 929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private final Context mContext; 939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final String BLUETOOTH_ADMIN_PERM = android.Manifest.permission.BLUETOOTH_ADMIN; 959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final String BLUETOOTH_PERM = android.Manifest.permission.BLUETOOTH; 969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 973fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh private static final String DOCK_ADDRESS_PATH = "/sys/class/switch/dock/bt_addr"; 983fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh private static final String DOCK_PIN_PATH = "/sys/class/switch/dock/bt_pin"; 993fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh 1006e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh private static final String SHARED_PREFERENCE_DOCK_ADDRESS = "dock_bluetooth_address"; 1016e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh private static final String SHARED_PREFERENCES_NAME = "bluetooth_service_settings"; 1026e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh 103105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project private static final int MESSAGE_REGISTER_SDP_RECORDS = 1; 104105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project private static final int MESSAGE_FINISH_DISABLE = 2; 1051caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh private static final int MESSAGE_UUID_INTENT = 3; 10612835478ee687a493d1b5882e67b6725bd539c26Nick Pelly private static final int MESSAGE_DISCOVERABLE_TIMEOUT = 4; 107a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh private static final int MESSAGE_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY = 5; 108a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh 109a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh // The time (in millisecs) to delay the pairing attempt after the first 110a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh // auto pairing attempt fails. We use an exponential delay with 111a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh // INIT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY as the initial value and 112a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh // MAX_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY as the max value. 113a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh private static final long INIT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY = 3000; 114a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh private static final long MAX_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY = 12000; 1151caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh 1161caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh // The timeout used to sent the UUIDs Intent 1171caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh // This timeout should be greater than the page timeout 1181caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh private static final int UUID_INTENT_DELAY = 6000; 119105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project 12016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly /** Always retrieve RFCOMM channel for these SDP UUIDs */ 12116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly private static final ParcelUuid[] RFCOMM_UUIDS = { 12216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly BluetoothUuid.Handsfree, 12316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly BluetoothUuid.HSP, 12416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly BluetoothUuid.ObexObjectPush }; 12516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly 1269b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh // TODO(): Optimize all these string handling 127bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly private final Map<String, String> mAdapterProperties; 12816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly private final HashMap<String, Map<String, String>> mDeviceProperties; 129d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh 13016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly private final HashMap<String, Map<ParcelUuid, Integer>> mDeviceServiceChannelCache; 13116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly private final ArrayList<String> mUuidIntentTracker; 13216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly private final HashMap<RemoteService, IBluetoothCallback> mUuidCallbackTracker; 1331caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh 13424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly private final HashMap<Integer, Integer> mServiceRecordToPid; 13524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly 136f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh private final HashMap<String, BluetoothDeviceProfileState> mDeviceProfileState; 137f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh private final BluetoothProfileState mA2dpProfileState; 138f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh private final BluetoothProfileState mHfpProfileState; 1399b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh 1409b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh private BluetoothA2dpService mA2dpService; 141cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh private final HashMap<String, Pair<byte[], byte[]>> mDeviceOobData; 142cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh 1433fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh private static String mDockAddress; 1443fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh private String mDockPin; 1453fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh 14616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly private static class RemoteService { 14716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly public String address; 14816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly public ParcelUuid uuid; 14916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly public RemoteService(String address, ParcelUuid uuid) { 15016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly this.address = address; 15116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly this.uuid = uuid; 15216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } 15316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly @Override 15416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly public boolean equals(Object o) { 15516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly if (o instanceof RemoteService) { 15616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly RemoteService service = (RemoteService)o; 15716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly return address.equals(service.address) && uuid.equals(service.uuid); 15816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } 15916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly return false; 16016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } 1615f61416305c47c4db0b94c0cf500e9a9d11d4cdbKenny Root 1625f61416305c47c4db0b94c0cf500e9a9d11d4cdbKenny Root @Override 1635f61416305c47c4db0b94c0cf500e9a9d11d4cdbKenny Root public int hashCode() { 1645f61416305c47c4db0b94c0cf500e9a9d11d4cdbKenny Root int hash = 1; 1655f61416305c47c4db0b94c0cf500e9a9d11d4cdbKenny Root hash = hash * 31 + (address == null ? 0 : address.hashCode()); 1665f61416305c47c4db0b94c0cf500e9a9d11d4cdbKenny Root hash = hash * 31 + (uuid == null ? 0 : uuid.hashCode()); 1675f61416305c47c4db0b94c0cf500e9a9d11d4cdbKenny Root return hash; 1685f61416305c47c4db0b94c0cf500e9a9d11d4cdbKenny Root } 16916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } 17016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly 1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project static { 1729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project classInitNative(); 1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 175bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly public BluetoothService(Context context) { 1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mContext = context; 177105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project 178105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project // Need to do this in place of: 179105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project // mBatteryStats = BatteryStatsService.getService(); 180105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project // Since we can not import BatteryStatsService from here. This class really needs to be 181105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project // moved to java/services/com/android/server/ 182105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService("batteryinfo")); 1839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project initializeNativeDataNative(); 185ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project 186ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project if (isEnabledNative() == 1) { 187ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project Log.w(TAG, "Bluetooth daemons already running - runtime restart? "); 188ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project disableNative(); 1899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 190ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project 191de893f550301a60274e87aa8168225e7a7a42184Nick Pelly mBluetoothState = BluetoothAdapter.STATE_OFF; 1929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mIsDiscovering = false; 193bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly mAdapterProperties = new HashMap<String, String>(); 194bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly mDeviceProperties = new HashMap<String, Map<String,String>>(); 19510eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh 19610eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh mDeviceServiceChannelCache = new HashMap<String, Map<ParcelUuid, Integer>>(); 197cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh mDeviceOobData = new HashMap<String, Pair<byte[], byte[]>>(); 1981caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh mUuidIntentTracker = new ArrayList<String>(); 19916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly mUuidCallbackTracker = new HashMap<RemoteService, IBluetoothCallback>(); 20024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly mServiceRecordToPid = new HashMap<Integer, Integer>(); 201f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh mDeviceProfileState = new HashMap<String, BluetoothDeviceProfileState>(); 202f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh mA2dpProfileState = new BluetoothProfileState(mContext, BluetoothProfileState.A2DP); 203f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh mHfpProfileState = new BluetoothProfileState(mContext, BluetoothProfileState.HFP); 204f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh 205f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh mHfpProfileState.start(); 206f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh mA2dpProfileState.start(); 2073fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh 2083fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh IntentFilter filter = new IntentFilter(); 2096e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh registerForAirplaneMode(filter); 2106e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh 2113fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh filter.addAction(Intent.ACTION_DOCK_EVENT); 2126e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh mContext.registerReceiver(mReceiver, filter); 2133fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh } 2143fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh 2159b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh public static synchronized String readDockBluetoothAddress() { 2163fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh if (mDockAddress != null) return mDockAddress; 2173fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh 2183fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh BufferedInputStream file = null; 2193fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh String dockAddress; 2203fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh try { 2213fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh file = new BufferedInputStream(new FileInputStream(DOCK_ADDRESS_PATH)); 2223fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh byte[] address = new byte[17]; 2233fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh file.read(address); 2243fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh dockAddress = new String(address); 2253fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh dockAddress = dockAddress.toUpperCase(); 2263fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh if (BluetoothAdapter.checkBluetoothAddress(dockAddress)) { 2273fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh mDockAddress = dockAddress; 2283fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh return mDockAddress; 2293fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh } else { 2303fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh log("CheckBluetoothAddress failed for car dock address:" + dockAddress); 2313fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh } 2323fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh } catch (FileNotFoundException e) { 2333fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh log("FileNotFoundException while trying to read dock address"); 2343fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh } catch (IOException e) { 2353fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh log("IOException while trying to read dock address"); 2363fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh } finally { 2373fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh if (file != null) { 2383fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh try { 2393fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh file.close(); 2403fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh } catch (IOException e) { 2413fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh // Ignore 2423fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh } 2433fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh } 2443fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh } 2453fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh mDockAddress = null; 2463fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh return null; 2473fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh } 2483fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh 2493fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh private synchronized boolean writeDockPin() { 2503fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh BufferedWriter out = null; 2513fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh try { 2523fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh out = new BufferedWriter(new FileWriter(DOCK_PIN_PATH)); 2533fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh 2543fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh // Generate a random 4 digit pin between 0000 and 9999 2553fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh // This is not truly random but good enough for our purposes. 2563fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh int pin = (int) Math.floor(Math.random() * 10000); 2573fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh 2583fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh mDockPin = String.format("%04d", pin); 2593fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh out.write(mDockPin); 2603fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh return true; 2613fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh } catch (FileNotFoundException e) { 2623fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh log("FileNotFoundException while trying to write dock pairing pin"); 2633fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh } catch (IOException e) { 2643fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh log("IOException while while trying to write dock pairing pin"); 2653fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh } finally { 2663fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh if (out != null) { 2673fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh try { 2683fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh out.close(); 2693fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh } catch (IOException e) { 2703fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh // Ignore 2713fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh } 2723fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh } 2733fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh } 2743fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh mDockPin = null; 2753fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh return false; 2763fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh } 2773fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh 2783fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh /*package*/ synchronized String getDockPin() { 2793fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh return mDockPin; 280bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly } 281bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly 282bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly public synchronized void initAfterRegistration() { 283f242b7b931898856bcbcb7ec36cacf43098ba544Nick Pelly mAdapter = BluetoothAdapter.getDefaultAdapter(); 284bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly mEventLoop = new BluetoothEventLoop(mContext, mAdapter, this); 2859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 2889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project protected void finalize() throws Throwable { 2896e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh mContext.unregisterReceiver(mReceiver); 2909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 2919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project cleanupNativeDataNative(); 2929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } finally { 2939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project super.finalize(); 2949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean isEnabled() { 2989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 2998c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh return isEnabledInternal(); 3008c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh } 3018c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh 3028c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh private boolean isEnabledInternal() { 303de893f550301a60274e87aa8168225e7a7a42184Nick Pelly return mBluetoothState == BluetoothAdapter.STATE_ON; 3049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 306105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project public int getBluetoothState() { 307105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 308105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project return mBluetoothState; 309105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project } 310105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project 311105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project 3129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 3139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Bring down bluetooth and disable BT in settings. Returns true on success. 3149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 3159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean disable() { 3169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return disable(true); 3179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 3209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Bring down bluetooth. Returns true on success. 3219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 322e6ee3be1c254404dad842298f6f56c11cc6c7ac8Nick Pelly * @param saveSetting If true, persist the new setting 3239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 3249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public synchronized boolean disable(boolean saveSetting) { 325e6ee3be1c254404dad842298f6f56c11cc6c7ac8Nick Pelly mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH_ADMIN permission"); 3269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 327105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project switch (mBluetoothState) { 328de893f550301a60274e87aa8168225e7a7a42184Nick Pelly case BluetoothAdapter.STATE_OFF: 329105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project return true; 330de893f550301a60274e87aa8168225e7a7a42184Nick Pelly case BluetoothAdapter.STATE_ON: 331105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project break; 332105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project default: 333105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project return false; 334105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project } 3359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mEnableThread != null && mEnableThread.isAlive()) { 3369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 3379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 338de893f550301a60274e87aa8168225e7a7a42184Nick Pelly setBluetoothState(BluetoothAdapter.STATE_TURNING_OFF); 339bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly mHandler.removeMessages(MESSAGE_REGISTER_SDP_RECORDS); 340105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project 341105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project // Allow 3 seconds for profiles to gracefully disconnect 342105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project // TODO: Introduce a callback mechanism so that each profile can notify 343bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly // BluetoothService when it is done shutting down 344105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project mHandler.sendMessageDelayed( 345105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project mHandler.obtainMessage(MESSAGE_FINISH_DISABLE, saveSetting ? 1 : 0, 0), 3000); 346105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project return true; 347105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project } 348105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project 349105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project 350105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project private synchronized void finishDisable(boolean saveSetting) { 351de893f550301a60274e87aa8168225e7a7a42184Nick Pelly if (mBluetoothState != BluetoothAdapter.STATE_TURNING_OFF) { 352105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project return; 3539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mEventLoop.stop(); 355d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh tearDownNativeDataNative(); 3569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project disableNative(); 3579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // mark in progress bondings as cancelled 3599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (String address : mBondState.listInState(BluetoothDevice.BOND_BONDING)) { 360005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly mBondState.setBondState(address, BluetoothDevice.BOND_NONE, 3619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project BluetoothDevice.UNBOND_REASON_AUTH_CANCELED); 3629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // update mode 365de893f550301a60274e87aa8168225e7a7a42184Nick Pelly Intent intent = new Intent(BluetoothAdapter.ACTION_SCAN_MODE_CHANGED); 366de893f550301a60274e87aa8168225e7a7a42184Nick Pelly intent.putExtra(BluetoothAdapter.EXTRA_SCAN_MODE, BluetoothAdapter.SCAN_MODE_NONE); 3679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mContext.sendBroadcast(intent, BLUETOOTH_PERM); 3689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 369105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project mIsDiscovering = false; 370bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly mAdapterProperties.clear(); 37124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly mServiceRecordToPid.clear(); 372105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project 3739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (saveSetting) { 3749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project persistBluetoothOnSetting(false); 3759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 376105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project 377de893f550301a60274e87aa8168225e7a7a42184Nick Pelly setBluetoothState(BluetoothAdapter.STATE_OFF); 378105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project 379105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project // Log bluetooth off to battery stats. 380105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project long ident = Binder.clearCallingIdentity(); 381105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project try { 382105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project mBatteryStats.noteBluetoothOff(); 383105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project } catch (RemoteException e) { 384105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project } finally { 385105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project Binder.restoreCallingIdentity(ident); 386105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project } 387997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly 388997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly if (mRestart) { 389997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly mRestart = false; 390997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly enable(); 391997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly } 3929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 394105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project /** Bring up BT and persist BT on in settings */ 395105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project public boolean enable() { 396105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project return enable(true); 3979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 4009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Enable this Bluetooth device, asynchronously. 4019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * This turns on/off the underlying hardware. 4029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 403105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project * @param saveSetting If true, persist the new state of BT in settings 404105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project * @return True on success (so far) 4059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 406105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project public synchronized boolean enable(boolean saveSetting) { 4079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 4089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Need BLUETOOTH_ADMIN permission"); 4099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Airplane mode can prevent Bluetooth radio from being turned on. 41144303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey if (mIsAirplaneSensitive && isAirplaneModeOn() && !mIsAirplaneToggleable) { 4129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 4139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 414de893f550301a60274e87aa8168225e7a7a42184Nick Pelly if (mBluetoothState != BluetoothAdapter.STATE_OFF) { 4159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 4169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mEnableThread != null && mEnableThread.isAlive()) { 4189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 4199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 420de893f550301a60274e87aa8168225e7a7a42184Nick Pelly setBluetoothState(BluetoothAdapter.STATE_TURNING_ON); 421105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project mEnableThread = new EnableThread(saveSetting); 4229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mEnableThread.start(); 4239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 4249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 426997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly /** Forcibly restart Bluetooth if it is on */ 427997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly /* package */ synchronized void restart() { 428de893f550301a60274e87aa8168225e7a7a42184Nick Pelly if (mBluetoothState != BluetoothAdapter.STATE_ON) { 429997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly return; 430997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly } 431997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly mRestart = true; 432997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly if (!disable(false)) { 433997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly mRestart = false; 434997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly } 435d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh } 436997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly 437105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project private synchronized void setBluetoothState(int state) { 438105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project if (state == mBluetoothState) { 439105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project return; 440105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project } 441105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project 442105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project if (DBG) log("Bluetooth state " + mBluetoothState + " -> " + state); 443105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project 444de893f550301a60274e87aa8168225e7a7a42184Nick Pelly Intent intent = new Intent(BluetoothAdapter.ACTION_STATE_CHANGED); 445de893f550301a60274e87aa8168225e7a7a42184Nick Pelly intent.putExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, mBluetoothState); 446de893f550301a60274e87aa8168225e7a7a42184Nick Pelly intent.putExtra(BluetoothAdapter.EXTRA_STATE, state); 447105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 448105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project 449105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project mBluetoothState = state; 450105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project 451105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project mContext.sendBroadcast(intent, BLUETOOTH_PERM); 452105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project } 453105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project 4549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private final Handler mHandler = new Handler() { 4559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 4569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void handleMessage(Message msg) { 4579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project switch (msg.what) { 458105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project case MESSAGE_REGISTER_SDP_RECORDS: 4598c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh if (!isEnabledInternal()) { 460bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly return; 461bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly } 462bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly // SystemService.start() forks sdptool to register service 463bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly // records. It can fail to register some records if it is 464bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly // forked multiple times in a row, probably because there is 465bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly // some race in sdptool or bluez when operated in parallel. 466bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly // As a workaround, delay 500ms between each fork of sdptool. 467bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly // TODO: Don't fork sdptool in order to regsiter service 468bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly // records, use a DBUS call instead. 469bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly switch (msg.arg1) { 470bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly case 1: 47177b4ad0e496941a28382eb938a05831f1f8d2d4aJaikumar Ganesh Log.d(TAG, "Registering hfag record"); 47277b4ad0e496941a28382eb938a05831f1f8d2d4aJaikumar Ganesh SystemService.start("hfag"); 473bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly mHandler.sendMessageDelayed( 474bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly mHandler.obtainMessage(MESSAGE_REGISTER_SDP_RECORDS, 2, -1), 500); 475bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly break; 476bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly case 2: 47777b4ad0e496941a28382eb938a05831f1f8d2d4aJaikumar Ganesh Log.d(TAG, "Registering hsag record"); 47877b4ad0e496941a28382eb938a05831f1f8d2d4aJaikumar Ganesh SystemService.start("hsag"); 479bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly mHandler.sendMessageDelayed( 480bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly mHandler.obtainMessage(MESSAGE_REGISTER_SDP_RECORDS, 3, -1), 500); 481bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly break; 482bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly case 3: 483bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly Log.d(TAG, "Registering opush record"); 48403c707ab6fc97e99b1603b8d6edc604dbea3cd6fNick Pelly SystemService.start("opush"); 485bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly mHandler.sendMessageDelayed( 486bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly mHandler.obtainMessage(MESSAGE_REGISTER_SDP_RECORDS, 4, -1), 500); 487bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly break; 488bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly case 4: 489bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly Log.d(TAG, "Registering pbap record"); 49067542964876aa7e4216e8f69f21dda68e7463b9aJaikumar Ganesh SystemService.start("pbap"); 491bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly break; 4929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 493105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project break; 494105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project case MESSAGE_FINISH_DISABLE: 495105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project finishDisable(msg.arg1 != 0); 496105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project break; 4971caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh case MESSAGE_UUID_INTENT: 4981caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh String address = (String)msg.obj; 49916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly if (address != null) { 5001caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh sendUuidIntent(address); 50116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly makeServiceChannelCallbacks(address); 50216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } 5031caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh break; 50412835478ee687a493d1b5882e67b6725bd539c26Nick Pelly case MESSAGE_DISCOVERABLE_TIMEOUT: 50512835478ee687a493d1b5882e67b6725bd539c26Nick Pelly int mode = msg.arg1; 5068c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh if (isEnabledInternal()) { 50712835478ee687a493d1b5882e67b6725bd539c26Nick Pelly // TODO: Switch back to the previous scan mode 50812835478ee687a493d1b5882e67b6725bd539c26Nick Pelly // This is ok for now, because we only use 50912835478ee687a493d1b5882e67b6725bd539c26Nick Pelly // CONNECTABLE and CONNECTABLE_DISCOVERABLE 51012835478ee687a493d1b5882e67b6725bd539c26Nick Pelly setScanMode(BluetoothAdapter.SCAN_MODE_CONNECTABLE, -1); 51112835478ee687a493d1b5882e67b6725bd539c26Nick Pelly } 51212835478ee687a493d1b5882e67b6725bd539c26Nick Pelly break; 513a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh case MESSAGE_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY: 514a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh address = (String)msg.obj; 515a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh if (address != null) { 516a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh createBond(address); 517a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh return; 518a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh } 519a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh break; 5209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project }; 5239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private EnableThread mEnableThread; 5259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private class EnableThread extends Thread { 5279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private final boolean mSaveSetting; 528105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project public EnableThread(boolean saveSetting) { 5299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mSaveSetting = saveSetting; 5309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void run() { 5329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean res = (enableNative() == 0); 5339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (res) { 534b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project int retryCount = 2; 535b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project boolean running = false; 536b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project while ((retryCount-- > 0) && !running) { 537b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project mEventLoop.start(); 538105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project // it may take a momement for the other thread to do its 539b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project // thing. Check periodically for a while. 540b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project int pollCount = 5; 541b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project while ((pollCount-- > 0) && !running) { 542b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project if (mEventLoop.isEventLoopRunning()) { 543b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project running = true; 544b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project break; 545b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project } 546b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project try { 547b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project Thread.sleep(100); 548b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project } catch (InterruptedException e) {} 549b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project } 550b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project } 551b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project if (!running) { 552b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project log("bt EnableThread giving up"); 553b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project res = false; 554b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project disableNative(); 555b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project } 5569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (res) { 560d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh if (!setupNativeDataNative()) { 561d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh return; 562d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh } 5639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mSaveSetting) { 5649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project persistBluetoothOnSetting(true); 5659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mIsDiscovering = false; 567c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh mBondState.readAutoPairingData(); 5689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mBondState.loadBondState(); 5699b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh initProfileState(); 570bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly mHandler.sendMessageDelayed( 571bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly mHandler.obtainMessage(MESSAGE_REGISTER_SDP_RECORDS, 1, -1), 3000); 5729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 573105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project // Log bluetooth on to battery stats. 574105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project long ident = Binder.clearCallingIdentity(); 575105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project try { 576105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project mBatteryStats.noteBluetoothOn(); 577105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project } catch (RemoteException e) { 578105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project } finally { 579105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project Binder.restoreCallingIdentity(ident); 580105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project } 5819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 582105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project 583105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project mEnableThread = null; 584105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project 585105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project setBluetoothState(res ? 586de893f550301a60274e87aa8168225e7a7a42184Nick Pelly BluetoothAdapter.STATE_ON : 587de893f550301a60274e87aa8168225e7a7a42184Nick Pelly BluetoothAdapter.STATE_OFF); 588105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project 589b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project if (res) { 590105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project // Update mode 591d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh String[] propVal = {"Pairable", getProperty("Pairable")}; 592d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh mEventLoop.onPropertyChanged(propVal); 593b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project } 594b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project 59544303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey if (mIsAirplaneSensitive && isAirplaneModeOn() && !mIsAirplaneToggleable) { 5965c43f735d94a538dc273c8f859d1100a7cdd5c71Daisuke Miyakawa disable(false); 5975c43f735d94a538dc273c8f859d1100a7cdd5c71Daisuke Miyakawa } 5985c43f735d94a538dc273c8f859d1100a7cdd5c71Daisuke Miyakawa 5999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void persistBluetoothOnSetting(boolean bluetoothOn) { 6039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project long origCallerIdentityToken = Binder.clearCallingIdentity(); 6049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Settings.Secure.putInt(mContext.getContentResolver(), Settings.Secure.BLUETOOTH_ON, 6059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project bluetoothOn ? 1 : 0); 6069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Binder.restoreCallingIdentity(origCallerIdentityToken); 6079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 609a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh /*package*/ synchronized boolean attemptAutoPair(String address) { 610a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh if (!mBondState.hasAutoPairingFailed(address) && 611a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh !mBondState.isAutoPairingBlacklisted(address)) { 612a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh mBondState.attempt(address); 613a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh setPin(address, BluetoothDevice.convertPinToBytes("0000")); 614a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh return true; 615a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh } 616a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh return false; 617a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh } 618a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh 619a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh /*package*/ synchronized void onCreatePairedDeviceResult(String address, int result) { 620a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh if (result == BluetoothDevice.BOND_SUCCESS) { 621a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh setBondState(address, BluetoothDevice.BOND_BONDED); 622a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh if (mBondState.isAutoPairingAttemptsInProgress(address)) { 623a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh mBondState.clearPinAttempts(address); 624a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh } 625a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh } else if (result == BluetoothDevice.UNBOND_REASON_AUTH_FAILED && 626a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh mBondState.getAttempt(address) == 1) { 627a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh mBondState.addAutoPairingFailure(address); 628a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh pairingAttempt(address, result); 629a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh } else if (result == BluetoothDevice.UNBOND_REASON_REMOTE_DEVICE_DOWN && 630a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh mBondState.isAutoPairingAttemptsInProgress(address)) { 631a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh pairingAttempt(address, result); 632a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh } else { 633a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh setBondState(address, BluetoothDevice.BOND_NONE, result); 634a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh if (mBondState.isAutoPairingAttemptsInProgress(address)) { 635a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh mBondState.clearPinAttempts(address); 636a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh } 637a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh } 638a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh } 639a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh 640a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh /*package*/ synchronized String getPendingOutgoingBonding() { 641a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh return mBondState.getPendingOutgoingBonding(); 642a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh } 643a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh 644a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh private void pairingAttempt(String address, int result) { 645a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh // This happens when our initial guess of "0000" as the pass key 646a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh // fails. Try to create the bond again and display the pin dialog 647a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh // to the user. Use back-off while posting the delayed 648a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh // message. The initial value is 649a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh // INIT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY and the max value is 650a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh // MAX_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY. If the max value is 651a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh // reached, display an error to the user. 652a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh int attempt = mBondState.getAttempt(address); 653a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh if (attempt * INIT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY > 654a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh MAX_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY) { 655a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh mBondState.clearPinAttempts(address); 656a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh setBondState(address, BluetoothDevice.BOND_NONE, result); 657a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh return; 658a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh } 659a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh 660a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh Message message = mHandler.obtainMessage(MESSAGE_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY); 661a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh message.obj = address; 662a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh boolean postResult = mHandler.sendMessageDelayed(message, 663a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh attempt * INIT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY); 664a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh if (!postResult) { 665a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh mBondState.clearPinAttempts(address); 666a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh setBondState(address, 667a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh BluetoothDevice.BOND_NONE, result); 668a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh return; 669a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh } 670a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh mBondState.attempt(address); 6719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** local cache of bonding state. 6749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* we keep our own state to track the intermediate state BONDING, which 6759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* bluez does not track. 6769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * All addreses must be passed in upper case. 6779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 6789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public class BondState { 6799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private final HashMap<String, Integer> mState = new HashMap<String, Integer>(); 6809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private final HashMap<String, Integer> mPinAttempt = new HashMap<String, Integer>(); 681c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh 682c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh private static final String AUTO_PAIRING_BLACKLIST = 683c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh "/etc/bluetooth/auto_pairing.conf"; 684c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh private static final String DYNAMIC_AUTO_PAIRING_BLACKLIST = 685c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh "/data/misc/bluetooth/dynamic_auto_pairing.conf"; 686c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh private ArrayList<String> mAutoPairingAddressBlacklist; 687c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh private ArrayList<String> mAutoPairingExactNameBlacklist; 688c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh private ArrayList<String> mAutoPairingPartialNameBlacklist; 689c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh // Addresses added to blacklist dynamically based on usage. 690c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh private ArrayList<String> mAutoPairingDynamicAddressBlacklist; 691c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh 692482d54bb0cd9e00fd929185c31fea3ad845d97bcJaikumar Ganesh 6932092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh // If this is an outgoing connection, store the address. 6942092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh // There can be only 1 pending outgoing connection at a time, 6952092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh private String mPendingOutgoingBonding; 6962092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh 6972092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh private synchronized void setPendingOutgoingBonding(String address) { 6982092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh mPendingOutgoingBonding = address; 6992092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh } 7002092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh 7012092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh public synchronized String getPendingOutgoingBonding() { 7022092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh return mPendingOutgoingBonding; 7032092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh } 7042092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh 7059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public synchronized void loadBondState() { 706de893f550301a60274e87aa8168225e7a7a42184Nick Pelly if (mBluetoothState != BluetoothAdapter.STATE_TURNING_ON) { 7079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 7089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 709d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh String []bonds = null; 710b148bc844e5eddb07bef2fd1b4b754716decb43eJaikumar Ganesh String val = getPropertyInternal("Devices"); 711d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh if (val != null) { 712d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh bonds = val.split(","); 713d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh } 7149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (bonds == null) { 7159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 7169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mState.clear(); 7189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (DBG) log("found " + bonds.length + " bonded devices"); 719d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh for (String device : bonds) { 720d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh mState.put(getAddressFromObjectPath(device).toUpperCase(), 721d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh BluetoothDevice.BOND_BONDED); 7229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public synchronized void setBondState(String address, int state) { 7269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project setBondState(address, state, 0); 7279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** reason is ignored unless state == BOND_NOT_BONDED */ 7309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public synchronized void setBondState(String address, int state, int reason) { 7319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int oldState = getBondState(address); 7329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (oldState == state) { 7339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 7349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7352092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh 7362092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh // Check if this was an pending outgoing bonding. 7372092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh // If yes, reset the state. 7382092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh if (oldState == BluetoothDevice.BOND_BONDING) { 7392092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh if (address.equals(mPendingOutgoingBonding)) { 7402092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh mPendingOutgoingBonding = null; 7412092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh } 7422092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh } 7432092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh 7449b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh if (state == BluetoothDevice.BOND_BONDED) { 7459b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh addProfileState(address); 7469b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh } else if (state == BluetoothDevice.BOND_NONE) { 7479b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh removeProfileState(address); 7489b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh } 7499b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh 7509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (DBG) log(address + " bond state " + oldState + " -> " + state + " (" + 7519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project reason + ")"); 752005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly Intent intent = new Intent(BluetoothDevice.ACTION_BOND_STATE_CHANGED); 753005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mAdapter.getRemoteDevice(address)); 754005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly intent.putExtra(BluetoothDevice.EXTRA_BOND_STATE, state); 755005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly intent.putExtra(BluetoothDevice.EXTRA_PREVIOUS_BOND_STATE, oldState); 756005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly if (state == BluetoothDevice.BOND_NONE) { 7579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (reason <= 0) { 7589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.w(TAG, "setBondState() called to unbond device, but reason code is " + 7599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "invalid. Overriding reason code with BOND_RESULT_REMOVED"); 7609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project reason = BluetoothDevice.UNBOND_REASON_REMOVED; 7619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 762005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly intent.putExtra(BluetoothDevice.EXTRA_REASON, reason); 7639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mState.remove(address); 7649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 7659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mState.put(address, state); 7669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mContext.sendBroadcast(intent, BLUETOOTH_PERM); 7699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean isAutoPairingBlacklisted(String address) { 772c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh if (mAutoPairingAddressBlacklist != null) { 773c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh for (String blacklistAddress : mAutoPairingAddressBlacklist) { 774c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh if (address.startsWith(blacklistAddress)) return true; 775c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh } 7769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 777482d54bb0cd9e00fd929185c31fea3ad845d97bcJaikumar Ganesh 778c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh if (mAutoPairingDynamicAddressBlacklist != null) { 779c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh for (String blacklistAddress: mAutoPairingDynamicAddressBlacklist) { 780c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh if (address.equals(blacklistAddress)) return true; 781c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh } 782c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh } 783482d54bb0cd9e00fd929185c31fea3ad845d97bcJaikumar Ganesh String name = getRemoteName(address); 784482d54bb0cd9e00fd929185c31fea3ad845d97bcJaikumar Ganesh if (name != null) { 785c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh if (mAutoPairingExactNameBlacklist != null) { 786c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh for (String blacklistName : mAutoPairingExactNameBlacklist) { 787c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh if (name.equals(blacklistName)) return true; 788c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh } 789738ed80262aa26128924c51f59ffd49e1163eb8dJaikumar Ganesh } 790738ed80262aa26128924c51f59ffd49e1163eb8dJaikumar Ganesh 791c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh if (mAutoPairingPartialNameBlacklist != null) { 792c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh for (String blacklistName : mAutoPairingPartialNameBlacklist) { 793c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh if (name.startsWith(blacklistName)) return true; 794c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh } 795482d54bb0cd9e00fd929185c31fea3ad845d97bcJaikumar Ganesh } 796482d54bb0cd9e00fd929185c31fea3ad845d97bcJaikumar Ganesh } 7979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 7989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public synchronized int getBondState(String address) { 8019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Integer state = mState.get(address); 8029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (state == null) { 803005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly return BluetoothDevice.BOND_NONE; 8049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return state.intValue(); 8069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 808e5d93b7ed983f98855555d560faf060836f1a52fJaikumar Ganesh /*package*/ synchronized String[] listInState(int state) { 8099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ArrayList<String> result = new ArrayList<String>(mState.size()); 8109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (Map.Entry<String, Integer> e : mState.entrySet()) { 8119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (e.getValue().intValue() == state) { 8129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project result.add(e.getKey()); 8139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return result.toArray(new String[result.size()]); 8169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public synchronized void addAutoPairingFailure(String address) { 819c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh if (mAutoPairingDynamicAddressBlacklist == null) { 820c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh mAutoPairingDynamicAddressBlacklist = new ArrayList<String>(); 8219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 822c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh 823c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh updateAutoPairingData(address); 824c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh mAutoPairingDynamicAddressBlacklist.add(address); 8259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public synchronized boolean isAutoPairingAttemptsInProgress(String address) { 8289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return getAttempt(address) != 0; 8299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public synchronized void clearPinAttempts(String address) { 8329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPinAttempt.remove(address); 8339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public synchronized boolean hasAutoPairingFailed(String address) { 836c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh if (mAutoPairingDynamicAddressBlacklist == null) return false; 837c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh 838c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh return mAutoPairingDynamicAddressBlacklist.contains(address); 8399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public synchronized int getAttempt(String address) { 8429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Integer attempt = mPinAttempt.get(address); 8439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (attempt == null) { 8449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return 0; 8459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return attempt.intValue(); 8479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public synchronized void attempt(String address) { 8509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Integer attempt = mPinAttempt.get(address); 8519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int newAttempt; 8529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (attempt == null) { 8539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project newAttempt = 1; 8549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 8559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project newAttempt = attempt.intValue() + 1; 8569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPinAttempt.put(address, new Integer(newAttempt)); 8589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 860c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh private void copyAutoPairingData() { 861c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh File file = null; 862c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh FileInputStream in = null; 863c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh FileOutputStream out = null; 864c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh try { 865c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh file = new File(DYNAMIC_AUTO_PAIRING_BLACKLIST); 866c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh if (file.exists()) return; 867c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh 868c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh in = new FileInputStream(AUTO_PAIRING_BLACKLIST); 869c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh out= new FileOutputStream(DYNAMIC_AUTO_PAIRING_BLACKLIST); 870c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh 871c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh byte[] buf = new byte[1024]; 872c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh int len; 873c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh while ((len = in.read(buf)) > 0) { 874c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh out.write(buf, 0, len); 875c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh } 876c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh } catch (FileNotFoundException e) { 877c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh log("FileNotFoundException: in copyAutoPairingData"); 878c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh } catch (IOException e) { 879c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh log("IOException: in copyAutoPairingData"); 880c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh } finally { 881c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh try { 882c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh if (in != null) in.close(); 883c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh if (out != null) out.close(); 884c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh } catch (IOException e) {} 885c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh } 886c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh } 887c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh 888c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh public void readAutoPairingData() { 889c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh if (mAutoPairingAddressBlacklist != null) return; 890c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh copyAutoPairingData(); 891c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh FileInputStream fstream = null; 892c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh try { 893c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh fstream = new FileInputStream(DYNAMIC_AUTO_PAIRING_BLACKLIST); 894c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh DataInputStream in = new DataInputStream(fstream); 895c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh BufferedReader file = new BufferedReader(new InputStreamReader(in)); 896c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh String line; 897c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh while((line = file.readLine()) != null) { 898c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh line = line.trim(); 899c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh if (line.length() == 0 || line.startsWith("//")) continue; 900c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh String[] value = line.split("="); 901c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh if (value != null && value.length == 2) { 902c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh String[] val = value[1].split(","); 903c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh if (value[0].equalsIgnoreCase("AddressBlacklist")) { 904c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh mAutoPairingAddressBlacklist = 905c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh new ArrayList<String>(Arrays.asList(val)); 906c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh } else if (value[0].equalsIgnoreCase("ExactNameBlacklist")) { 907c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh mAutoPairingExactNameBlacklist = 908c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh new ArrayList<String>(Arrays.asList(val)); 909c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh } else if (value[0].equalsIgnoreCase("PartialNameBlacklist")) { 910c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh mAutoPairingPartialNameBlacklist = 911c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh new ArrayList<String>(Arrays.asList(val)); 912c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh } else if (value[0].equalsIgnoreCase("DynamicAddressBlacklist")) { 913c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh mAutoPairingDynamicAddressBlacklist = 914c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh new ArrayList<String>(Arrays.asList(val)); 915c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh } else { 916c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh Log.e(TAG, "Error parsing Auto pairing blacklist file"); 917c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh } 918c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh } 919c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh } 920c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh } catch (FileNotFoundException e) { 921c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh log("FileNotFoundException: readAutoPairingData" + e.toString()); 922c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh } catch (IOException e) { 923c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh log("IOException: readAutoPairingData" + e.toString()); 924c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh } finally { 925c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh if (fstream != null) { 926c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh try { 927c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh fstream.close(); 928c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh } catch (IOException e) { 929c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh // Ignore 930c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh } 931c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh } 932c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh } 933c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh } 934c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh 935c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh // This function adds a bluetooth address to the auto pairing blacklis 936c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh // file. These addresses are added to DynamicAddressBlacklistSection 937c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh private void updateAutoPairingData(String address) { 938c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh BufferedWriter out = null; 939c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh try { 940c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh out = new BufferedWriter(new FileWriter(DYNAMIC_AUTO_PAIRING_BLACKLIST, true)); 941c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh StringBuilder str = new StringBuilder(); 942c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh if (mAutoPairingDynamicAddressBlacklist.size() == 0) { 943c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh str.append("DynamicAddressBlacklist="); 944c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh } 945c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh str.append(address); 946c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh str.append(","); 947c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh out.write(str.toString()); 948c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh } catch (FileNotFoundException e) { 949c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh log("FileNotFoundException: updateAutoPairingData" + e.toString()); 950c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh } catch (IOException e) { 951c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh log("IOException: updateAutoPairingData" + e.toString()); 952c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh } finally { 953c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh if (out != null) { 954c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh try { 955c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh out.close(); 956c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh } catch (IOException e) { 957c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh // Ignore 958c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh } 959c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh } 960c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh } 961c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh } 9629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static String toBondStateString(int bondState) { 9659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project switch (bondState) { 966005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly case BluetoothDevice.BOND_NONE: 9679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return "not bonded"; 9689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case BluetoothDevice.BOND_BONDING: 9699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return "bonding"; 9709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case BluetoothDevice.BOND_BONDED: 9719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return "bonded"; 9729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project default: 9739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return "??????"; 9749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9779519ce75f15ba287a641166c1b7ed10f2aa73f74Jaikumar Ganesh /*package*/ synchronized boolean isAdapterPropertiesEmpty() { 9789519ce75f15ba287a641166c1b7ed10f2aa73f74Jaikumar Ganesh return mAdapterProperties.isEmpty(); 9799519ce75f15ba287a641166c1b7ed10f2aa73f74Jaikumar Ganesh } 9809519ce75f15ba287a641166c1b7ed10f2aa73f74Jaikumar Ganesh 981d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh /*package*/synchronized void getAllProperties() { 9828c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh 9839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 984bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly mAdapterProperties.clear(); 985d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh 986d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh String properties[] = (String [])getAdapterPropertiesNative(); 987d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh // The String Array consists of key-value pairs. 988d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh if (properties == null) { 989d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh Log.e(TAG, "*Error*: GetAdapterProperties returned NULL"); 990d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh return; 991d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh } 992d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh 9938bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh for (int i = 0; i < properties.length; i++) { 9948bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh String name = properties[i]; 995efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh String newValue = null; 9968bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh int len; 9978bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh if (name == null) { 9988bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh Log.e(TAG, "Error:Adapter Property at index" + i + "is null"); 9998bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh continue; 10008bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh } 10017a9de8b425954e4039053038e4ec1762b866c83cDanica Chang if (name.equals("Devices") || name.equals("UUIDs")) { 1002efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh StringBuilder str = new StringBuilder(); 10038bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh len = Integer.valueOf(properties[++i]); 10048bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh for (int j = 0; j < len; j++) { 1005efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh str.append(properties[++i]); 1006efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh str.append(","); 1007efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh } 1008efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh if (len > 0) { 1009efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh newValue = str.toString(); 10108bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh } 10118bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh } else { 10128bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh newValue = properties[++i]; 10138bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh } 1014bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly mAdapterProperties.put(name, newValue); 1015d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh } 1016d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh 1017d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh // Add adapter object path property. 1018d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh String adapterPath = getAdapterPathNative(); 1019d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh if (adapterPath != null) 1020bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly mAdapterProperties.put("ObjectPath", adapterPath + "/dev_"); 10219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1023d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh /* package */ synchronized void setProperty(String name, String value) { 1024bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly mAdapterProperties.put(name, value); 10259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public synchronized boolean setName(String name) { 10289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 10299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Need BLUETOOTH_ADMIN permission"); 10309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (name == null) { 10319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 10329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1033d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh return setPropertyString("Name", name); 10349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1036d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh //TODO(): setPropertyString, setPropertyInteger, setPropertyBoolean 1037d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh // Either have a single property function with Object as the parameter 1038d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh // or have a function for each property and then obfuscate in the JNI layer. 1039d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh // The following looks dirty. 1040d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh private boolean setPropertyString(String key, String value) { 10419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 10428c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh if (!isEnabledInternal()) return false; 1043d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh return setAdapterPropertyStringNative(key, value); 10449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1046d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh private boolean setPropertyInteger(String key, int value) { 1047d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 10488c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh if (!isEnabledInternal()) return false; 1049d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh return setAdapterPropertyIntegerNative(key, value); 1050d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh } 10519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1052d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh private boolean setPropertyBoolean(String key, boolean value) { 1053d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 10548c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh if (!isEnabledInternal()) return false; 1055d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh return setAdapterPropertyBooleanNative(key, value ? 1 : 0); 10569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1058d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh /** 1059d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh * Set the discoverability window for the device. A timeout of zero 1060d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh * makes the device permanently discoverable (if the device is 1061d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh * discoverable). Setting the timeout to a nonzero value does not make 1062d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh * a device discoverable; you need to call setMode() to make the device 1063d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh * explicitly discoverable. 1064d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh * 1065d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh * @param timeout_s The discoverable timeout in seconds. 1066d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh */ 1067d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh public synchronized boolean setDiscoverableTimeout(int timeout) { 10689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 10699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Need BLUETOOTH_ADMIN permission"); 1070d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh return setPropertyInteger("DiscoverableTimeout", timeout); 10719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 107312835478ee687a493d1b5882e67b6725bd539c26Nick Pelly public synchronized boolean setScanMode(int mode, int duration) { 107418b1e79a123b979d25bfa5d0b0ee5d0382dbd64bNick Pelly mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS, 107518b1e79a123b979d25bfa5d0b0ee5d0382dbd64bNick Pelly "Need WRITE_SECURE_SETTINGS permission"); 1076de893f550301a60274e87aa8168225e7a7a42184Nick Pelly boolean pairable = false; 1077de893f550301a60274e87aa8168225e7a7a42184Nick Pelly boolean discoverable = false; 107812835478ee687a493d1b5882e67b6725bd539c26Nick Pelly 1079de893f550301a60274e87aa8168225e7a7a42184Nick Pelly switch (mode) { 1080de893f550301a60274e87aa8168225e7a7a42184Nick Pelly case BluetoothAdapter.SCAN_MODE_NONE: 108112835478ee687a493d1b5882e67b6725bd539c26Nick Pelly mHandler.removeMessages(MESSAGE_DISCOVERABLE_TIMEOUT); 1082d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh pairable = false; 1083d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh discoverable = false; 1084de893f550301a60274e87aa8168225e7a7a42184Nick Pelly break; 1085de893f550301a60274e87aa8168225e7a7a42184Nick Pelly case BluetoothAdapter.SCAN_MODE_CONNECTABLE: 108612835478ee687a493d1b5882e67b6725bd539c26Nick Pelly mHandler.removeMessages(MESSAGE_DISCOVERABLE_TIMEOUT); 1087d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh pairable = true; 1088d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh discoverable = false; 1089005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly break; 1090de893f550301a60274e87aa8168225e7a7a42184Nick Pelly case BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE: 109112835478ee687a493d1b5882e67b6725bd539c26Nick Pelly mHandler.removeMessages(MESSAGE_DISCOVERABLE_TIMEOUT); 1092d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh pairable = true; 1093d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh discoverable = true; 109412835478ee687a493d1b5882e67b6725bd539c26Nick Pelly Message msg = mHandler.obtainMessage(MESSAGE_DISCOVERABLE_TIMEOUT); 109512835478ee687a493d1b5882e67b6725bd539c26Nick Pelly mHandler.sendMessageDelayed(msg, duration * 1000); 109612835478ee687a493d1b5882e67b6725bd539c26Nick Pelly if (DBG) Log.d(TAG, "BT Discoverable for " + duration + " seconds"); 1097005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly break; 1098de893f550301a60274e87aa8168225e7a7a42184Nick Pelly default: 1099de893f550301a60274e87aa8168225e7a7a42184Nick Pelly Log.w(TAG, "Requested invalid scan mode " + mode); 1100de893f550301a60274e87aa8168225e7a7a42184Nick Pelly return false; 1101d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh } 1102d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh setPropertyBoolean("Pairable", pairable); 1103d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh setPropertyBoolean("Discoverable", discoverable); 11049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1105d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh return true; 11069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1108b148bc844e5eddb07bef2fd1b4b754716decb43eJaikumar Ganesh /*package*/ synchronized String getProperty(String name) { 1109b148bc844e5eddb07bef2fd1b4b754716decb43eJaikumar Ganesh if (!isEnabledInternal()) return null; 1110b148bc844e5eddb07bef2fd1b4b754716decb43eJaikumar Ganesh return getPropertyInternal(name); 1111b148bc844e5eddb07bef2fd1b4b754716decb43eJaikumar Ganesh } 1112b148bc844e5eddb07bef2fd1b4b754716decb43eJaikumar Ganesh 1113b148bc844e5eddb07bef2fd1b4b754716decb43eJaikumar Ganesh /*package*/ synchronized String getPropertyInternal(String name) { 1114bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly if (!mAdapterProperties.isEmpty()) 1115bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly return mAdapterProperties.get(name); 1116d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh getAllProperties(); 1117bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly return mAdapterProperties.get(name); 11189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1120d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh public synchronized String getAddress() { 1121d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1122d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh return getProperty("Address"); 11239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1125d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh public synchronized String getName() { 11269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1127d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh return getProperty("Name"); 11289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1131d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh * Returns the user-friendly name of a remote device. This value is 1132d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh * returned from our local cache, which is updated when onPropertyChange 1133d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh * event is received. 1134d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh * Do not expect to retrieve the updated remote name immediately after 1135d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh * changing the name on the remote device. 11369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 1137d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh * @param address Bluetooth address of remote device. 1138d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh * 1139d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh * @return The user-friendly name of the specified remote device. 11409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1141d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh public synchronized String getRemoteName(String address) { 1142d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1143005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly if (!BluetoothAdapter.checkBluetoothAddress(address)) { 1144d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh return null; 1145d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh } 114655929a958bf0e482c8e4d7df3dd75957f1e9d871Jaikumar Ganesh return getRemoteDeviceProperty(address, "Name"); 11479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 11509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Get the discoverability window for the device. A timeout of zero 11519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * means that the device is permanently discoverable (if the device is 11529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * in the discoverable mode). 11539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 11549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return The discoverability window of the device, in seconds. A negative 11559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * value indicates an error. 11569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 11579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public synchronized int getDiscoverableTimeout() { 11589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1159d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh String timeout = getProperty("DiscoverableTimeout"); 1160d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh if (timeout != null) 1161d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh return Integer.valueOf(timeout); 1162d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh else 1163d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh return -1; 11649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public synchronized int getScanMode() { 11679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 11688c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh if (!isEnabledInternal()) 1169de893f550301a60274e87aa8168225e7a7a42184Nick Pelly return BluetoothAdapter.SCAN_MODE_NONE; 1170d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh 1171d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh boolean pairable = getProperty("Pairable").equals("true"); 1172d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh boolean discoverable = getProperty("Discoverable").equals("true"); 1173d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh return bluezStringToScanMode (pairable, discoverable); 11749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1176d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh public synchronized boolean startDiscovery() { 11779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 11789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Need BLUETOOTH_ADMIN permission"); 11798c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh if (!isEnabledInternal()) return false; 11808c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh 1181d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh return startDiscoveryNative(); 11829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1184d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh public synchronized boolean cancelDiscovery() { 11859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 11869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Need BLUETOOTH_ADMIN permission"); 11878c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh if (!isEnabledInternal()) return false; 11888c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh 1189d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh return stopDiscoveryNative(); 1190d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh } 1191d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh 1192d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh public synchronized boolean isDiscovering() { 1193d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1194d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh return mIsDiscovering; 1195d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh } 1196d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh 1197d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh /* package */ void setIsDiscovering(boolean isDiscovering) { 1198d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh mIsDiscovering = isDiscovering; 11999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1201cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh private boolean isBondingFeasible(String address) { 12029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 12039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Need BLUETOOTH_ADMIN permission"); 12048c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh if (!isEnabledInternal()) return false; 12058c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh 1206005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly if (!BluetoothAdapter.checkBluetoothAddress(address)) { 12079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 12089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project address = address.toUpperCase(); 12109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12112092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh if (mBondState.getPendingOutgoingBonding() != null) { 12129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project log("Ignoring createBond(): another device is bonding"); 12139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // a different device is currently bonding, fail 12149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 12159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Check for bond state only if we are not performing auto 12189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // pairing exponential back-off attempts. 12199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!mBondState.isAutoPairingAttemptsInProgress(address) && 1220005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly mBondState.getBondState(address) != BluetoothDevice.BOND_NONE) { 12219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project log("Ignoring createBond(): this device is already bonding or bonded"); 12229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 12239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12253fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh if (address.equals(mDockAddress)) { 12263fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh if (!writeDockPin()) { 12273fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh log("Error while writing Pin for the dock"); 12283fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh return false; 12293fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh } 12303fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh } 1231cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh return true; 1232cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh } 12333fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh 1234cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh public synchronized boolean createBond(String address) { 1235cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh if (!isBondingFeasible(address)) return false; 1236cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh 1237cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh if (!createPairedDeviceNative(address, 60000 /*1 minute*/ )) { 12389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 12399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12412092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh mBondState.setPendingOutgoingBonding(address); 12429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mBondState.setBondState(address, BluetoothDevice.BOND_BONDING); 12432092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh 12449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 12459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1247cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh public synchronized boolean createBondOutOfBand(String address, byte[] hash, 1248cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh byte[] randomizer) { 1249cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh if (!isBondingFeasible(address)) return false; 1250cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh 1251cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh if (!createPairedDeviceOutOfBandNative(address, 60000 /* 1 minute */)) { 1252cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh return false; 1253cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh } 1254cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh 1255cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh setDeviceOutOfBandData(address, hash, randomizer); 1256cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh mBondState.setPendingOutgoingBonding(address); 1257cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh mBondState.setBondState(address, BluetoothDevice.BOND_BONDING); 1258cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh 1259cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh return true; 1260cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh } 1261cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh 1262cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh public synchronized boolean setDeviceOutOfBandData(String address, byte[] hash, 1263cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh byte[] randomizer) { 1264cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 1265cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh "Need BLUETOOTH_ADMIN permission"); 1266cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh if (!isEnabledInternal()) return false; 1267cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh 1268cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh Pair <byte[], byte[]> value = new Pair<byte[], byte[]>(hash, randomizer); 1269cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh 1270cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh if (DBG) { 1271cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh log("Setting out of band data for:" + address + ":" + 1272cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh Arrays.toString(hash) + ":" + Arrays.toString(randomizer)); 1273cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh } 1274cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh 1275cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh mDeviceOobData.put(address, value); 1276cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh return true; 1277cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh } 1278cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh 1279cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh Pair<byte[], byte[]> getDeviceOutOfBandData(BluetoothDevice device) { 1280cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh return mDeviceOobData.get(device.getAddress()); 1281cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh } 1282cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh 1283cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh 1284cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh public synchronized byte[] readOutOfBandData() { 1285cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, 1286cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh "Need BLUETOOTH permission"); 1287cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh if (!isEnabledInternal()) return null; 1288cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh 1289cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh return readAdapterOutOfBandDataNative(); 1290cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh } 1291cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh 12929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public synchronized boolean cancelBondProcess(String address) { 12939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 12949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Need BLUETOOTH_ADMIN permission"); 12958c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh if (!isEnabledInternal()) return false; 12968c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh 1297005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly if (!BluetoothAdapter.checkBluetoothAddress(address)) { 12989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 12999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project address = address.toUpperCase(); 13019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mBondState.getBondState(address) != BluetoothDevice.BOND_BONDING) { 13029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 13039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1305005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly mBondState.setBondState(address, BluetoothDevice.BOND_NONE, 13069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project BluetoothDevice.UNBOND_REASON_AUTH_CANCELED); 1307d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh cancelDeviceCreationNative(address); 13089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 13099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public synchronized boolean removeBond(String address) { 13129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 13139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Need BLUETOOTH_ADMIN permission"); 13148c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh if (!isEnabledInternal()) return false; 13158c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh 1316005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly if (!BluetoothAdapter.checkBluetoothAddress(address)) { 13179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 13189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1319f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh BluetoothDeviceProfileState state = mDeviceProfileState.get(address); 13209b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh if (state != null) { 1321f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh state.sendMessage(BluetoothDeviceProfileState.UNPAIR); 13229b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh return true; 13239b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh } else { 13249b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh return false; 13259b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh } 13269b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh } 13279b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh 13289b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh public synchronized boolean removeBondInternal(String address) { 1329d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh return removeDeviceNative(getObjectPathFromAddress(address)); 13309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public synchronized String[] listBonds() { 13339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 13349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mBondState.listInState(BluetoothDevice.BOND_BONDED); 13359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1337a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh /*package*/ synchronized String[] listInState(int state) { 1338a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh return mBondState.listInState(state); 1339a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh } 1340a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh 13419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public synchronized int getBondState(String address) { 13429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1343005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly if (!BluetoothAdapter.checkBluetoothAddress(address)) { 1344b24e11baac589fe16426f2d243b460ab84991c7bNick Pelly return BluetoothDevice.ERROR; 13459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mBondState.getBondState(address.toUpperCase()); 13479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1349a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh /*package*/ synchronized boolean setBondState(String address, int state) { 1350a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh return setBondState(address, state, 0); 1351a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh } 1352a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh 1353a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh /*package*/ synchronized boolean setBondState(String address, int state, int reason) { 1354a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh mBondState.setBondState(address.toUpperCase(), state); 1355a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh return true; 1356a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh } 1357a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh 13583fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh public synchronized boolean isBluetoothDock(String address) { 13596e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh SharedPreferences sp = mContext.getSharedPreferences(SHARED_PREFERENCES_NAME, 13606e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh mContext.MODE_PRIVATE); 13616e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh 13626e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh return sp.contains(SHARED_PREFERENCE_DOCK_ADDRESS + address); 13633fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh } 13643fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh 13659488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh /*package*/ boolean isRemoteDeviceInCache(String address) { 1366bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly return (mDeviceProperties.get(address) != null); 13679488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh } 13689488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh 13699488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh /*package*/ String[] getRemoteDeviceProperties(String address) { 13708c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh if (!isEnabledInternal()) return null; 13718c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh 13729488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh String objectPath = getObjectPathFromAddress(address); 13739488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh return (String [])getDevicePropertiesNative(objectPath); 13749488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh } 13759488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh 1376d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh /*package*/ synchronized String getRemoteDeviceProperty(String address, String property) { 1377bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly Map<String, String> properties = mDeviceProperties.get(address); 1378d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh if (properties != null) { 1379d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh return properties.get(property); 1380d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh } else { 1381d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh // Query for remote device properties, again. 1382d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh // We will need to reload the cache when we switch Bluetooth on / off 1383d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh // or if we crash. 138410eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh if (updateRemoteDevicePropertiesCache(address)) 1385d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh return getRemoteDeviceProperty(address, property); 13869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1387d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh Log.e(TAG, "getRemoteDeviceProperty: " + property + "not present:" + address); 1388d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh return null; 13899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 139110eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh /* package */ synchronized boolean updateRemoteDevicePropertiesCache(String address) { 139210eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh String[] propValues = getRemoteDeviceProperties(address); 139310eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh if (propValues != null) { 139410eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh addRemoteDeviceProperties(address, propValues); 139510eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh return true; 139610eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh } 139710eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh return false; 139810eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh } 139910eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh 1400d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh /* package */ synchronized void addRemoteDeviceProperties(String address, String[] properties) { 1401395d1023660c5caedf7888def17f8ad826f51bf8Jaikumar Ganesh /* 1402395d1023660c5caedf7888def17f8ad826f51bf8Jaikumar Ganesh * We get a DeviceFound signal every time RSSI changes or name changes. 1403395d1023660c5caedf7888def17f8ad826f51bf8Jaikumar Ganesh * Don't create a new Map object every time */ 1404bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly Map<String, String> propertyValues = mDeviceProperties.get(address); 1405efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh if (propertyValues == null) { 1406395d1023660c5caedf7888def17f8ad826f51bf8Jaikumar Ganesh propertyValues = new HashMap<String, String>(); 1407395d1023660c5caedf7888def17f8ad826f51bf8Jaikumar Ganesh } 1408395d1023660c5caedf7888def17f8ad826f51bf8Jaikumar Ganesh 14098bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh for (int i = 0; i < properties.length; i++) { 14108bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh String name = properties[i]; 1411efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh String newValue = null; 14128bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh int len; 14138bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh if (name == null) { 14148bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh Log.e(TAG, "Error: Remote Device Property at index" + i + "is null"); 14158bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh continue; 14168bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh } 14178bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh if (name.equals("UUIDs") || name.equals("Nodes")) { 1418efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh StringBuilder str = new StringBuilder(); 14198bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh len = Integer.valueOf(properties[++i]); 14208bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh for (int j = 0; j < len; j++) { 1421efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh str.append(properties[++i]); 1422efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh str.append(","); 1423efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh } 1424efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh if (len > 0) { 1425efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh newValue = str.toString(); 14268bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh } 1427d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh } else { 14288bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh newValue = properties[++i]; 1429d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh } 1430efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh 14318bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh propertyValues.put(name, newValue); 14329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1433bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly mDeviceProperties.put(address, propertyValues); 143410eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh 143510eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh // We have added a new remote device or updated its properties. 143610eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh // Also update the serviceChannel cache. 143710eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh updateDeviceServiceChannelCache(address); 14389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1440d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh /* package */ void removeRemoteDeviceProperties(String address) { 1441bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly mDeviceProperties.remove(address); 14429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1444d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh /* package */ synchronized void setRemoteDeviceProperty(String address, String name, 1445d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh String value) { 1446bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly Map <String, String> propVal = mDeviceProperties.get(address); 1447d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh if (propVal != null) { 1448d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh propVal.put(name, value); 1449bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly mDeviceProperties.put(address, propVal); 1450d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh } else { 1451d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh Log.e(TAG, "setRemoteDeviceProperty for a device not in cache:" + address); 14529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1456efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue * Sets the remote device trust state. 1457efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue * 1458efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue * @return boolean to indicate operation success or fail 1459efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue */ 1460efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue public synchronized boolean setTrust(String address, boolean value) { 1461005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly if (!BluetoothAdapter.checkBluetoothAddress(address)) { 1462e6ee3be1c254404dad842298f6f56c11cc6c7ac8Nick Pelly mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 1463e6ee3be1c254404dad842298f6f56c11cc6c7ac8Nick Pelly "Need BLUETOOTH_ADMIN permission"); 1464efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue return false; 1465efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue } 1466efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue 14678c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh if (!isEnabledInternal()) return false; 14688c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh 1469efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue return setDevicePropertyBooleanNative(getObjectPathFromAddress(address), "Trusted", 1470efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue value ? 1 : 0); 1471efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue } 1472efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue 1473efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue /** 1474efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue * Gets the remote device trust state as boolean. 1475efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue * Note: this value may be 1476efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue * retrieved from cache if we retrieved the data before * 1477efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue * 1478efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue * @return boolean to indicate trust or untrust state 1479efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue */ 1480efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue public synchronized boolean getTrustState(String address) { 1481005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly if (!BluetoothAdapter.checkBluetoothAddress(address)) { 1482efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1483efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue return false; 1484efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue } 1485efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue 1486efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue String val = getRemoteDeviceProperty(address, "Trusted"); 1487efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue if (val == null) { 1488efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue return false; 1489efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue } else { 1490efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue return val.equals("true") ? true : false; 1491efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue } 1492efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue } 1493efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue 1494efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue /** 1495d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh * Gets the remote major, minor classes encoded as a 32-bit 14969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * integer. 14979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 14989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Note: this value is retrieved from cache, because we get it during 14999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * remote-device discovery. 15009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 15019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return 32-bit integer encoding the remote major, minor, and service 15029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * classes. 15039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 15049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public synchronized int getRemoteClass(String address) { 1505005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly if (!BluetoothAdapter.checkBluetoothAddress(address)) { 1506ea600ccfb7568f60377c4abc85f56c80af7fdbfcNick Pelly mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1507ea600ccfb7568f60377c4abc85f56c80af7fdbfcNick Pelly return BluetoothClass.ERROR; 15089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1509d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh String val = getRemoteDeviceProperty(address, "Class"); 1510d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh if (val == null) 1511d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh return BluetoothClass.ERROR; 1512d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh else { 1513d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh return Integer.valueOf(val); 1514d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh } 15159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1516d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh 15179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 15189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1519dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh * Gets the UUIDs supported by the remote device 15209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 1521dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh * @return array of 128bit ParcelUuids 15229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1523dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh public synchronized ParcelUuid[] getRemoteUuids(String address) { 15249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1525005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly if (!BluetoothAdapter.checkBluetoothAddress(address)) { 15269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return null; 15279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15281caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh return getUuidFromCache(address); 15291caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh } 15301caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh 15311caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh private ParcelUuid[] getUuidFromCache(String address) { 1532d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh String value = getRemoteDeviceProperty(address, "UUIDs"); 1533dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh if (value == null) return null; 1534dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh 1535dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh String[] uuidStrings = null; 1536d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh // The UUIDs are stored as a "," separated string. 1537dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh uuidStrings = value.split(","); 1538dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh ParcelUuid[] uuids = new ParcelUuid[uuidStrings.length]; 1539dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh 1540dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh for (int i = 0; i < uuidStrings.length; i++) { 1541dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh uuids[i] = ParcelUuid.fromString(uuidStrings[i]); 1542dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh } 1543d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh return uuids; 15449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 154616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly /** 154716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly * Connect and fetch new UUID's using SDP. 154816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly * The UUID's found are broadcast as intents. 154916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly * Optionally takes a uuid and callback to fetch the RFCOMM channel for the 155016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly * a given uuid. 155116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly * TODO: Don't wait UUID_INTENT_DELAY to broadcast UUID intents on success 155216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly * TODO: Don't wait UUID_INTENT_DELAY to handle the failure case for 155316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly * callback and broadcast intents. 155416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly */ 155516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly public synchronized boolean fetchRemoteUuids(String address, ParcelUuid uuid, 155616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly IBluetoothCallback callback) { 15571caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 15588c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh if (!isEnabledInternal()) return false; 15598c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh 15601caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh if (!BluetoothAdapter.checkBluetoothAddress(address)) { 15611caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh return false; 15621caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh } 15631caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh 156416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly RemoteService service = new RemoteService(address, uuid); 156516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly if (uuid != null && mUuidCallbackTracker.get(service) != null) { 156616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly // An SDP query for this address & uuid is already in progress 156716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly // Do not add this callback for the uuid 156816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly return false; 156916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } 157016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly 15711caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh if (mUuidIntentTracker.contains(address)) { 15721caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh // An SDP query for this address is already in progress 157316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly // Add this uuid onto the in-progress SDP query 157416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly if (uuid != null) { 157516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly mUuidCallbackTracker.put(new RemoteService(address, uuid), callback); 157616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } 15771caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh return true; 15781caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh } 15791caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh 15801caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh boolean ret; 15810e09030977aea8b40fd177139528d4b5637c9771Jaikumar Ganesh // Just do the SDP if the device is already created and UUIDs are not 15820e09030977aea8b40fd177139528d4b5637c9771Jaikumar Ganesh // NULL, else create the device and then do SDP. 15830e09030977aea8b40fd177139528d4b5637c9771Jaikumar Ganesh if (isRemoteDeviceInCache(address) && getRemoteUuids(address) != null) { 15841caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh String path = getObjectPathFromAddress(address); 15851caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh if (path == null) return false; 15861caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh 15871caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh // Use an empty string for the UUID pattern 15881caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh ret = discoverServicesNative(path, ""); 15891caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh } else { 15901caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh ret = createDeviceNative(address); 15911caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh } 15921caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh 15931caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh mUuidIntentTracker.add(address); 159416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly if (uuid != null) { 159516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly mUuidCallbackTracker.put(new RemoteService(address, uuid), callback); 159616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } 15971caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh 15981caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh Message message = mHandler.obtainMessage(MESSAGE_UUID_INTENT); 15991caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh message.obj = address; 16001caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh mHandler.sendMessageDelayed(message, UUID_INTENT_DELAY); 16011caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh return ret; 16021caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh } 16031caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh 16049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1605d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh * Gets the rfcomm channel associated with the UUID. 160616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly * Pulls records from the cache only. 16079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 1608d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh * @param address Address of the remote device 1609dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh * @param uuid ParcelUuid of the service attribute 16109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 1611d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh * @return rfcomm channel associated with the service attribute 161210eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh * -1 on error 16139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1614dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh public int getRemoteServiceChannel(String address, ParcelUuid uuid) { 16159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 16168c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh if (!isEnabledInternal()) return -1; 16178c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh 1618005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly if (!BluetoothAdapter.checkBluetoothAddress(address)) { 1619b24e11baac589fe16426f2d243b460ab84991c7bNick Pelly return BluetoothDevice.ERROR; 16209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 162110eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh // Check if we are recovering from a crash. 162210eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh if (mDeviceProperties.isEmpty()) { 162310eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh if (!updateRemoteDevicePropertiesCache(address)) 162410eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh return -1; 162510eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh } 162610eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh 162710eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh Map<ParcelUuid, Integer> value = mDeviceServiceChannelCache.get(address); 162810eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh if (value != null && value.containsKey(uuid)) 162910eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh return value.get(uuid); 163010eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh return -1; 16319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 16339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public synchronized boolean setPin(String address, byte[] pin) { 16349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 16359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Need BLUETOOTH_ADMIN permission"); 16368c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh if (!isEnabledInternal()) return false; 16378c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh 16389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (pin == null || pin.length <= 0 || pin.length > 16 || 1639005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly !BluetoothAdapter.checkBluetoothAddress(address)) { 16409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 16419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project address = address.toUpperCase(); 16439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Integer data = mEventLoop.getPasskeyAgentRequestData().remove(address); 16449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (data == null) { 16459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.w(TAG, "setPin(" + address + ") called but no native data available, " + 16469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "ignoring. Maybe the PasskeyAgent Request was cancelled by the remote device" + 16479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project " or by bluez.\n"); 16489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 16499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // bluez API wants pin as a string 16519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String pinString; 16529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 16539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project pinString = new String(pin, "UTF8"); 16549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (UnsupportedEncodingException uee) { 16559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.e(TAG, "UTF8 not supported?!?"); 16569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 16579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return setPinNative(address, pinString, data.intValue()); 16599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1661b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh public synchronized boolean setPasskey(String address, int passkey) { 1662b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 1663b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh "Need BLUETOOTH_ADMIN permission"); 16648c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh if (!isEnabledInternal()) return false; 16658c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh 1666005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly if (passkey < 0 || passkey > 999999 || !BluetoothAdapter.checkBluetoothAddress(address)) { 1667b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh return false; 1668b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh } 1669b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh address = address.toUpperCase(); 1670b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh Integer data = mEventLoop.getPasskeyAgentRequestData().remove(address); 1671b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh if (data == null) { 1672b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh Log.w(TAG, "setPasskey(" + address + ") called but no native data available, " + 1673b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh "ignoring. Maybe the PasskeyAgent Request was cancelled by the remote device" + 1674b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh " or by bluez.\n"); 1675b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh return false; 1676b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh } 1677b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh return setPasskeyNative(address, passkey, data.intValue()); 1678b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh } 1679b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh 1680b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh public synchronized boolean setPairingConfirmation(String address, boolean confirm) { 1681b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 1682b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh "Need BLUETOOTH_ADMIN permission"); 16838c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh if (!isEnabledInternal()) return false; 16848c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh 1685b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh address = address.toUpperCase(); 1686b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh Integer data = mEventLoop.getPasskeyAgentRequestData().remove(address); 1687b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh if (data == null) { 1688b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh Log.w(TAG, "setPasskey(" + address + ") called but no native data available, " + 1689b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh "ignoring. Maybe the PasskeyAgent Request was cancelled by the remote device" + 1690b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh " or by bluez.\n"); 1691b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh return false; 1692b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh } 1693b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh return setPairingConfirmationNative(address, confirm, data.intValue()); 1694b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh } 1695b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh 1696cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh public synchronized boolean setRemoteOutOfBandData(String address) { 1697cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 1698cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh "Need BLUETOOTH_ADMIN permission"); 1699cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh if (!isEnabledInternal()) return false; 1700cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh address = address.toUpperCase(); 1701cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh Integer data = mEventLoop.getPasskeyAgentRequestData().remove(address); 1702cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh if (data == null) { 1703cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh Log.w(TAG, "setRemoteOobData(" + address + ") called but no native data available, " + 1704cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh "ignoring. Maybe the PasskeyAgent Request was cancelled by the remote device" + 1705cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh " or by bluez.\n"); 1706cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh return false; 1707cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh } 1708cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh 1709cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh Pair<byte[], byte[]> val = mDeviceOobData.get(address); 1710cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh byte[] hash, randomizer; 1711cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh if (val == null) { 1712cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh // TODO: check what should be passed in this case. 1713cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh hash = new byte[16]; 1714cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh randomizer = new byte[16]; 1715cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh } else { 1716cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh hash = val.first; 1717cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh randomizer = val.second; 1718cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh } 1719cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh return setRemoteOutOfBandDataNative(address, hash, randomizer, data.intValue()); 1720cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh } 1721cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh 1722b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh public synchronized boolean cancelPairingUserInput(String address) { 17239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 17249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Need BLUETOOTH_ADMIN permission"); 17258c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh if (!isEnabledInternal()) return false; 17268c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh 1727005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly if (!BluetoothAdapter.checkBluetoothAddress(address)) { 17289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 17299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1730005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly mBondState.setBondState(address, BluetoothDevice.BOND_NONE, 1731397d8f4f4829a45f4fe7a672cc395466bbc0f442Jaikumar Ganesh BluetoothDevice.UNBOND_REASON_AUTH_CANCELED); 17329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project address = address.toUpperCase(); 17339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Integer data = mEventLoop.getPasskeyAgentRequestData().remove(address); 17349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (data == null) { 1735b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh Log.w(TAG, "cancelUserInputNative(" + address + ") called but no native data " + 1736b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh "available, ignoring. Maybe the PasskeyAgent Request was already cancelled " + 1737b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh "by the remote or by bluez.\n"); 17389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 17399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1740b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh return cancelPairingUserInputNative(address, data.intValue()); 17419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 17438c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh /*package*/ void updateDeviceServiceChannelCache(String address) { 174410eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh ParcelUuid[] deviceUuids = getRemoteUuids(address); 174510eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh // We are storing the rfcomm channel numbers only for the uuids 174610eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh // we are interested in. 174710eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh int channel; 174816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly if (DBG) log("updateDeviceServiceChannelCache(" + address + ")"); 174916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly 175016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly ArrayList<ParcelUuid> applicationUuids = new ArrayList(); 175116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly 175216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly synchronized (this) { 175316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly for (RemoteService service : mUuidCallbackTracker.keySet()) { 175416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly if (service.address.equals(address)) { 175516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly applicationUuids.add(service.uuid); 175616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } 175716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } 175816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } 175910eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh 176010eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh Map <ParcelUuid, Integer> value = new HashMap<ParcelUuid, Integer>(); 176116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly 176216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly // Retrieve RFCOMM channel for default uuids 176316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly for (ParcelUuid uuid : RFCOMM_UUIDS) { 176410eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh if (BluetoothUuid.isUuidPresent(deviceUuids, uuid)) { 176516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly channel = getDeviceServiceChannelNative(getObjectPathFromAddress(address), 176616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly uuid.toString(), 0x0004); 176716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly if (DBG) log("\tuuid(system): " + uuid + " " + channel); 176810eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh value.put(uuid, channel); 176910eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh } 177010eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh } 177116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly // Retrieve RFCOMM channel for application requested uuids 177216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly for (ParcelUuid uuid : applicationUuids) { 177316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly if (BluetoothUuid.isUuidPresent(deviceUuids, uuid)) { 177416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly channel = getDeviceServiceChannelNative(getObjectPathFromAddress(address), 177516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly uuid.toString(), 0x0004); 177616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly if (DBG) log("\tuuid(application): " + uuid + " " + channel); 177716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly value.put(uuid, channel); 177816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } 177916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } 178016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly 178116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly synchronized (this) { 178216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly // Make application callbacks 178316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly for (Iterator<RemoteService> iter = mUuidCallbackTracker.keySet().iterator(); 178416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly iter.hasNext();) { 178516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly RemoteService service = iter.next(); 178616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly if (service.address.equals(address)) { 178716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly channel = -1; 178816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly if (value.get(service.uuid) != null) { 178916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly channel = value.get(service.uuid); 179016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } 179116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly if (channel != -1) { 179216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly if (DBG) log("Making callback for " + service.uuid + " with result " + 179316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly channel); 179416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly IBluetoothCallback callback = mUuidCallbackTracker.get(service); 179516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly if (callback != null) { 179616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly try { 179716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly callback.onRfcommChannelFound(channel); 179816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } catch (RemoteException e) {Log.e(TAG, "", e);} 179916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } 180016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly 180116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly iter.remove(); 180216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } 180316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } 180416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } 180516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly 180616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly // Update cache 180716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly mDeviceServiceChannelCache.put(address, value); 180816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } 180910eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh } 181010eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh 181124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly /** 181224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly * b is a handle to a Binder instance, so that this service can be notified 181324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly * for Applications that terminate unexpectedly, to clean there service 181424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly * records 181524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly */ 181624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly public synchronized int addRfcommServiceRecord(String serviceName, ParcelUuid uuid, 181724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly int channel, IBinder b) { 18188c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 18198c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh if (!isEnabledInternal()) return -1; 18208c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh 182124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly if (serviceName == null || uuid == null || channel < 1 || 182224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly channel > BluetoothSocket.MAX_RFCOMM_CHANNEL) { 182324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly return -1; 182424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly } 182524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly if (BluetoothUuid.isUuidPresent(BluetoothUuid.RESERVED_UUIDS, uuid)) { 182624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly Log.w(TAG, "Attempted to register a reserved UUID: " + uuid); 182724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly return -1; 182824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly } 182924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly int handle = addRfcommServiceRecordNative(serviceName, 183024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly uuid.getUuid().getMostSignificantBits(), uuid.getUuid().getLeastSignificantBits(), 183124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly (short)channel); 183224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly if (DBG) log("new handle " + Integer.toHexString(handle)); 183324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly if (handle == -1) { 183424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly return -1; 183524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly } 183624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly 183724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly int pid = Binder.getCallingPid(); 183824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly mServiceRecordToPid.put(new Integer(handle), new Integer(pid)); 183924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly try { 184024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly b.linkToDeath(new Reaper(handle, pid), 0); 184124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly } catch (RemoteException e) {} 184224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly return handle; 184324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly } 184424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly 184524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly public void removeServiceRecord(int handle) { 184624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, 184724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly "Need BLUETOOTH permission"); 184824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly checkAndRemoveRecord(handle, Binder.getCallingPid()); 184924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly } 185024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly 185124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly private synchronized void checkAndRemoveRecord(int handle, int pid) { 185224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly Integer handleInt = new Integer(handle); 185324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly Integer owner = mServiceRecordToPid.get(handleInt); 185424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly if (owner != null && pid == owner.intValue()) { 185524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly if (DBG) log("Removing service record " + Integer.toHexString(handle) + " for pid " + 185624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly pid); 185724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly mServiceRecordToPid.remove(handleInt); 185824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly removeServiceRecordNative(handle); 185924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly } 186024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly } 186124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly 186224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly private class Reaper implements IBinder.DeathRecipient { 186324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly int pid; 186424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly int handle; 186524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly Reaper(int handle, int pid) { 186624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly this.pid = pid; 186724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly this.handle = handle; 186824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly } 186924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly public void binderDied() { 187024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly synchronized (BluetoothService.this) { 187124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly if (DBG) log("Tracked app " + pid + " died"); 187224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly checkAndRemoveRecord(handle, pid); 187324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly } 187424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly } 187524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly } 187624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly 18779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private final BroadcastReceiver mReceiver = new BroadcastReceiver() { 18789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 18799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void onReceive(Context context, Intent intent) { 18806e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh if (intent == null) return; 18816e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh 18829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String action = intent.getAction(); 18839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (action.equals(Intent.ACTION_AIRPLANE_MODE_CHANGED)) { 18849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ContentResolver resolver = context.getContentResolver(); 18859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Query the airplane mode from Settings.System just to make sure that 18869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // some random app is not sending this intent and disabling bluetooth 18879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean enabled = !isAirplaneModeOn(); 18889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // If bluetooth is currently expected to be on, then enable or disable bluetooth 18899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (Settings.Secure.getInt(resolver, Settings.Secure.BLUETOOTH_ON, 0) > 0) { 18909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (enabled) { 1891105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project enable(false); 18929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 18939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project disable(false); 18949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 18959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 18966e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh } else if (Intent.ACTION_DOCK_EVENT.equals(action)) { 18976e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh int state = intent.getIntExtra(Intent.EXTRA_DOCK_STATE, 18986e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh Intent.EXTRA_DOCK_STATE_UNDOCKED); 18996e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh if (DBG) Log.v(TAG, "Received ACTION_DOCK_EVENT with State:" + state); 19006e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh if (state == Intent.EXTRA_DOCK_STATE_UNDOCKED) { 19016e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh mDockAddress = null; 19026e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh mDockPin = null; 19036e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh } else { 19046e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh SharedPreferences.Editor editor = 19056e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh mContext.getSharedPreferences(SHARED_PREFERENCES_NAME, 19066e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh mContext.MODE_PRIVATE).edit(); 19076e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh editor.putBoolean(SHARED_PREFERENCE_DOCK_ADDRESS + mDockAddress, true); 190866fce5068a8a3aeb28aaf713843891b286a75280Brad Fitzpatrick editor.apply(); 19096e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh } 19109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 19119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 19129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project }; 19139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 19146e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh private void registerForAirplaneMode(IntentFilter filter) { 191544303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey final ContentResolver resolver = mContext.getContentResolver(); 191644303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey final String airplaneModeRadios = Settings.System.getString(resolver, 19179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Settings.System.AIRPLANE_MODE_RADIOS); 191844303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey final String toggleableRadios = Settings.System.getString(resolver, 191944303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey Settings.System.AIRPLANE_MODE_TOGGLEABLE_RADIOS); 192044303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey 192144303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey mIsAirplaneSensitive = airplaneModeRadios == null ? true : 192244303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey airplaneModeRadios.contains(Settings.System.RADIO_BLUETOOTH); 192344303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey mIsAirplaneToggleable = toggleableRadios == null ? false : 192444303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey toggleableRadios.contains(Settings.System.RADIO_BLUETOOTH); 192544303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey 19269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mIsAirplaneSensitive) { 19276e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED); 19289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 19299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 19309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 19319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* Returns true if airplane mode is currently on */ 19329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private final boolean isAirplaneModeOn() { 19339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return Settings.System.getInt(mContext.getContentResolver(), 19349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Settings.System.AIRPLANE_MODE_ON, 0) == 1; 19359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 19369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 19371caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh /* Broadcast the Uuid intent */ 19381caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh /*package*/ synchronized void sendUuidIntent(String address) { 19396179965e85ec17b836084a4a3d7963d8a7a1e1ccJaikumar Ganesh ParcelUuid[] uuid = getUuidFromCache(address); 19406179965e85ec17b836084a4a3d7963d8a7a1e1ccJaikumar Ganesh Intent intent = new Intent(BluetoothDevice.ACTION_UUID); 19412d3b98d868cda30535505b2a2fba47aa1c9c052bJaikumar Ganesh intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mAdapter.getRemoteDevice(address)); 19426179965e85ec17b836084a4a3d7963d8a7a1e1ccJaikumar Ganesh intent.putExtra(BluetoothDevice.EXTRA_UUID, uuid); 19436179965e85ec17b836084a4a3d7963d8a7a1e1ccJaikumar Ganesh mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM); 19441caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh 19456179965e85ec17b836084a4a3d7963d8a7a1e1ccJaikumar Ganesh if (mUuidIntentTracker.contains(address)) 19461caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh mUuidIntentTracker.remove(address); 194716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly 194816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } 194916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly 195016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly /*package*/ synchronized void makeServiceChannelCallbacks(String address) { 195116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly for (Iterator<RemoteService> iter = mUuidCallbackTracker.keySet().iterator(); 195216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly iter.hasNext();) { 195316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly RemoteService service = iter.next(); 195416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly if (service.address.equals(address)) { 195516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly if (DBG) log("Cleaning up failed UUID channel lookup: " + service.address + 195616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly " " + service.uuid); 195716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly IBluetoothCallback callback = mUuidCallbackTracker.get(service); 195816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly if (callback != null) { 195916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly try { 196016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly callback.onRfcommChannelFound(-1); 196116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } catch (RemoteException e) {Log.e(TAG, "", e);} 196216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } 196316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly 196416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly iter.remove(); 196516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } 196616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } 19671caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh } 19681caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh 19699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 19709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 1971105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project switch(mBluetoothState) { 1972de893f550301a60274e87aa8168225e7a7a42184Nick Pelly case BluetoothAdapter.STATE_OFF: 197324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly pw.println("Bluetooth OFF\n"); 1974105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project return; 1975de893f550301a60274e87aa8168225e7a7a42184Nick Pelly case BluetoothAdapter.STATE_TURNING_ON: 197624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly pw.println("Bluetooth TURNING ON\n"); 1977105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project return; 1978de893f550301a60274e87aa8168225e7a7a42184Nick Pelly case BluetoothAdapter.STATE_TURNING_OFF: 197924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly pw.println("Bluetooth TURNING OFF\n"); 1980105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project return; 1981de893f550301a60274e87aa8168225e7a7a42184Nick Pelly case BluetoothAdapter.STATE_ON: 198224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly pw.println("Bluetooth ON\n"); 1983105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project } 1984105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project 198524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly pw.println("mIsAirplaneSensitive = " + mIsAirplaneSensitive); 198644303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey pw.println("mIsAirplaneToggleable = " + mIsAirplaneToggleable); 198724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly 198824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly pw.println("Local address = " + getAddress()); 198924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly pw.println("Local name = " + getName()); 199024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly pw.println("isDiscovering() = " + isDiscovering()); 1991105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project 1992105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project BluetoothHeadset headset = new BluetoothHeadset(mContext, null); 1993105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project 1994105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project pw.println("\n--Known devices--"); 1995bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly for (String address : mDeviceProperties.keySet()) { 19961eada0d3d655d6396bf862da954d254856a1bc03Nick Pelly int bondState = mBondState.getBondState(address); 1997105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project pw.printf("%s %10s (%d) %s\n", address, 19981eada0d3d655d6396bf862da954d254856a1bc03Nick Pelly toBondStateString(bondState), 1999105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project mBondState.getAttempt(address), 2000105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project getRemoteName(address)); 200124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly 200224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly Map<ParcelUuid, Integer> uuidChannels = mDeviceServiceChannelCache.get(address); 200324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly if (uuidChannels == null) { 200424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly pw.println("\tuuids = null"); 200524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly } else { 200624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly for (ParcelUuid uuid : uuidChannels.keySet()) { 200724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly Integer channel = uuidChannels.get(uuid); 200824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly if (channel == null) { 200924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly pw.println("\t" + uuid); 201024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly } else { 201124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly pw.println("\t" + uuid + " RFCOMM channel = " + channel); 20121eada0d3d655d6396bf862da954d254856a1bc03Nick Pelly } 20131eada0d3d655d6396bf862da954d254856a1bc03Nick Pelly } 20141eada0d3d655d6396bf862da954d254856a1bc03Nick Pelly } 201516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly for (RemoteService service : mUuidCallbackTracker.keySet()) { 201616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly if (service.address.equals(address)) { 201716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly pw.println("\tPENDING CALLBACK: " + service.uuid); 201816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } 201916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } 2020105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project } 2021105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project 2022d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh String value = getProperty("Devices"); 20231eada0d3d655d6396bf862da954d254856a1bc03Nick Pelly String[] devicesObjectPath = null; 2024d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh if (value != null) { 2025d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh devicesObjectPath = value.split(","); 2026d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh } 2027105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project pw.println("\n--ACL connected devices--"); 202824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly if (devicesObjectPath != null) { 202924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly for (String device : devicesObjectPath) { 203024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly pw.println(getAddressFromObjectPath(device)); 203124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly } 2032105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project } 2033105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project 2034105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project // Rather not do this from here, but no-where else and I need this 2035105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project // dump 2036105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project pw.println("\n--Headset Service--"); 2037740e39be6af3e366a4b82c030b5ea67ab144b42aJaikumar Ganesh switch (headset.getState(headset.getCurrentHeadset())) { 2038105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project case BluetoothHeadset.STATE_DISCONNECTED: 2039105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project pw.println("getState() = STATE_DISCONNECTED"); 2040105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project break; 2041105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project case BluetoothHeadset.STATE_CONNECTING: 2042105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project pw.println("getState() = STATE_CONNECTING"); 2043105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project break; 2044105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project case BluetoothHeadset.STATE_CONNECTED: 2045105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project pw.println("getState() = STATE_CONNECTED"); 2046105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project break; 2047105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project case BluetoothHeadset.STATE_ERROR: 2048105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project pw.println("getState() = STATE_ERROR"); 2049105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project break; 2050105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project } 20516c901db72dbaf57d8fdf26adae6721de14ecae22Nick Pelly 205224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly pw.println("\ngetCurrentHeadset() = " + headset.getCurrentHeadset()); 205324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly pw.println("getBatteryUsageHint() = " + headset.getBatteryUsageHint()); 2054105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project headset.close(); 205524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly pw.println("\n--Application Service Records--"); 205624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly for (Integer handle : mServiceRecordToPid.keySet()) { 205724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly Integer pid = mServiceRecordToPid.get(handle); 205824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly pw.println("\tpid " + pid + " handle " + Integer.toHexString(handle)); 205924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly } 20609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 20619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2062d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh /* package */ static int bluezStringToScanMode(boolean pairable, boolean discoverable) { 2063d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh if (pairable && discoverable) 2064bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly return BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE; 2065d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh else if (pairable && !discoverable) 2066bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly return BluetoothAdapter.SCAN_MODE_CONNECTABLE; 2067d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh else 2068bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly return BluetoothAdapter.SCAN_MODE_NONE; 20699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 20709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 20719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* package */ static String scanModeToBluezString(int mode) { 20729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project switch (mode) { 2073bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly case BluetoothAdapter.SCAN_MODE_NONE: 20749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return "off"; 2075bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly case BluetoothAdapter.SCAN_MODE_CONNECTABLE: 20769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return "connectable"; 2077bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly case BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE: 20789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return "discoverable"; 20799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 20809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return null; 20819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 20829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2083d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh /*package*/ String getAddressFromObjectPath(String objectPath) { 2084b148bc844e5eddb07bef2fd1b4b754716decb43eJaikumar Ganesh String adapterObjectPath = getPropertyInternal("ObjectPath"); 2085d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh if (adapterObjectPath == null || objectPath == null) { 2086d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh Log.e(TAG, "getAddressFromObjectPath: AdpaterObjectPath:" + adapterObjectPath + 2087d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh " or deviceObjectPath:" + objectPath + " is null"); 2088d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh return null; 2089d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh } 2090d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh if (!objectPath.startsWith(adapterObjectPath)) { 2091d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh Log.e(TAG, "getAddressFromObjectPath: AdpaterObjectPath:" + adapterObjectPath + 2092d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh " is not a prefix of deviceObjectPath:" + objectPath + 2093d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh "bluetoothd crashed ?"); 2094d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh return null; 2095d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh } 2096d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh String address = objectPath.substring(adapterObjectPath.length()); 2097d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh if (address != null) return address.replace('_', ':'); 2098d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh 2099d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh Log.e(TAG, "getAddressFromObjectPath: Address being returned is null"); 2100d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh return null; 2101d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh } 2102d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh 2103d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh /*package*/ String getObjectPathFromAddress(String address) { 2104b148bc844e5eddb07bef2fd1b4b754716decb43eJaikumar Ganesh String path = getPropertyInternal("ObjectPath"); 2105d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh if (path == null) { 2106d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh Log.e(TAG, "Error: Object Path is null"); 2107d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh return null; 2108d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh } 2109d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh path = path + address.replace(":", "_"); 2110d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh return path; 2111d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh } 2112d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh 2113b7e029d03c115ed65cdea9b2bba307e882c308e2Jaikumar Ganesh /*package */ void setLinkTimeout(String address, int num_slots) { 2114b7e029d03c115ed65cdea9b2bba307e882c308e2Jaikumar Ganesh String path = getObjectPathFromAddress(address); 2115b7e029d03c115ed65cdea9b2bba307e882c308e2Jaikumar Ganesh boolean result = setLinkTimeoutNative(path, num_slots); 2116b7e029d03c115ed65cdea9b2bba307e882c308e2Jaikumar Ganesh 2117b7e029d03c115ed65cdea9b2bba307e882c308e2Jaikumar Ganesh if (!result) log("Set Link Timeout to:" + num_slots + " slots failed"); 2118b7e029d03c115ed65cdea9b2bba307e882c308e2Jaikumar Ganesh } 2119b7e029d03c115ed65cdea9b2bba307e882c308e2Jaikumar Ganesh 21209b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh public boolean connectHeadset(String address) { 2121f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh BluetoothDeviceProfileState state = mDeviceProfileState.get(address); 21229b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh if (state != null) { 2123f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh Message msg = new Message(); 2124f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh msg.arg1 = BluetoothDeviceProfileState.CONNECT_HFP_OUTGOING; 2125f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh msg.obj = state; 2126f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh mHfpProfileState.sendMessage(msg); 2127f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh return true; 21289b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh } 21299b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh return false; 21309b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh } 21319b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh 21329b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh public boolean disconnectHeadset(String address) { 2133f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh BluetoothDeviceProfileState state = mDeviceProfileState.get(address); 21349b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh if (state != null) { 2135f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh Message msg = new Message(); 2136f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh msg.arg1 = BluetoothDeviceProfileState.DISCONNECT_HFP_OUTGOING; 2137f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh msg.obj = state; 2138f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh mHfpProfileState.sendMessage(msg); 21399b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh return true; 21409b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh } 21419b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh return false; 21429b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh } 21439b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh 21449b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh public boolean connectSink(String address) { 2145f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh BluetoothDeviceProfileState state = mDeviceProfileState.get(address); 21469b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh if (state != null) { 2147f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh Message msg = new Message(); 2148f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh msg.arg1 = BluetoothDeviceProfileState.CONNECT_A2DP_OUTGOING; 2149f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh msg.obj = state; 2150f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh mA2dpProfileState.sendMessage(msg); 2151f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh return true; 21529b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh } 21539b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh return false; 21549b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh } 21559b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh 21569b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh public boolean disconnectSink(String address) { 2157f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh BluetoothDeviceProfileState state = mDeviceProfileState.get(address); 21589b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh if (state != null) { 2159f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh Message msg = new Message(); 2160f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh msg.arg1 = BluetoothDeviceProfileState.DISCONNECT_A2DP_OUTGOING; 2161f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh msg.obj = state; 2162f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh mA2dpProfileState.sendMessage(msg); 21639b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh return true; 21649b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh } 21659b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh return false; 21669b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh } 21679b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh 2168f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh private BluetoothDeviceProfileState addProfileState(String address) { 2169f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh BluetoothDeviceProfileState state = mDeviceProfileState.get(address); 21709b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh if (state != null) return state; 21719b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh 2172f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh state = new BluetoothDeviceProfileState(mContext, address, this, mA2dpService); 2173f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh mDeviceProfileState.put(address, state); 21749b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh state.start(); 21759b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh return state; 21769b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh } 21779b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh 21789b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh private void removeProfileState(String address) { 2179f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh mDeviceProfileState.remove(address); 21809b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh } 21819b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh 21829b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh private void initProfileState() { 21839b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh String []bonds = null; 21849b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh String val = getPropertyInternal("Devices"); 21859b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh if (val != null) { 21869b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh bonds = val.split(","); 21879b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh } 21889b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh if (bonds == null) { 21899b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh return; 21909b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh } 21919b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh 21929b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh for (String path : bonds) { 21939b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh String address = getAddressFromObjectPath(path); 2194f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh BluetoothDeviceProfileState state = addProfileState(address); 21959b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh // Allow 8 secs for SDP records to get registered. 21969b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh Message msg = new Message(); 2197f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh msg.what = BluetoothDeviceProfileState.AUTO_CONNECT_PROFILES; 21989b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh state.sendMessageDelayed(msg, 8000); 21999b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh } 22009b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh } 22019b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh 22029b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh public boolean notifyIncomingConnection(String address) { 2203f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh BluetoothDeviceProfileState state = 2204f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh mDeviceProfileState.get(address); 22059b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh if (state != null) { 22069b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh Message msg = new Message(); 2207f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh msg.what = BluetoothDeviceProfileState.CONNECT_HFP_INCOMING; 22089b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh state.sendMessage(msg); 22099b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh return true; 22109b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh } 22119b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh return false; 22129b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh } 22139b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh 22149b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh /*package*/ boolean notifyIncomingA2dpConnection(String address) { 2215f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh BluetoothDeviceProfileState state = 2216f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh mDeviceProfileState.get(address); 22179b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh if (state != null) { 22189b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh Message msg = new Message(); 2219f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh msg.what = BluetoothDeviceProfileState.CONNECT_A2DP_INCOMING; 22209b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh state.sendMessage(msg); 22219b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh return true; 22229b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh } 22239b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh return false; 22249b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh } 22259b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh 22269b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh /*package*/ void setA2dpService(BluetoothA2dpService a2dpService) { 22279b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh mA2dpService = a2dpService; 22289b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh } 22299b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh 22309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static void log(String msg) { 22319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.d(TAG, msg); 22329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2233d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh 2234d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh private native static void classInitNative(); 2235d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh private native void initializeNativeDataNative(); 2236d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh private native boolean setupNativeDataNative(); 2237d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh private native boolean tearDownNativeDataNative(); 2238d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh private native void cleanupNativeDataNative(); 2239d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh private native String getAdapterPathNative(); 2240d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh 2241d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh private native int isEnabledNative(); 2242d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh private native int enableNative(); 2243d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh private native int disableNative(); 2244d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh 2245d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh private native Object[] getAdapterPropertiesNative(); 2246d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh private native Object[] getDevicePropertiesNative(String objectPath); 2247d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh private native boolean setAdapterPropertyStringNative(String key, String value); 2248d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh private native boolean setAdapterPropertyIntegerNative(String key, int value); 2249d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh private native boolean setAdapterPropertyBooleanNative(String key, int value); 2250d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh 2251d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh private native boolean startDiscoveryNative(); 2252d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh private native boolean stopDiscoveryNative(); 2253d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh 2254d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh private native boolean createPairedDeviceNative(String address, int timeout_ms); 2255cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh private native boolean createPairedDeviceOutOfBandNative(String address, int timeout_ms); 2256cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh private native byte[] readAdapterOutOfBandDataNative(); 2257cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh 2258d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh private native boolean cancelDeviceCreationNative(String address); 2259d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh private native boolean removeDeviceNative(String objectPath); 2260d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh private native int getDeviceServiceChannelNative(String objectPath, String uuid, 2261d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh int attributeId); 2262d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh 2263b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh private native boolean cancelPairingUserInputNative(String address, int nativeData); 2264d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh private native boolean setPinNative(String address, String pin, int nativeData); 2265b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh private native boolean setPasskeyNative(String address, int passkey, int nativeData); 2266b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh private native boolean setPairingConfirmationNative(String address, boolean confirm, 2267b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh int nativeData); 2268cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh private native boolean setRemoteOutOfBandDataNative(String address, byte[] hash, 2269cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh byte[] randomizer, int nativeData); 2270cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh 227124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly private native boolean setDevicePropertyBooleanNative(String objectPath, String key, 227224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly int value); 22731caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh private native boolean createDeviceNative(String address); 227416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly /*package*/ native boolean discoverServicesNative(String objectPath, String pattern); 227510eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh 227624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly private native int addRfcommServiceRecordNative(String name, long uuidMsb, long uuidLsb, 227724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly short channel); 227824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly private native boolean removeServiceRecordNative(int handle); 2279b7e029d03c115ed65cdea9b2bba307e882c308e2Jaikumar Ganesh private native boolean setLinkTimeoutNative(String path, int num_slots); 22809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 2281