BluetoothService.java revision 7d0548d0944e48421857de4aec2822ced325bea0
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; 326fdd0c6274c81b337ad35b70480f881daf7354c3Danica Changimport android.bluetooth.BluetoothPan; 3396a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganeshimport android.bluetooth.BluetoothProfile; 34f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganeshimport android.bluetooth.BluetoothProfileState; 35545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganeshimport android.bluetooth.BluetoothInputDevice; 3624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pellyimport android.bluetooth.BluetoothSocket; 3710eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganeshimport android.bluetooth.BluetoothUuid; 38bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pellyimport android.bluetooth.IBluetooth; 3916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pellyimport android.bluetooth.IBluetoothCallback; 409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.BroadcastReceiver; 419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.ContentResolver; 429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Context; 439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Intent; 449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.IntentFilter; 456e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganeshimport android.content.SharedPreferences; 46707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganeshimport android.content.res.Resources.NotFoundException; 476fdd0c6274c81b337ad35b70480f881daf7354c3Danica Changimport android.net.ConnectivityManager; 486fdd0c6274c81b337ad35b70480f881daf7354c3Danica Changimport android.net.InterfaceConfiguration; 499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Binder; 509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Handler; 513fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganeshimport android.os.IBinder; 526fdd0c6274c81b337ad35b70480f881daf7354c3Danica Changimport android.os.INetworkManagementService; 539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Message; 543fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganeshimport android.os.ParcelUuid; 559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.RemoteException; 56105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Projectimport android.os.ServiceManager; 579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.SystemService; 589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.provider.Settings; 599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.Log; 60cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganeshimport android.util.Pair; 619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 62d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganeshimport com.android.internal.app.IBatteryStats; 63d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh 643fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganeshimport java.io.BufferedInputStream; 65c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganeshimport java.io.BufferedReader; 663fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganeshimport java.io.BufferedWriter; 67c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganeshimport java.io.DataInputStream; 68c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganeshimport java.io.File; 699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.FileDescriptor; 703fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganeshimport java.io.FileInputStream; 713fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganeshimport java.io.FileNotFoundException; 72c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganeshimport java.io.FileOutputStream; 733fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganeshimport java.io.FileWriter; 743fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganeshimport java.io.IOException; 75c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganeshimport java.io.InputStreamReader; 769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.PrintWriter; 779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.UnsupportedEncodingException; 789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.ArrayList; 799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.Arrays; 809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.HashMap; 81545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganeshimport java.util.HashSet; 8216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pellyimport java.util.Iterator; 839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.Map; 84545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganeshimport java.util.Set; 859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 86bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pellypublic class BluetoothService extends IBluetooth.Stub { 87bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly private static final String TAG = "BluetoothService"; 889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final boolean DBG = true; 899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mNativeData; 919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private BluetoothEventLoop mEventLoop; 9296a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh private BluetoothHeadset mBluetoothHeadset; 939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private boolean mIsAirplaneSensitive; 9444303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey private boolean mIsAirplaneToggleable; 95105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project private int mBluetoothState; 96997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly private boolean mRestart = false; // need to call enable() after disable() 97bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly private boolean mIsDiscovering; 986fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang private boolean mTetheringOn; 99997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly 100bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly private BluetoothAdapter mAdapter; // constant after init() 101997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly private final BondState mBondState = new BondState(); // local cache of bondings 102105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project private final IBatteryStats mBatteryStats; 1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private final Context mContext; 1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final String BLUETOOTH_ADMIN_PERM = android.Manifest.permission.BLUETOOTH_ADMIN; 1069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final String BLUETOOTH_PERM = android.Manifest.permission.BLUETOOTH; 1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1083fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh private static final String DOCK_ADDRESS_PATH = "/sys/class/switch/dock/bt_addr"; 1093fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh private static final String DOCK_PIN_PATH = "/sys/class/switch/dock/bt_pin"; 1103fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh 1116e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh private static final String SHARED_PREFERENCE_DOCK_ADDRESS = "dock_bluetooth_address"; 1126e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh private static final String SHARED_PREFERENCES_NAME = "bluetooth_service_settings"; 1136e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh 114105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project private static final int MESSAGE_REGISTER_SDP_RECORDS = 1; 115105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project private static final int MESSAGE_FINISH_DISABLE = 2; 1161caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh private static final int MESSAGE_UUID_INTENT = 3; 11712835478ee687a493d1b5882e67b6725bd539c26Nick Pelly private static final int MESSAGE_DISCOVERABLE_TIMEOUT = 4; 118a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh private static final int MESSAGE_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY = 5; 119a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh 120a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh // The time (in millisecs) to delay the pairing attempt after the first 121a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh // auto pairing attempt fails. We use an exponential delay with 122a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh // INIT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY as the initial value and 123a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh // MAX_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY as the max value. 124a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh private static final long INIT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY = 3000; 125a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh private static final long MAX_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY = 12000; 1261caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh 1276fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang private ArrayList<String> mBluetoothIfaceAddresses; 128707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh private int mMaxPanDevices; 129707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh 130707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh private static final String BLUETOOTH_IFACE_ADDR_START= "192.168.44.1"; 131707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh private static final int BLUETOOTH_MAX_PAN_CONNECTIONS = 5; 1326fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang private static final String BLUETOOTH_NETMASK = "255.255.255.0"; 1336fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang 1341caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh // The timeout used to sent the UUIDs Intent 1351caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh // This timeout should be greater than the page timeout 1361caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh private static final int UUID_INTENT_DELAY = 6000; 137105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project 13816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly /** Always retrieve RFCOMM channel for these SDP UUIDs */ 13916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly private static final ParcelUuid[] RFCOMM_UUIDS = { 14016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly BluetoothUuid.Handsfree, 14116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly BluetoothUuid.HSP, 14216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly BluetoothUuid.ObexObjectPush }; 14316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly 1449b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh // TODO(): Optimize all these string handling 145bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly private final Map<String, String> mAdapterProperties; 14616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly private final HashMap<String, Map<String, String>> mDeviceProperties; 147d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh 14816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly private final HashMap<String, Map<ParcelUuid, Integer>> mDeviceServiceChannelCache; 14916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly private final ArrayList<String> mUuidIntentTracker; 15016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly private final HashMap<RemoteService, IBluetoothCallback> mUuidCallbackTracker; 1511caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh 15224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly private final HashMap<Integer, Integer> mServiceRecordToPid; 15324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly 154f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh private final HashMap<String, BluetoothDeviceProfileState> mDeviceProfileState; 155f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh private final BluetoothProfileState mA2dpProfileState; 156f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh private final BluetoothProfileState mHfpProfileState; 157de07503a382e81ba82f4cd4dee81ff2fbf3295bcJaikumar Ganesh private final BluetoothProfileState mHidProfileState; 1589b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh 1599b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh private BluetoothA2dpService mA2dpService; 160545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh private final HashMap<BluetoothDevice, Integer> mInputDevices; 161707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh private final HashMap<BluetoothDevice, Pair<Integer, String>> mPanDevices; 162cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh private final HashMap<String, Pair<byte[], byte[]>> mDeviceOobData; 163545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh 164707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh 1653fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh private static String mDockAddress; 1663fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh private String mDockPin; 1673fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh 16816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly private static class RemoteService { 16916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly public String address; 17016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly public ParcelUuid uuid; 17116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly public RemoteService(String address, ParcelUuid uuid) { 17216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly this.address = address; 17316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly this.uuid = uuid; 17416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } 17516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly @Override 17616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly public boolean equals(Object o) { 17716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly if (o instanceof RemoteService) { 17816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly RemoteService service = (RemoteService)o; 17916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly return address.equals(service.address) && uuid.equals(service.uuid); 18016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } 18116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly return false; 18216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } 1835f61416305c47c4db0b94c0cf500e9a9d11d4cdbKenny Root 1845f61416305c47c4db0b94c0cf500e9a9d11d4cdbKenny Root @Override 1855f61416305c47c4db0b94c0cf500e9a9d11d4cdbKenny Root public int hashCode() { 1865f61416305c47c4db0b94c0cf500e9a9d11d4cdbKenny Root int hash = 1; 1875f61416305c47c4db0b94c0cf500e9a9d11d4cdbKenny Root hash = hash * 31 + (address == null ? 0 : address.hashCode()); 1885f61416305c47c4db0b94c0cf500e9a9d11d4cdbKenny Root hash = hash * 31 + (uuid == null ? 0 : uuid.hashCode()); 1895f61416305c47c4db0b94c0cf500e9a9d11d4cdbKenny Root return hash; 1905f61416305c47c4db0b94c0cf500e9a9d11d4cdbKenny Root } 19116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } 19216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly 1939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project static { 1949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project classInitNative(); 1959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 197bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly public BluetoothService(Context context) { 1989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mContext = context; 199105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project 200105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project // Need to do this in place of: 201105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project // mBatteryStats = BatteryStatsService.getService(); 202105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project // Since we can not import BatteryStatsService from here. This class really needs to be 203105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project // moved to java/services/com/android/server/ 204105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService("batteryinfo")); 2059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project initializeNativeDataNative(); 207ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project 208ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project if (isEnabledNative() == 1) { 209ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project Log.w(TAG, "Bluetooth daemons already running - runtime restart? "); 210ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project disableNative(); 2119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 212ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project 213de893f550301a60274e87aa8168225e7a7a42184Nick Pelly mBluetoothState = BluetoothAdapter.STATE_OFF; 2149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mIsDiscovering = false; 2156fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang mTetheringOn = false; 216bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly mAdapterProperties = new HashMap<String, String>(); 217bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly mDeviceProperties = new HashMap<String, Map<String,String>>(); 21810eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh 21910eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh mDeviceServiceChannelCache = new HashMap<String, Map<ParcelUuid, Integer>>(); 220cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh mDeviceOobData = new HashMap<String, Pair<byte[], byte[]>>(); 2211caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh mUuidIntentTracker = new ArrayList<String>(); 22216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly mUuidCallbackTracker = new HashMap<RemoteService, IBluetoothCallback>(); 22324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly mServiceRecordToPid = new HashMap<Integer, Integer>(); 224f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh mDeviceProfileState = new HashMap<String, BluetoothDeviceProfileState>(); 225f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh mA2dpProfileState = new BluetoothProfileState(mContext, BluetoothProfileState.A2DP); 226f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh mHfpProfileState = new BluetoothProfileState(mContext, BluetoothProfileState.HFP); 227de07503a382e81ba82f4cd4dee81ff2fbf3295bcJaikumar Ganesh mHidProfileState = new BluetoothProfileState(mContext, BluetoothProfileState.HID); 228f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh 229707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh mBluetoothIfaceAddresses = new ArrayList<String>(); 230707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh try { 231707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh mMaxPanDevices = context.getResources().getInteger( 232707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh com.android.internal.R.integer.config_max_pan_devices); 233707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh } catch (NotFoundException e) { 234707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh mMaxPanDevices = BLUETOOTH_MAX_PAN_CONNECTIONS; 2356fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang } 2366fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang 237f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh mHfpProfileState.start(); 238f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh mA2dpProfileState.start(); 239de07503a382e81ba82f4cd4dee81ff2fbf3295bcJaikumar Ganesh mHidProfileState.start(); 2403fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh 2413fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh IntentFilter filter = new IntentFilter(); 2426e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh registerForAirplaneMode(filter); 2436e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh 2443fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh filter.addAction(Intent.ACTION_DOCK_EVENT); 2456e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh mContext.registerReceiver(mReceiver, filter); 246545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh mInputDevices = new HashMap<BluetoothDevice, Integer>(); 247707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh mPanDevices = new HashMap<BluetoothDevice, Pair<Integer, String>>(); 2483fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh } 2493fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh 2509b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh public static synchronized String readDockBluetoothAddress() { 2513fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh if (mDockAddress != null) return mDockAddress; 2523fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh 2533fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh BufferedInputStream file = null; 2543fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh String dockAddress; 2553fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh try { 2563fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh file = new BufferedInputStream(new FileInputStream(DOCK_ADDRESS_PATH)); 2573fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh byte[] address = new byte[17]; 2583fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh file.read(address); 2593fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh dockAddress = new String(address); 2603fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh dockAddress = dockAddress.toUpperCase(); 2613fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh if (BluetoothAdapter.checkBluetoothAddress(dockAddress)) { 2623fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh mDockAddress = dockAddress; 2633fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh return mDockAddress; 2643fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh } else { 2653fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh log("CheckBluetoothAddress failed for car dock address:" + dockAddress); 2663fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh } 2673fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh } catch (FileNotFoundException e) { 2683fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh log("FileNotFoundException while trying to read dock address"); 2693fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh } catch (IOException e) { 2703fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh log("IOException while trying to read dock address"); 2713fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh } finally { 2723fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh if (file != null) { 2733fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh try { 2743fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh file.close(); 2753fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh } catch (IOException e) { 2763fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh // Ignore 2773fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh } 2783fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh } 2793fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh } 2803fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh mDockAddress = null; 2813fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh return null; 2823fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh } 2833fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh 2843fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh private synchronized boolean writeDockPin() { 2853fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh BufferedWriter out = null; 2863fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh try { 2873fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh out = new BufferedWriter(new FileWriter(DOCK_PIN_PATH)); 2883fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh 2893fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh // Generate a random 4 digit pin between 0000 and 9999 2903fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh // This is not truly random but good enough for our purposes. 2913fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh int pin = (int) Math.floor(Math.random() * 10000); 2923fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh 2933fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh mDockPin = String.format("%04d", pin); 2943fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh out.write(mDockPin); 2953fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh return true; 2963fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh } catch (FileNotFoundException e) { 2973fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh log("FileNotFoundException while trying to write dock pairing pin"); 2983fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh } catch (IOException e) { 2993fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh log("IOException while while trying to write dock pairing pin"); 3003fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh } finally { 3013fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh if (out != null) { 3023fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh try { 3033fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh out.close(); 3043fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh } catch (IOException e) { 3053fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh // Ignore 3063fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh } 3073fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh } 3083fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh } 3093fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh mDockPin = null; 3103fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh return false; 3113fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh } 3123fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh 3133fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh /*package*/ synchronized String getDockPin() { 3143fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh return mDockPin; 315bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly } 316bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly 317bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly public synchronized void initAfterRegistration() { 318f242b7b931898856bcbcb7ec36cacf43098ba544Nick Pelly mAdapter = BluetoothAdapter.getDefaultAdapter(); 319bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly mEventLoop = new BluetoothEventLoop(mContext, mAdapter, this); 3209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3227d0548d0944e48421857de4aec2822ced325bea0Jaikumar Ganesh public synchronized void initAfterA2dpRegistration() { 3237d0548d0944e48421857de4aec2822ced325bea0Jaikumar Ganesh mEventLoop.getProfileProxy(); 3247d0548d0944e48421857de4aec2822ced325bea0Jaikumar Ganesh } 3257d0548d0944e48421857de4aec2822ced325bea0Jaikumar Ganesh 3269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 3279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project protected void finalize() throws Throwable { 3286e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh mContext.unregisterReceiver(mReceiver); 3299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 3309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project cleanupNativeDataNative(); 3319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } finally { 3329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project super.finalize(); 3339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean isEnabled() { 3379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 3388c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh return isEnabledInternal(); 3398c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh } 3408c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh 3418c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh private boolean isEnabledInternal() { 342de893f550301a60274e87aa8168225e7a7a42184Nick Pelly return mBluetoothState == BluetoothAdapter.STATE_ON; 3439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 345105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project public int getBluetoothState() { 346105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 347105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project return mBluetoothState; 348105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project } 349105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project 350105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project 3519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 3529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Bring down bluetooth and disable BT in settings. Returns true on success. 3539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 3549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean disable() { 3559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return disable(true); 3569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 3599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Bring down bluetooth. Returns true on success. 3609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 361e6ee3be1c254404dad842298f6f56c11cc6c7ac8Nick Pelly * @param saveSetting If true, persist the new setting 3629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 3639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public synchronized boolean disable(boolean saveSetting) { 364e6ee3be1c254404dad842298f6f56c11cc6c7ac8Nick Pelly mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH_ADMIN permission"); 3659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 366105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project switch (mBluetoothState) { 367de893f550301a60274e87aa8168225e7a7a42184Nick Pelly case BluetoothAdapter.STATE_OFF: 368105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project return true; 369de893f550301a60274e87aa8168225e7a7a42184Nick Pelly case BluetoothAdapter.STATE_ON: 370105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project break; 371105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project default: 372105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project return false; 373105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project } 3749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mEnableThread != null && mEnableThread.isAlive()) { 3759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 3769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 377de893f550301a60274e87aa8168225e7a7a42184Nick Pelly setBluetoothState(BluetoothAdapter.STATE_TURNING_OFF); 378bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly mHandler.removeMessages(MESSAGE_REGISTER_SDP_RECORDS); 379b70765cc27a174d1d4a0bab7062733ebd3eae354Jaikumar Ganesh setBluetoothTetheringNative(false, BluetoothPan.NAP_ROLE, BluetoothPan.NAP_BRIDGE); 380105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project 381105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project // Allow 3 seconds for profiles to gracefully disconnect 382105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project // TODO: Introduce a callback mechanism so that each profile can notify 383bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly // BluetoothService when it is done shutting down 384105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project mHandler.sendMessageDelayed( 385105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project mHandler.obtainMessage(MESSAGE_FINISH_DISABLE, saveSetting ? 1 : 0, 0), 3000); 386105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project return true; 387105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project } 388105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project 389105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project 390105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project private synchronized void finishDisable(boolean saveSetting) { 391de893f550301a60274e87aa8168225e7a7a42184Nick Pelly if (mBluetoothState != BluetoothAdapter.STATE_TURNING_OFF) { 392105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project return; 3939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mEventLoop.stop(); 395d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh tearDownNativeDataNative(); 3969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project disableNative(); 3979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // mark in progress bondings as cancelled 3999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (String address : mBondState.listInState(BluetoothDevice.BOND_BONDING)) { 400005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly mBondState.setBondState(address, BluetoothDevice.BOND_NONE, 4019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project BluetoothDevice.UNBOND_REASON_AUTH_CANCELED); 4029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // update mode 405de893f550301a60274e87aa8168225e7a7a42184Nick Pelly Intent intent = new Intent(BluetoothAdapter.ACTION_SCAN_MODE_CHANGED); 406de893f550301a60274e87aa8168225e7a7a42184Nick Pelly intent.putExtra(BluetoothAdapter.EXTRA_SCAN_MODE, BluetoothAdapter.SCAN_MODE_NONE); 4079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mContext.sendBroadcast(intent, BLUETOOTH_PERM); 4089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 409105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project mIsDiscovering = false; 410bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly mAdapterProperties.clear(); 41124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly mServiceRecordToPid.clear(); 412105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project 4139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (saveSetting) { 4149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project persistBluetoothOnSetting(false); 4159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 416105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project 417de893f550301a60274e87aa8168225e7a7a42184Nick Pelly setBluetoothState(BluetoothAdapter.STATE_OFF); 418105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project 419105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project // Log bluetooth off to battery stats. 420105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project long ident = Binder.clearCallingIdentity(); 421105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project try { 422105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project mBatteryStats.noteBluetoothOff(); 423105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project } catch (RemoteException e) { 424105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project } finally { 425105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project Binder.restoreCallingIdentity(ident); 426105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project } 427997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly 428997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly if (mRestart) { 429997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly mRestart = false; 430997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly enable(); 431997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly } 4329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 434105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project /** Bring up BT and persist BT on in settings */ 435105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project public boolean enable() { 436105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project return enable(true); 4379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 4409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Enable this Bluetooth device, asynchronously. 4419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * This turns on/off the underlying hardware. 4429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 443105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project * @param saveSetting If true, persist the new state of BT in settings 444105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project * @return True on success (so far) 4459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 446105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project public synchronized boolean enable(boolean saveSetting) { 4479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 4489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Need BLUETOOTH_ADMIN permission"); 4499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Airplane mode can prevent Bluetooth radio from being turned on. 45144303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey if (mIsAirplaneSensitive && isAirplaneModeOn() && !mIsAirplaneToggleable) { 4529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 4539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 454de893f550301a60274e87aa8168225e7a7a42184Nick Pelly if (mBluetoothState != BluetoothAdapter.STATE_OFF) { 4559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 4569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mEnableThread != null && mEnableThread.isAlive()) { 4589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 4599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 460de893f550301a60274e87aa8168225e7a7a42184Nick Pelly setBluetoothState(BluetoothAdapter.STATE_TURNING_ON); 461105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project mEnableThread = new EnableThread(saveSetting); 4629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mEnableThread.start(); 4639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 4649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 466997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly /** Forcibly restart Bluetooth if it is on */ 467997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly /* package */ synchronized void restart() { 468de893f550301a60274e87aa8168225e7a7a42184Nick Pelly if (mBluetoothState != BluetoothAdapter.STATE_ON) { 469997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly return; 470997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly } 471997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly mRestart = true; 472997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly if (!disable(false)) { 473997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly mRestart = false; 474997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly } 475d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh } 476997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly 477105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project private synchronized void setBluetoothState(int state) { 478105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project if (state == mBluetoothState) { 479105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project return; 480105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project } 481105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project 482105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project if (DBG) log("Bluetooth state " + mBluetoothState + " -> " + state); 483105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project 484de893f550301a60274e87aa8168225e7a7a42184Nick Pelly Intent intent = new Intent(BluetoothAdapter.ACTION_STATE_CHANGED); 485de893f550301a60274e87aa8168225e7a7a42184Nick Pelly intent.putExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, mBluetoothState); 486de893f550301a60274e87aa8168225e7a7a42184Nick Pelly intent.putExtra(BluetoothAdapter.EXTRA_STATE, state); 487105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 488105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project 489105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project mBluetoothState = state; 490105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project 491105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project mContext.sendBroadcast(intent, BLUETOOTH_PERM); 492105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project } 493105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project 4949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private final Handler mHandler = new Handler() { 4959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 4969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void handleMessage(Message msg) { 4979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project switch (msg.what) { 498105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project case MESSAGE_REGISTER_SDP_RECORDS: 4998c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh if (!isEnabledInternal()) { 500bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly return; 501bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly } 502bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly // SystemService.start() forks sdptool to register service 503bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly // records. It can fail to register some records if it is 504bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly // forked multiple times in a row, probably because there is 505bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly // some race in sdptool or bluez when operated in parallel. 506bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly // As a workaround, delay 500ms between each fork of sdptool. 507f51eadaf1f83abfe16a609a4ded6d789494689b2Jake Hamby // TODO: Don't fork sdptool in order to register service 508bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly // records, use a DBUS call instead. 509bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly switch (msg.arg1) { 510bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly case 1: 51177b4ad0e496941a28382eb938a05831f1f8d2d4aJaikumar Ganesh Log.d(TAG, "Registering hfag record"); 51277b4ad0e496941a28382eb938a05831f1f8d2d4aJaikumar Ganesh SystemService.start("hfag"); 513bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly mHandler.sendMessageDelayed( 514bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly mHandler.obtainMessage(MESSAGE_REGISTER_SDP_RECORDS, 2, -1), 500); 515bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly break; 516bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly case 2: 51777b4ad0e496941a28382eb938a05831f1f8d2d4aJaikumar Ganesh Log.d(TAG, "Registering hsag record"); 51877b4ad0e496941a28382eb938a05831f1f8d2d4aJaikumar Ganesh SystemService.start("hsag"); 519bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly mHandler.sendMessageDelayed( 520bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly mHandler.obtainMessage(MESSAGE_REGISTER_SDP_RECORDS, 3, -1), 500); 521bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly break; 522bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly case 3: 523bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly Log.d(TAG, "Registering opush record"); 52403c707ab6fc97e99b1603b8d6edc604dbea3cd6fNick Pelly SystemService.start("opush"); 525bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly mHandler.sendMessageDelayed( 526bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly mHandler.obtainMessage(MESSAGE_REGISTER_SDP_RECORDS, 4, -1), 500); 527bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly break; 528bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly case 4: 529bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly Log.d(TAG, "Registering pbap record"); 53067542964876aa7e4216e8f69f21dda68e7463b9aJaikumar Ganesh SystemService.start("pbap"); 531bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly break; 5329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 533105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project break; 534105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project case MESSAGE_FINISH_DISABLE: 535105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project finishDisable(msg.arg1 != 0); 536105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project break; 5371caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh case MESSAGE_UUID_INTENT: 5381caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh String address = (String)msg.obj; 53916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly if (address != null) { 5401caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh sendUuidIntent(address); 54116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly makeServiceChannelCallbacks(address); 54216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } 5431caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh break; 54412835478ee687a493d1b5882e67b6725bd539c26Nick Pelly case MESSAGE_DISCOVERABLE_TIMEOUT: 54512835478ee687a493d1b5882e67b6725bd539c26Nick Pelly int mode = msg.arg1; 5468c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh if (isEnabledInternal()) { 54712835478ee687a493d1b5882e67b6725bd539c26Nick Pelly // TODO: Switch back to the previous scan mode 54812835478ee687a493d1b5882e67b6725bd539c26Nick Pelly // This is ok for now, because we only use 54912835478ee687a493d1b5882e67b6725bd539c26Nick Pelly // CONNECTABLE and CONNECTABLE_DISCOVERABLE 55012835478ee687a493d1b5882e67b6725bd539c26Nick Pelly setScanMode(BluetoothAdapter.SCAN_MODE_CONNECTABLE, -1); 55112835478ee687a493d1b5882e67b6725bd539c26Nick Pelly } 55212835478ee687a493d1b5882e67b6725bd539c26Nick Pelly break; 553a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh case MESSAGE_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY: 554a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh address = (String)msg.obj; 555a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh if (address != null) { 556a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh createBond(address); 557a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh return; 558a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh } 559a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh break; 5609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project }; 5639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private EnableThread mEnableThread; 5659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private class EnableThread extends Thread { 5679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private final boolean mSaveSetting; 568105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project public EnableThread(boolean saveSetting) { 5699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mSaveSetting = saveSetting; 5709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void run() { 5729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean res = (enableNative() == 0); 5739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (res) { 574b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project int retryCount = 2; 575b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project boolean running = false; 576b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project while ((retryCount-- > 0) && !running) { 577b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project mEventLoop.start(); 578105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project // it may take a momement for the other thread to do its 579b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project // thing. Check periodically for a while. 580b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project int pollCount = 5; 581b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project while ((pollCount-- > 0) && !running) { 582b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project if (mEventLoop.isEventLoopRunning()) { 583b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project running = true; 584b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project break; 585b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project } 586b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project try { 587b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project Thread.sleep(100); 588b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project } catch (InterruptedException e) {} 589b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project } 590b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project } 591b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project if (!running) { 592b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project log("bt EnableThread giving up"); 593b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project res = false; 594b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project disableNative(); 595b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project } 5969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (res) { 600d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh if (!setupNativeDataNative()) { 601d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh return; 602d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh } 6039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mSaveSetting) { 6049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project persistBluetoothOnSetting(true); 6059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mIsDiscovering = false; 607c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh mBondState.readAutoPairingData(); 6089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mBondState.loadBondState(); 6099b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh initProfileState(); 610b70765cc27a174d1d4a0bab7062733ebd3eae354Jaikumar Ganesh 611b70765cc27a174d1d4a0bab7062733ebd3eae354Jaikumar Ganesh //Register SDP records. 612bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly mHandler.sendMessageDelayed( 613bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly mHandler.obtainMessage(MESSAGE_REGISTER_SDP_RECORDS, 1, -1), 3000); 614b70765cc27a174d1d4a0bab7062733ebd3eae354Jaikumar Ganesh setBluetoothTetheringNative(true, BluetoothPan.NAP_ROLE, BluetoothPan.NAP_BRIDGE); 615b70765cc27a174d1d4a0bab7062733ebd3eae354Jaikumar Ganesh 6169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 617105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project // Log bluetooth on to battery stats. 618105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project long ident = Binder.clearCallingIdentity(); 619105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project try { 620105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project mBatteryStats.noteBluetoothOn(); 621105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project } catch (RemoteException e) { 622105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project } finally { 623105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project Binder.restoreCallingIdentity(ident); 624105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project } 6259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 626105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project 627105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project mEnableThread = null; 628105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project 629105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project setBluetoothState(res ? 630de893f550301a60274e87aa8168225e7a7a42184Nick Pelly BluetoothAdapter.STATE_ON : 631de893f550301a60274e87aa8168225e7a7a42184Nick Pelly BluetoothAdapter.STATE_OFF); 632105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project 633b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project if (res) { 634105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project // Update mode 635d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh String[] propVal = {"Pairable", getProperty("Pairable")}; 636d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh mEventLoop.onPropertyChanged(propVal); 637b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project } 638b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project 63944303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey if (mIsAirplaneSensitive && isAirplaneModeOn() && !mIsAirplaneToggleable) { 6405c43f735d94a538dc273c8f859d1100a7cdd5c71Daisuke Miyakawa disable(false); 6415c43f735d94a538dc273c8f859d1100a7cdd5c71Daisuke Miyakawa } 6425c43f735d94a538dc273c8f859d1100a7cdd5c71Daisuke Miyakawa 6439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void persistBluetoothOnSetting(boolean bluetoothOn) { 6479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project long origCallerIdentityToken = Binder.clearCallingIdentity(); 6489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Settings.Secure.putInt(mContext.getContentResolver(), Settings.Secure.BLUETOOTH_ON, 6499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project bluetoothOn ? 1 : 0); 6509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Binder.restoreCallingIdentity(origCallerIdentityToken); 6519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 653a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh /*package*/ synchronized boolean attemptAutoPair(String address) { 654a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh if (!mBondState.hasAutoPairingFailed(address) && 655a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh !mBondState.isAutoPairingBlacklisted(address)) { 656a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh mBondState.attempt(address); 657a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh setPin(address, BluetoothDevice.convertPinToBytes("0000")); 658a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh return true; 659a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh } 660a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh return false; 661a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh } 662a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh 663a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh /*package*/ synchronized void onCreatePairedDeviceResult(String address, int result) { 664a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh if (result == BluetoothDevice.BOND_SUCCESS) { 665a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh setBondState(address, BluetoothDevice.BOND_BONDED); 666a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh if (mBondState.isAutoPairingAttemptsInProgress(address)) { 667a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh mBondState.clearPinAttempts(address); 668a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh } 669a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh } else if (result == BluetoothDevice.UNBOND_REASON_AUTH_FAILED && 670a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh mBondState.getAttempt(address) == 1) { 671a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh mBondState.addAutoPairingFailure(address); 672a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh pairingAttempt(address, result); 673a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh } else if (result == BluetoothDevice.UNBOND_REASON_REMOTE_DEVICE_DOWN && 674a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh mBondState.isAutoPairingAttemptsInProgress(address)) { 675a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh pairingAttempt(address, result); 676a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh } else { 677a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh setBondState(address, BluetoothDevice.BOND_NONE, result); 678a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh if (mBondState.isAutoPairingAttemptsInProgress(address)) { 679a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh mBondState.clearPinAttempts(address); 680a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh } 681a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh } 682a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh } 683a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh 684a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh /*package*/ synchronized String getPendingOutgoingBonding() { 685a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh return mBondState.getPendingOutgoingBonding(); 686a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh } 687a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh 688a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh private void pairingAttempt(String address, int result) { 689a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh // This happens when our initial guess of "0000" as the pass key 690a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh // fails. Try to create the bond again and display the pin dialog 691a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh // to the user. Use back-off while posting the delayed 692a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh // message. The initial value is 693a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh // INIT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY and the max value is 694a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh // MAX_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY. If the max value is 695a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh // reached, display an error to the user. 696a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh int attempt = mBondState.getAttempt(address); 697a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh if (attempt * INIT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY > 698a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh MAX_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY) { 699a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh mBondState.clearPinAttempts(address); 700a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh setBondState(address, BluetoothDevice.BOND_NONE, result); 701a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh return; 702a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh } 703a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh 704a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh Message message = mHandler.obtainMessage(MESSAGE_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY); 705a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh message.obj = address; 706a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh boolean postResult = mHandler.sendMessageDelayed(message, 707a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh attempt * INIT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY); 708a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh if (!postResult) { 709a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh mBondState.clearPinAttempts(address); 710a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh setBondState(address, 711a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh BluetoothDevice.BOND_NONE, result); 712a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh return; 713a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh } 714a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh mBondState.attempt(address); 7159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** local cache of bonding state. 7189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* we keep our own state to track the intermediate state BONDING, which 7199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* bluez does not track. 720f51eadaf1f83abfe16a609a4ded6d789494689b2Jake Hamby * All addresses must be passed in upper case. 7219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 7229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public class BondState { 7239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private final HashMap<String, Integer> mState = new HashMap<String, Integer>(); 7249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private final HashMap<String, Integer> mPinAttempt = new HashMap<String, Integer>(); 725c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh 726c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh private static final String AUTO_PAIRING_BLACKLIST = 727c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh "/etc/bluetooth/auto_pairing.conf"; 728c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh private static final String DYNAMIC_AUTO_PAIRING_BLACKLIST = 729c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh "/data/misc/bluetooth/dynamic_auto_pairing.conf"; 730c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh private ArrayList<String> mAutoPairingAddressBlacklist; 731c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh private ArrayList<String> mAutoPairingExactNameBlacklist; 732c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh private ArrayList<String> mAutoPairingPartialNameBlacklist; 733c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh // Addresses added to blacklist dynamically based on usage. 734c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh private ArrayList<String> mAutoPairingDynamicAddressBlacklist; 735c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh 736482d54bb0cd9e00fd929185c31fea3ad845d97bcJaikumar Ganesh 7372092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh // If this is an outgoing connection, store the address. 7382092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh // There can be only 1 pending outgoing connection at a time, 7392092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh private String mPendingOutgoingBonding; 7402092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh 7412092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh private synchronized void setPendingOutgoingBonding(String address) { 7422092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh mPendingOutgoingBonding = address; 7432092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh } 7442092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh 7452092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh public synchronized String getPendingOutgoingBonding() { 7462092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh return mPendingOutgoingBonding; 7472092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh } 7482092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh 7499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public synchronized void loadBondState() { 750de893f550301a60274e87aa8168225e7a7a42184Nick Pelly if (mBluetoothState != BluetoothAdapter.STATE_TURNING_ON) { 7519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 7529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 753d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh String []bonds = null; 754b148bc844e5eddb07bef2fd1b4b754716decb43eJaikumar Ganesh String val = getPropertyInternal("Devices"); 755d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh if (val != null) { 756d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh bonds = val.split(","); 757d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh } 7589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (bonds == null) { 7599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 7609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mState.clear(); 7629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (DBG) log("found " + bonds.length + " bonded devices"); 763d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh for (String device : bonds) { 764d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh mState.put(getAddressFromObjectPath(device).toUpperCase(), 765d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh BluetoothDevice.BOND_BONDED); 7669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public synchronized void setBondState(String address, int state) { 7709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project setBondState(address, state, 0); 7719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** reason is ignored unless state == BOND_NOT_BONDED */ 7749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public synchronized void setBondState(String address, int state, int reason) { 7759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int oldState = getBondState(address); 7769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (oldState == state) { 7779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 7789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7792092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh 7802092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh // Check if this was an pending outgoing bonding. 7812092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh // If yes, reset the state. 7822092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh if (oldState == BluetoothDevice.BOND_BONDING) { 7832092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh if (address.equals(mPendingOutgoingBonding)) { 7842092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh mPendingOutgoingBonding = null; 7852092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh } 7862092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh } 7872092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh 7889b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh if (state == BluetoothDevice.BOND_BONDED) { 7899b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh addProfileState(address); 7909b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh } else if (state == BluetoothDevice.BOND_NONE) { 7919b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh removeProfileState(address); 7929b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh } 7939b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh 794c3ee99d9eb7e8b4b20c2b8f1c548373e1017e0d3Jaikumar Ganesh // HID is handled by BluetoothService, other profiles 795c3ee99d9eb7e8b4b20c2b8f1c548373e1017e0d3Jaikumar Ganesh // will be handled by their respective services. 796c3ee99d9eb7e8b4b20c2b8f1c548373e1017e0d3Jaikumar Ganesh setInitialInputDevicePriority(mAdapter.getRemoteDevice(address), state); 797c3ee99d9eb7e8b4b20c2b8f1c548373e1017e0d3Jaikumar Ganesh 7989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (DBG) log(address + " bond state " + oldState + " -> " + state + " (" + 7999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project reason + ")"); 800005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly Intent intent = new Intent(BluetoothDevice.ACTION_BOND_STATE_CHANGED); 801005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mAdapter.getRemoteDevice(address)); 802005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly intent.putExtra(BluetoothDevice.EXTRA_BOND_STATE, state); 803005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly intent.putExtra(BluetoothDevice.EXTRA_PREVIOUS_BOND_STATE, oldState); 804005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly if (state == BluetoothDevice.BOND_NONE) { 8059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (reason <= 0) { 8069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.w(TAG, "setBondState() called to unbond device, but reason code is " + 8079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "invalid. Overriding reason code with BOND_RESULT_REMOVED"); 8089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project reason = BluetoothDevice.UNBOND_REASON_REMOVED; 8099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 810005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly intent.putExtra(BluetoothDevice.EXTRA_REASON, reason); 8119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mState.remove(address); 8129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 8139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mState.put(address, state); 8149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mContext.sendBroadcast(intent, BLUETOOTH_PERM); 8179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean isAutoPairingBlacklisted(String address) { 820c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh if (mAutoPairingAddressBlacklist != null) { 821c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh for (String blacklistAddress : mAutoPairingAddressBlacklist) { 822c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh if (address.startsWith(blacklistAddress)) return true; 823c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh } 8249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 825482d54bb0cd9e00fd929185c31fea3ad845d97bcJaikumar Ganesh 826c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh if (mAutoPairingDynamicAddressBlacklist != null) { 827c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh for (String blacklistAddress: mAutoPairingDynamicAddressBlacklist) { 828c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh if (address.equals(blacklistAddress)) return true; 829c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh } 830c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh } 831482d54bb0cd9e00fd929185c31fea3ad845d97bcJaikumar Ganesh String name = getRemoteName(address); 832482d54bb0cd9e00fd929185c31fea3ad845d97bcJaikumar Ganesh if (name != null) { 833c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh if (mAutoPairingExactNameBlacklist != null) { 834c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh for (String blacklistName : mAutoPairingExactNameBlacklist) { 835c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh if (name.equals(blacklistName)) return true; 836c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh } 837738ed80262aa26128924c51f59ffd49e1163eb8dJaikumar Ganesh } 838738ed80262aa26128924c51f59ffd49e1163eb8dJaikumar Ganesh 839c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh if (mAutoPairingPartialNameBlacklist != null) { 840c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh for (String blacklistName : mAutoPairingPartialNameBlacklist) { 841c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh if (name.startsWith(blacklistName)) return true; 842c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh } 843482d54bb0cd9e00fd929185c31fea3ad845d97bcJaikumar Ganesh } 844482d54bb0cd9e00fd929185c31fea3ad845d97bcJaikumar Ganesh } 8459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 8469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public synchronized int getBondState(String address) { 8499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Integer state = mState.get(address); 8509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (state == null) { 851005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly return BluetoothDevice.BOND_NONE; 8529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return state.intValue(); 8549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 856e5d93b7ed983f98855555d560faf060836f1a52fJaikumar Ganesh /*package*/ synchronized String[] listInState(int state) { 8579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ArrayList<String> result = new ArrayList<String>(mState.size()); 8589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (Map.Entry<String, Integer> e : mState.entrySet()) { 8599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (e.getValue().intValue() == state) { 8609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project result.add(e.getKey()); 8619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return result.toArray(new String[result.size()]); 8649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public synchronized void addAutoPairingFailure(String address) { 867c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh if (mAutoPairingDynamicAddressBlacklist == null) { 868c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh mAutoPairingDynamicAddressBlacklist = new ArrayList<String>(); 8699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 870c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh 871c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh updateAutoPairingData(address); 872c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh mAutoPairingDynamicAddressBlacklist.add(address); 8739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public synchronized boolean isAutoPairingAttemptsInProgress(String address) { 8769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return getAttempt(address) != 0; 8779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public synchronized void clearPinAttempts(String address) { 8809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPinAttempt.remove(address); 8819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public synchronized boolean hasAutoPairingFailed(String address) { 884c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh if (mAutoPairingDynamicAddressBlacklist == null) return false; 885c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh 886c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh return mAutoPairingDynamicAddressBlacklist.contains(address); 8879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public synchronized int getAttempt(String address) { 8909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Integer attempt = mPinAttempt.get(address); 8919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (attempt == null) { 8929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return 0; 8939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return attempt.intValue(); 8959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public synchronized void attempt(String address) { 8989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Integer attempt = mPinAttempt.get(address); 8999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int newAttempt; 9009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (attempt == null) { 9019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project newAttempt = 1; 9029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 9039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project newAttempt = attempt.intValue() + 1; 9049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPinAttempt.put(address, new Integer(newAttempt)); 9069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 908c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh private void copyAutoPairingData() { 909c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh File file = null; 910c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh FileInputStream in = null; 911c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh FileOutputStream out = null; 912c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh try { 913c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh file = new File(DYNAMIC_AUTO_PAIRING_BLACKLIST); 914c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh if (file.exists()) return; 915c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh 916c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh in = new FileInputStream(AUTO_PAIRING_BLACKLIST); 917c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh out= new FileOutputStream(DYNAMIC_AUTO_PAIRING_BLACKLIST); 918c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh 919c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh byte[] buf = new byte[1024]; 920c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh int len; 921c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh while ((len = in.read(buf)) > 0) { 922c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh out.write(buf, 0, len); 923c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh } 924c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh } catch (FileNotFoundException e) { 925c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh log("FileNotFoundException: in copyAutoPairingData"); 926c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh } catch (IOException e) { 927c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh log("IOException: in copyAutoPairingData"); 928c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh } finally { 929c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh try { 930c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh if (in != null) in.close(); 931c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh if (out != null) out.close(); 932c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh } catch (IOException e) {} 933c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh } 934c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh } 935c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh 936c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh public void readAutoPairingData() { 937c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh if (mAutoPairingAddressBlacklist != null) return; 938c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh copyAutoPairingData(); 939c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh FileInputStream fstream = null; 940c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh try { 941c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh fstream = new FileInputStream(DYNAMIC_AUTO_PAIRING_BLACKLIST); 942c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh DataInputStream in = new DataInputStream(fstream); 943c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh BufferedReader file = new BufferedReader(new InputStreamReader(in)); 944c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh String line; 945c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh while((line = file.readLine()) != null) { 946c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh line = line.trim(); 947c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh if (line.length() == 0 || line.startsWith("//")) continue; 948c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh String[] value = line.split("="); 949c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh if (value != null && value.length == 2) { 950c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh String[] val = value[1].split(","); 951c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh if (value[0].equalsIgnoreCase("AddressBlacklist")) { 952c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh mAutoPairingAddressBlacklist = 953c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh new ArrayList<String>(Arrays.asList(val)); 954c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh } else if (value[0].equalsIgnoreCase("ExactNameBlacklist")) { 955c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh mAutoPairingExactNameBlacklist = 956c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh new ArrayList<String>(Arrays.asList(val)); 957c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh } else if (value[0].equalsIgnoreCase("PartialNameBlacklist")) { 958c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh mAutoPairingPartialNameBlacklist = 959c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh new ArrayList<String>(Arrays.asList(val)); 960c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh } else if (value[0].equalsIgnoreCase("DynamicAddressBlacklist")) { 961c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh mAutoPairingDynamicAddressBlacklist = 962c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh new ArrayList<String>(Arrays.asList(val)); 963c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh } else { 964c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh Log.e(TAG, "Error parsing Auto pairing blacklist file"); 965c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh } 966c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh } 967c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh } 968c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh } catch (FileNotFoundException e) { 969c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh log("FileNotFoundException: readAutoPairingData" + e.toString()); 970c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh } catch (IOException e) { 971c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh log("IOException: readAutoPairingData" + e.toString()); 972c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh } finally { 973c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh if (fstream != null) { 974c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh try { 975c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh fstream.close(); 976c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh } catch (IOException e) { 977c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh // Ignore 978c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh } 979c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh } 980c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh } 981c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh } 982c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh 983f51eadaf1f83abfe16a609a4ded6d789494689b2Jake Hamby // This function adds a bluetooth address to the auto pairing blacklist 984c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh // file. These addresses are added to DynamicAddressBlacklistSection 985c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh private void updateAutoPairingData(String address) { 986c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh BufferedWriter out = null; 987c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh try { 988c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh out = new BufferedWriter(new FileWriter(DYNAMIC_AUTO_PAIRING_BLACKLIST, true)); 989c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh StringBuilder str = new StringBuilder(); 990c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh if (mAutoPairingDynamicAddressBlacklist.size() == 0) { 991c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh str.append("DynamicAddressBlacklist="); 992c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh } 993c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh str.append(address); 994c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh str.append(","); 995c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh out.write(str.toString()); 996c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh } catch (FileNotFoundException e) { 997c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh log("FileNotFoundException: updateAutoPairingData" + e.toString()); 998c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh } catch (IOException e) { 999c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh log("IOException: updateAutoPairingData" + e.toString()); 1000c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh } finally { 1001c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh if (out != null) { 1002c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh try { 1003c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh out.close(); 1004c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh } catch (IOException e) { 1005c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh // Ignore 1006c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh } 1007c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh } 1008c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh } 1009c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh } 10109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static String toBondStateString(int bondState) { 10139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project switch (bondState) { 1014005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly case BluetoothDevice.BOND_NONE: 10159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return "not bonded"; 10169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case BluetoothDevice.BOND_BONDING: 10179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return "bonding"; 10189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case BluetoothDevice.BOND_BONDED: 10199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return "bonded"; 10209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project default: 10219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return "??????"; 10229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10259519ce75f15ba287a641166c1b7ed10f2aa73f74Jaikumar Ganesh /*package*/ synchronized boolean isAdapterPropertiesEmpty() { 10269519ce75f15ba287a641166c1b7ed10f2aa73f74Jaikumar Ganesh return mAdapterProperties.isEmpty(); 10279519ce75f15ba287a641166c1b7ed10f2aa73f74Jaikumar Ganesh } 10289519ce75f15ba287a641166c1b7ed10f2aa73f74Jaikumar Ganesh 1029d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh /*package*/synchronized void getAllProperties() { 10308c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh 10319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1032bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly mAdapterProperties.clear(); 1033d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh 1034d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh String properties[] = (String [])getAdapterPropertiesNative(); 1035d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh // The String Array consists of key-value pairs. 1036d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh if (properties == null) { 1037d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh Log.e(TAG, "*Error*: GetAdapterProperties returned NULL"); 1038d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh return; 1039d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh } 1040d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh 10418bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh for (int i = 0; i < properties.length; i++) { 10428bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh String name = properties[i]; 1043efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh String newValue = null; 10448bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh int len; 10458bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh if (name == null) { 10468bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh Log.e(TAG, "Error:Adapter Property at index" + i + "is null"); 10478bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh continue; 10488bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh } 10497a9de8b425954e4039053038e4ec1762b866c83cDanica Chang if (name.equals("Devices") || name.equals("UUIDs")) { 1050efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh StringBuilder str = new StringBuilder(); 10518bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh len = Integer.valueOf(properties[++i]); 10528bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh for (int j = 0; j < len; j++) { 1053efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh str.append(properties[++i]); 1054efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh str.append(","); 1055efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh } 1056efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh if (len > 0) { 1057efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh newValue = str.toString(); 10588bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh } 10598bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh } else { 10608bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh newValue = properties[++i]; 10618bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh } 1062bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly mAdapterProperties.put(name, newValue); 1063d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh } 1064d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh 1065d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh // Add adapter object path property. 1066d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh String adapterPath = getAdapterPathNative(); 1067d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh if (adapterPath != null) 1068bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly mAdapterProperties.put("ObjectPath", adapterPath + "/dev_"); 10699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1071d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh /* package */ synchronized void setProperty(String name, String value) { 1072bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly mAdapterProperties.put(name, value); 10739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public synchronized boolean setName(String name) { 10769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 10779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Need BLUETOOTH_ADMIN permission"); 10789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (name == null) { 10799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 10809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1081d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh return setPropertyString("Name", name); 10829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1084d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh //TODO(): setPropertyString, setPropertyInteger, setPropertyBoolean 1085d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh // Either have a single property function with Object as the parameter 1086d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh // or have a function for each property and then obfuscate in the JNI layer. 1087d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh // The following looks dirty. 1088d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh private boolean setPropertyString(String key, String value) { 10899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 10908c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh if (!isEnabledInternal()) return false; 1091d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh return setAdapterPropertyStringNative(key, value); 10929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1094d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh private boolean setPropertyInteger(String key, int value) { 1095d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 10968c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh if (!isEnabledInternal()) return false; 1097d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh return setAdapterPropertyIntegerNative(key, value); 1098d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh } 10999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1100d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh private boolean setPropertyBoolean(String key, boolean value) { 1101d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 11028c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh if (!isEnabledInternal()) return false; 1103d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh return setAdapterPropertyBooleanNative(key, value ? 1 : 0); 11049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1106d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh /** 1107d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh * Set the discoverability window for the device. A timeout of zero 1108d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh * makes the device permanently discoverable (if the device is 1109d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh * discoverable). Setting the timeout to a nonzero value does not make 1110d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh * a device discoverable; you need to call setMode() to make the device 1111d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh * explicitly discoverable. 1112d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh * 1113f51eadaf1f83abfe16a609a4ded6d789494689b2Jake Hamby * @param timeout The discoverable timeout in seconds. 1114d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh */ 1115d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh public synchronized boolean setDiscoverableTimeout(int timeout) { 11169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 11179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Need BLUETOOTH_ADMIN permission"); 1118d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh return setPropertyInteger("DiscoverableTimeout", timeout); 11199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 112112835478ee687a493d1b5882e67b6725bd539c26Nick Pelly public synchronized boolean setScanMode(int mode, int duration) { 112218b1e79a123b979d25bfa5d0b0ee5d0382dbd64bNick Pelly mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS, 112318b1e79a123b979d25bfa5d0b0ee5d0382dbd64bNick Pelly "Need WRITE_SECURE_SETTINGS permission"); 1124de893f550301a60274e87aa8168225e7a7a42184Nick Pelly boolean pairable = false; 1125de893f550301a60274e87aa8168225e7a7a42184Nick Pelly boolean discoverable = false; 112612835478ee687a493d1b5882e67b6725bd539c26Nick Pelly 1127de893f550301a60274e87aa8168225e7a7a42184Nick Pelly switch (mode) { 1128de893f550301a60274e87aa8168225e7a7a42184Nick Pelly case BluetoothAdapter.SCAN_MODE_NONE: 112912835478ee687a493d1b5882e67b6725bd539c26Nick Pelly mHandler.removeMessages(MESSAGE_DISCOVERABLE_TIMEOUT); 1130d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh pairable = false; 1131d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh discoverable = false; 1132de893f550301a60274e87aa8168225e7a7a42184Nick Pelly break; 1133de893f550301a60274e87aa8168225e7a7a42184Nick Pelly case BluetoothAdapter.SCAN_MODE_CONNECTABLE: 113412835478ee687a493d1b5882e67b6725bd539c26Nick Pelly mHandler.removeMessages(MESSAGE_DISCOVERABLE_TIMEOUT); 1135d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh pairable = true; 1136d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh discoverable = false; 1137005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly break; 1138de893f550301a60274e87aa8168225e7a7a42184Nick Pelly case BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE: 113912835478ee687a493d1b5882e67b6725bd539c26Nick Pelly mHandler.removeMessages(MESSAGE_DISCOVERABLE_TIMEOUT); 1140d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh pairable = true; 1141d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh discoverable = true; 114212835478ee687a493d1b5882e67b6725bd539c26Nick Pelly Message msg = mHandler.obtainMessage(MESSAGE_DISCOVERABLE_TIMEOUT); 114312835478ee687a493d1b5882e67b6725bd539c26Nick Pelly mHandler.sendMessageDelayed(msg, duration * 1000); 114412835478ee687a493d1b5882e67b6725bd539c26Nick Pelly if (DBG) Log.d(TAG, "BT Discoverable for " + duration + " seconds"); 1145005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly break; 1146de893f550301a60274e87aa8168225e7a7a42184Nick Pelly default: 1147de893f550301a60274e87aa8168225e7a7a42184Nick Pelly Log.w(TAG, "Requested invalid scan mode " + mode); 1148de893f550301a60274e87aa8168225e7a7a42184Nick Pelly return false; 1149d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh } 1150d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh setPropertyBoolean("Pairable", pairable); 1151d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh setPropertyBoolean("Discoverable", discoverable); 11529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1153d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh return true; 11549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1156b148bc844e5eddb07bef2fd1b4b754716decb43eJaikumar Ganesh /*package*/ synchronized String getProperty(String name) { 1157b148bc844e5eddb07bef2fd1b4b754716decb43eJaikumar Ganesh if (!isEnabledInternal()) return null; 1158b148bc844e5eddb07bef2fd1b4b754716decb43eJaikumar Ganesh return getPropertyInternal(name); 1159b148bc844e5eddb07bef2fd1b4b754716decb43eJaikumar Ganesh } 1160b148bc844e5eddb07bef2fd1b4b754716decb43eJaikumar Ganesh 1161b148bc844e5eddb07bef2fd1b4b754716decb43eJaikumar Ganesh /*package*/ synchronized String getPropertyInternal(String name) { 1162bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly if (!mAdapterProperties.isEmpty()) 1163bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly return mAdapterProperties.get(name); 1164d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh getAllProperties(); 1165bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly return mAdapterProperties.get(name); 11669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1168d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh public synchronized String getAddress() { 1169d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1170d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh return getProperty("Address"); 11719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1173d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh public synchronized String getName() { 11749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1175d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh return getProperty("Name"); 11769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1179d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh * Returns the user-friendly name of a remote device. This value is 1180d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh * returned from our local cache, which is updated when onPropertyChange 1181d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh * event is received. 1182d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh * Do not expect to retrieve the updated remote name immediately after 1183d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh * changing the name on the remote device. 11849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 1185d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh * @param address Bluetooth address of remote device. 1186d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh * 1187d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh * @return The user-friendly name of the specified remote device. 11889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1189d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh public synchronized String getRemoteName(String address) { 1190d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1191005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly if (!BluetoothAdapter.checkBluetoothAddress(address)) { 1192d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh return null; 1193d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh } 119455929a958bf0e482c8e4d7df3dd75957f1e9d871Jaikumar Ganesh return getRemoteDeviceProperty(address, "Name"); 11959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 11989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Get the discoverability window for the device. A timeout of zero 11999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * means that the device is permanently discoverable (if the device is 12009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * in the discoverable mode). 12019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 12029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return The discoverability window of the device, in seconds. A negative 12039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * value indicates an error. 12049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 12059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public synchronized int getDiscoverableTimeout() { 12069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1207d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh String timeout = getProperty("DiscoverableTimeout"); 1208d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh if (timeout != null) 1209d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh return Integer.valueOf(timeout); 1210d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh else 1211d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh return -1; 12129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public synchronized int getScanMode() { 12159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 12168c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh if (!isEnabledInternal()) 1217de893f550301a60274e87aa8168225e7a7a42184Nick Pelly return BluetoothAdapter.SCAN_MODE_NONE; 1218d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh 1219d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh boolean pairable = getProperty("Pairable").equals("true"); 1220d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh boolean discoverable = getProperty("Discoverable").equals("true"); 1221d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh return bluezStringToScanMode (pairable, discoverable); 12229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1224d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh public synchronized boolean startDiscovery() { 12259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 12269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Need BLUETOOTH_ADMIN permission"); 12278c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh if (!isEnabledInternal()) return false; 12288c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh 1229d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh return startDiscoveryNative(); 12309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1232d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh public synchronized boolean cancelDiscovery() { 12339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 12349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Need BLUETOOTH_ADMIN permission"); 12358c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh if (!isEnabledInternal()) return false; 12368c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh 1237d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh return stopDiscoveryNative(); 1238d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh } 1239d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh 1240d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh public synchronized boolean isDiscovering() { 1241d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1242d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh return mIsDiscovering; 1243d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh } 1244d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh 1245d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh /* package */ void setIsDiscovering(boolean isDiscovering) { 1246d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh mIsDiscovering = isDiscovering; 12479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1249cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh private boolean isBondingFeasible(String address) { 12509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 12519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Need BLUETOOTH_ADMIN permission"); 12528c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh if (!isEnabledInternal()) return false; 12538c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh 1254005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly if (!BluetoothAdapter.checkBluetoothAddress(address)) { 12559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 12569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project address = address.toUpperCase(); 12589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12592092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh if (mBondState.getPendingOutgoingBonding() != null) { 12609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project log("Ignoring createBond(): another device is bonding"); 12619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // a different device is currently bonding, fail 12629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 12639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Check for bond state only if we are not performing auto 12669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // pairing exponential back-off attempts. 12679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!mBondState.isAutoPairingAttemptsInProgress(address) && 1268005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly mBondState.getBondState(address) != BluetoothDevice.BOND_NONE) { 12699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project log("Ignoring createBond(): this device is already bonding or bonded"); 12709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 12719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12733fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh if (address.equals(mDockAddress)) { 12743fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh if (!writeDockPin()) { 12753fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh log("Error while writing Pin for the dock"); 12763fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh return false; 12773fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh } 12783fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh } 1279cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh return true; 1280cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh } 12813fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh 1282cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh public synchronized boolean createBond(String address) { 1283cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh if (!isBondingFeasible(address)) return false; 1284cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh 1285cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh if (!createPairedDeviceNative(address, 60000 /*1 minute*/ )) { 12869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 12879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12892092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh mBondState.setPendingOutgoingBonding(address); 12909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mBondState.setBondState(address, BluetoothDevice.BOND_BONDING); 12912092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh 12929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 12939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1295cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh public synchronized boolean createBondOutOfBand(String address, byte[] hash, 1296cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh byte[] randomizer) { 1297cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh if (!isBondingFeasible(address)) return false; 12983fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh 1299cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh if (!createPairedDeviceOutOfBandNative(address, 60000 /* 1 minute */)) { 13009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 13019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1303cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh setDeviceOutOfBandData(address, hash, randomizer); 13042092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh mBondState.setPendingOutgoingBonding(address); 13059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mBondState.setBondState(address, BluetoothDevice.BOND_BONDING); 13062092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh 13079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 13089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1310cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh public synchronized boolean setDeviceOutOfBandData(String address, byte[] hash, 1311cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh byte[] randomizer) { 1312cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 1313cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh "Need BLUETOOTH_ADMIN permission"); 1314cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh if (!isEnabledInternal()) return false; 1315cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh 1316cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh Pair <byte[], byte[]> value = new Pair<byte[], byte[]>(hash, randomizer); 1317cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh 1318cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh if (DBG) { 1319cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh log("Setting out of band data for:" + address + ":" + 1320cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh Arrays.toString(hash) + ":" + Arrays.toString(randomizer)); 1321cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh } 1322cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh 1323cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh mDeviceOobData.put(address, value); 1324cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh return true; 1325cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh } 1326cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh 1327cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh Pair<byte[], byte[]> getDeviceOutOfBandData(BluetoothDevice device) { 1328cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh return mDeviceOobData.get(device.getAddress()); 1329cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh } 1330cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh 1331cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh 1332cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh public synchronized byte[] readOutOfBandData() { 1333cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, 1334cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh "Need BLUETOOTH permission"); 1335cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh if (!isEnabledInternal()) return null; 1336cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh 1337cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh return readAdapterOutOfBandDataNative(); 1338cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh } 1339cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh 13409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public synchronized boolean cancelBondProcess(String address) { 13419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 13429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Need BLUETOOTH_ADMIN permission"); 13438c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh if (!isEnabledInternal()) return false; 13448c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh 1345005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly if (!BluetoothAdapter.checkBluetoothAddress(address)) { 13469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 13479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project address = address.toUpperCase(); 13499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mBondState.getBondState(address) != BluetoothDevice.BOND_BONDING) { 13509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 13519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1353005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly mBondState.setBondState(address, BluetoothDevice.BOND_NONE, 13549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project BluetoothDevice.UNBOND_REASON_AUTH_CANCELED); 1355d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh cancelDeviceCreationNative(address); 13569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 13579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public synchronized boolean removeBond(String address) { 13609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 13619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Need BLUETOOTH_ADMIN permission"); 13628c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh if (!isEnabledInternal()) return false; 13638c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh 1364005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly if (!BluetoothAdapter.checkBluetoothAddress(address)) { 13659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 13669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1367f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh BluetoothDeviceProfileState state = mDeviceProfileState.get(address); 13689b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh if (state != null) { 1369f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh state.sendMessage(BluetoothDeviceProfileState.UNPAIR); 13709b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh return true; 13719b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh } else { 13729b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh return false; 13739b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh } 13749b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh } 13759b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh 13769b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh public synchronized boolean removeBondInternal(String address) { 1377d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh return removeDeviceNative(getObjectPathFromAddress(address)); 13789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public synchronized String[] listBonds() { 13819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 13829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mBondState.listInState(BluetoothDevice.BOND_BONDED); 13839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1385a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh /*package*/ synchronized String[] listInState(int state) { 1386a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh return mBondState.listInState(state); 1387a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh } 1388a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh 13899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public synchronized int getBondState(String address) { 13909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1391005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly if (!BluetoothAdapter.checkBluetoothAddress(address)) { 1392b24e11baac589fe16426f2d243b460ab84991c7bNick Pelly return BluetoothDevice.ERROR; 13939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mBondState.getBondState(address.toUpperCase()); 13959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1397a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh /*package*/ synchronized boolean setBondState(String address, int state) { 1398a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh return setBondState(address, state, 0); 1399a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh } 1400a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh 1401a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh /*package*/ synchronized boolean setBondState(String address, int state, int reason) { 1402a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh mBondState.setBondState(address.toUpperCase(), state); 1403a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh return true; 1404a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh } 1405a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh 14063fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh public synchronized boolean isBluetoothDock(String address) { 14076e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh SharedPreferences sp = mContext.getSharedPreferences(SHARED_PREFERENCES_NAME, 14086e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh mContext.MODE_PRIVATE); 14096e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh 14106e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh return sp.contains(SHARED_PREFERENCE_DOCK_ADDRESS + address); 14113fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh } 14123fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh 14136fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang public synchronized boolean isTetheringOn() { 14146fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang return mTetheringOn; 14156fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang } 14166fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang 1417707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh /*package*/ synchronized boolean allowIncomingTethering() { 1418707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh if (isTetheringOn() && getConnectedPanDevices().length < mMaxPanDevices) 1419707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh return true; 1420707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh return false; 1421707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh } 1422707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh 14238aac82a5248e922bac2f84df746b5d1f34498f53Danica Chang private BroadcastReceiver mTetheringReceiver = null; 14248aac82a5248e922bac2f84df746b5d1f34498f53Danica Chang 1425b70765cc27a174d1d4a0bab7062733ebd3eae354Jaikumar Ganesh public synchronized void setBluetoothTethering(boolean value) { 14266fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang if (!value) { 14276fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang disconnectPan(); 14286fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang } 14298aac82a5248e922bac2f84df746b5d1f34498f53Danica Chang 1430b70765cc27a174d1d4a0bab7062733ebd3eae354Jaikumar Ganesh if (getBluetoothState() != BluetoothAdapter.STATE_ON && value) { 14318aac82a5248e922bac2f84df746b5d1f34498f53Danica Chang IntentFilter filter = new IntentFilter(); 14328aac82a5248e922bac2f84df746b5d1f34498f53Danica Chang filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED); 14338aac82a5248e922bac2f84df746b5d1f34498f53Danica Chang mTetheringReceiver = new BroadcastReceiver() { 14348aac82a5248e922bac2f84df746b5d1f34498f53Danica Chang @Override 14358aac82a5248e922bac2f84df746b5d1f34498f53Danica Chang public synchronized void onReceive(Context context, Intent intent) { 14368aac82a5248e922bac2f84df746b5d1f34498f53Danica Chang if (intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.STATE_OFF) 14378aac82a5248e922bac2f84df746b5d1f34498f53Danica Chang == BluetoothAdapter.STATE_ON) { 1438b70765cc27a174d1d4a0bab7062733ebd3eae354Jaikumar Ganesh mTetheringOn = true; 14398aac82a5248e922bac2f84df746b5d1f34498f53Danica Chang mContext.unregisterReceiver(mTetheringReceiver); 14408aac82a5248e922bac2f84df746b5d1f34498f53Danica Chang } 14418aac82a5248e922bac2f84df746b5d1f34498f53Danica Chang } 14428aac82a5248e922bac2f84df746b5d1f34498f53Danica Chang }; 14438aac82a5248e922bac2f84df746b5d1f34498f53Danica Chang mContext.registerReceiver(mTetheringReceiver, filter); 14448aac82a5248e922bac2f84df746b5d1f34498f53Danica Chang } else { 1445b70765cc27a174d1d4a0bab7062733ebd3eae354Jaikumar Ganesh mTetheringOn = value; 14468aac82a5248e922bac2f84df746b5d1f34498f53Danica Chang } 14476fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang } 14486fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang 14496fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang public synchronized int getPanDeviceState(BluetoothDevice device) { 14506fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 14516fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang 1452707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh Pair<Integer, String> panDevice = mPanDevices.get(device); 1453707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh if (panDevice == null) { 14546fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang return BluetoothPan.STATE_DISCONNECTED; 14556fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang } 1456707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh return panDevice.first; 14576fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang } 14586fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang 14596fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang public synchronized boolean connectPanDevice(BluetoothDevice device) { 14606fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 14616fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang "Need BLUETOOTH_ADMIN permission"); 14626fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang 14636fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang String objectPath = getObjectPathFromAddress(device.getAddress()); 14646fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang if (DBG) log("connect PAN(" + objectPath + ")"); 14656fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang if (getPanDeviceState(device) != BluetoothPan.STATE_DISCONNECTED) { 14666fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang log (device + " already connected to PAN"); 14676fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang } 14686fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang 14696fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang int connectedCount = 0; 1470707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh for (BluetoothDevice panDevice: mPanDevices.keySet()) { 1471707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh if (getPanDeviceState(panDevice) == BluetoothPan.STATE_CONNECTED) { 14726fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang connectedCount ++; 14736fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang } 14746fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang } 14756fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang if (connectedCount > 8) { 14766fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang log (device + " could not connect to PAN because 8 other devices are already connected"); 14776fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang return false; 14786fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang } 14796fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang 14806fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang handlePanDeviceStateChange(device, BluetoothPan.STATE_CONNECTING); 14816fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang if (connectPanDeviceNative(objectPath, "nap", "panu")) { 14826fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang log ("connecting to PAN"); 14836fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang return true; 14846fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang } else { 14856fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang handlePanDeviceStateChange(device, BluetoothPan.STATE_DISCONNECTED); 14866fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang log ("could not connect to PAN"); 14876fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang return false; 14886fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang } 14896fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang } 14906fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang 14916fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang private synchronized boolean disconnectPan() { 14926fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 14936fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang if (DBG) log("disconnect all PAN devices"); 14946fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang 14956fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang for (BluetoothDevice device: mPanDevices.keySet()) { 14966fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang if (getPanDeviceState(device) == BluetoothPan.STATE_CONNECTED) { 14976fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang if (!disconnectPanDevice(device)) { 14986fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang log ("could not disconnect Pan Device "+device.getAddress()); 14996fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang return false; 15006fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang } 15016fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang } 15026fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang } 15036fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang return true; 15046fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang } 15056fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang 15066fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang public synchronized BluetoothDevice[] getConnectedPanDevices() { 15076fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 15086fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang 15096fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang Set<BluetoothDevice> devices = new HashSet<BluetoothDevice>(); 15106fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang for (BluetoothDevice device: mPanDevices.keySet()) { 15116fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang if (getPanDeviceState(device) == BluetoothPan.STATE_CONNECTED) { 15126fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang devices.add(device); 15136fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang } 15146fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang } 15156fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang return devices.toArray(new BluetoothDevice[devices.size()]); 15166fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang } 15176fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang 15186fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang public synchronized boolean disconnectPanDevice(BluetoothDevice device) { 15196fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 15206fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang "Need BLUETOOTH_ADMIN permission"); 15216fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang String objectPath = getObjectPathFromAddress(device.getAddress()); 15226fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang if (DBG) log("disconnect PAN(" + objectPath + ")"); 15236fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang if (getPanDeviceState(device) != BluetoothPan.STATE_CONNECTED) { 15246fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang log (device + " already disconnected from PAN"); 15256fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang } 15266fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang handlePanDeviceStateChange(device, BluetoothPan.STATE_DISCONNECTING); 15276fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang return disconnectPanDeviceNative(objectPath); 15286fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang } 15296fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang 1530707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh /*package*/ synchronized void handlePanDeviceStateChange(BluetoothDevice device, 1531707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh String iface, 1532707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh int state) { 15336fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang int prevState; 1534707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh String ifaceAddr = null; 1535707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh 15366fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang if (mPanDevices.get(device) == null) { 15376fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang prevState = BluetoothPan.STATE_DISCONNECTED; 15386fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang } else { 1539707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh prevState = mPanDevices.get(device).first; 1540707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh ifaceAddr = mPanDevices.get(device).second; 15416fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang } 15426fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang if (prevState == state) return; 15436fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang 15446fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang if (state == BluetoothPan.STATE_CONNECTED) { 1545707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh ifaceAddr = enableTethering(iface); 1546707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh if (ifaceAddr == null) Log.e(TAG, "Error seting up tether interface"); 1547707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh } else if (state == BluetoothPan.STATE_DISCONNECTED) { 1548707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh if (ifaceAddr != null) { 1549707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh mBluetoothIfaceAddresses.remove(ifaceAddr); 1550707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh ifaceAddr = null; 1551707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh } 15526fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang } 15536fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang 1554707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh Pair<Integer, String> value = new Pair<Integer, String>(state, ifaceAddr); 1555707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh mPanDevices.put(device, value); 1556707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh 15576fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang Intent intent = new Intent(BluetoothPan.ACTION_PAN_STATE_CHANGED); 15586fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); 15596fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang intent.putExtra(BluetoothPan.EXTRA_PREVIOUS_PAN_STATE, prevState); 15606fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang intent.putExtra(BluetoothPan.EXTRA_PAN_STATE, state); 15616fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang mContext.sendBroadcast(intent, BLUETOOTH_PERM); 15626fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang 15636fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang if (DBG) log("Pan Device state : device: " + device + " State:" + prevState + "->" + state); 1564707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh } 1565707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh 1566707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh /*package*/ synchronized void handlePanDeviceStateChange(BluetoothDevice device, 1567707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh int state) { 1568707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh handlePanDeviceStateChange(device, null, state); 1569707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh } 15706fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang 1571707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh private String createNewTetheringAddressLocked() { 1572707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh if (getConnectedPanDevices().length == mMaxPanDevices) { 1573707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh log("Max PAN device connections reached"); 1574707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh return null; 1575707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh } 1576707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh String address = BLUETOOTH_IFACE_ADDR_START; 1577707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh while (true) { 1578707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh if (mBluetoothIfaceAddresses.contains(address)) { 1579707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh String[] addr = address.split("\\."); 1580707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh Integer newIp = Integer.parseInt(addr[2]) + 1; 1581707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh address = address.replace(addr[2], newIp.toString()); 1582707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh } else { 1583707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh break; 1584707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh } 1585707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh } 1586707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh mBluetoothIfaceAddresses.add(address); 1587707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh return address; 15886fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang } 15896fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang 1590707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh // configured when we start tethering 1591707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh private synchronized String enableTethering(String iface) { 1592707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh log("updateTetherState:" + iface); 15936fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang 15946fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE); 15956fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang INetworkManagementService service = INetworkManagementService.Stub.asInterface(b); 15966fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang ConnectivityManager cm = 15976fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang (ConnectivityManager)mContext.getSystemService(Context.CONNECTIVITY_SERVICE); 15986fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang String[] bluetoothRegexs = cm.getTetherableBluetoothRegexs(); 15996fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang 16006fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang // bring toggle the interfaces 1601707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh String[] currentIfaces = new String[0]; 16026fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang try { 1603707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh currentIfaces = service.listInterfaces(); 16046fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang } catch (Exception e) { 16056fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang Log.e(TAG, "Error listing Interfaces :" + e); 1606707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh return null; 16076fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang } 16086fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang 1609707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh boolean found = false; 1610707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh for (String currIface: currentIfaces) { 1611707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh if (currIface.equals(iface)) { 1612707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh found = true; 1613707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh break; 16146fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang } 16156fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang } 16166fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang 1617707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh if (!found) return null; 1618707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh 1619707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh String address = createNewTetheringAddressLocked(); 1620707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh if (address == null) return null; 1621707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh 1622707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh InterfaceConfiguration ifcg = null; 1623707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh try { 1624707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh ifcg = service.getInterfaceConfig(iface); 1625707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh if (ifcg != null) { 1626707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh String[] addr = BLUETOOTH_NETMASK.split("\\."); 1627707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh ifcg.netmask = (Integer.parseInt(addr[0]) << 24) + 1628707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh (Integer.parseInt(addr[1]) << 16) + 1629707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh (Integer.parseInt(addr[2]) << 8) + 1630707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh (Integer.parseInt(addr[3])); 1631707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh if (ifcg.ipAddr == 0) { 1632707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh addr = address.split("\\."); 1633707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh 1634707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh ifcg.ipAddr = (Integer.parseInt(addr[0]) << 24) + 1635707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh (Integer.parseInt(addr[1]) << 16) + 1636707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh (Integer.parseInt(addr[2]) << 8) + 1637707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh (Integer.parseInt(addr[3])); 1638707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh ifcg.interfaceFlags = 1639707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh ifcg.interfaceFlags.replace("down", "up"); 1640707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh } 1641707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh ifcg.interfaceFlags = ifcg.interfaceFlags.replace("running", ""); 1642707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh ifcg.interfaceFlags = ifcg.interfaceFlags.replace(" "," "); 1643707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh service.setInterfaceConfig(iface, ifcg); 1644707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh if (cm.tether(iface) != ConnectivityManager.TETHER_ERROR_NO_ERROR) { 1645707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh Log.e(TAG, "Error tethering "+iface); 1646707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh } 1647707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh } 1648707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh } catch (Exception e) { 1649707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh Log.e(TAG, "Error configuring interface " + iface + ", :" + e); 1650707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh return null; 1651707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh } 1652707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh return address; 16536fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang } 16546fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang 1655545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh public synchronized boolean connectInputDevice(BluetoothDevice device) { 1656545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 1657545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh "Need BLUETOOTH_ADMIN permission"); 1658545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh 1659545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh String objectPath = getObjectPathFromAddress(device.getAddress()); 166005a1863cebcc8e318283f3f4a49ba69d83b62866Jaikumar Ganesh if (objectPath == null || 166105a1863cebcc8e318283f3f4a49ba69d83b62866Jaikumar Ganesh getInputDeviceState(device) != BluetoothInputDevice.STATE_DISCONNECTED || 1662545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh getInputDevicePriority(device) == BluetoothInputDevice.PRIORITY_OFF) { 1663545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh return false; 1664545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh } 1665de07503a382e81ba82f4cd4dee81ff2fbf3295bcJaikumar Ganesh BluetoothDeviceProfileState state = mDeviceProfileState.get(device.getAddress()); 1666de07503a382e81ba82f4cd4dee81ff2fbf3295bcJaikumar Ganesh if (state != null) { 1667de07503a382e81ba82f4cd4dee81ff2fbf3295bcJaikumar Ganesh Message msg = new Message(); 1668de07503a382e81ba82f4cd4dee81ff2fbf3295bcJaikumar Ganesh msg.arg1 = BluetoothDeviceProfileState.CONNECT_HID_OUTGOING; 1669de07503a382e81ba82f4cd4dee81ff2fbf3295bcJaikumar Ganesh msg.obj = state; 1670de07503a382e81ba82f4cd4dee81ff2fbf3295bcJaikumar Ganesh mHidProfileState.sendMessage(msg); 1671545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh return true; 1672545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh } 1673545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh return false; 1674545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh } 1675545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh 1676de07503a382e81ba82f4cd4dee81ff2fbf3295bcJaikumar Ganesh public synchronized boolean connectInputDeviceInternal(BluetoothDevice device) { 1677de07503a382e81ba82f4cd4dee81ff2fbf3295bcJaikumar Ganesh String objectPath = getObjectPathFromAddress(device.getAddress()); 1678de07503a382e81ba82f4cd4dee81ff2fbf3295bcJaikumar Ganesh handleInputDeviceStateChange(device, BluetoothInputDevice.STATE_CONNECTING); 1679de07503a382e81ba82f4cd4dee81ff2fbf3295bcJaikumar Ganesh if (!connectInputDeviceNative(objectPath)) { 1680de07503a382e81ba82f4cd4dee81ff2fbf3295bcJaikumar Ganesh handleInputDeviceStateChange(device, BluetoothInputDevice.STATE_DISCONNECTED); 1681de07503a382e81ba82f4cd4dee81ff2fbf3295bcJaikumar Ganesh return false; 1682de07503a382e81ba82f4cd4dee81ff2fbf3295bcJaikumar Ganesh } 1683de07503a382e81ba82f4cd4dee81ff2fbf3295bcJaikumar Ganesh return true; 1684de07503a382e81ba82f4cd4dee81ff2fbf3295bcJaikumar Ganesh } 1685de07503a382e81ba82f4cd4dee81ff2fbf3295bcJaikumar Ganesh 1686545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh public synchronized boolean disconnectInputDevice(BluetoothDevice device) { 1687545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 1688545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh "Need BLUETOOTH_ADMIN permission"); 1689545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh 1690545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh String objectPath = getObjectPathFromAddress(device.getAddress()); 1691545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh if (objectPath == null || getConnectedInputDevices().length == 0) { 1692545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh return false; 1693545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh } 1694de07503a382e81ba82f4cd4dee81ff2fbf3295bcJaikumar Ganesh BluetoothDeviceProfileState state = mDeviceProfileState.get(device.getAddress()); 1695de07503a382e81ba82f4cd4dee81ff2fbf3295bcJaikumar Ganesh if (state != null) { 1696de07503a382e81ba82f4cd4dee81ff2fbf3295bcJaikumar Ganesh Message msg = new Message(); 1697de07503a382e81ba82f4cd4dee81ff2fbf3295bcJaikumar Ganesh msg.arg1 = BluetoothDeviceProfileState.DISCONNECT_HID_OUTGOING; 1698de07503a382e81ba82f4cd4dee81ff2fbf3295bcJaikumar Ganesh msg.obj = state; 1699de07503a382e81ba82f4cd4dee81ff2fbf3295bcJaikumar Ganesh mHidProfileState.sendMessage(msg); 1700545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh return true; 1701545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh } 1702545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh return false; 1703545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh } 1704545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh 1705de07503a382e81ba82f4cd4dee81ff2fbf3295bcJaikumar Ganesh public synchronized boolean disconnectInputDeviceInternal(BluetoothDevice device) { 1706de07503a382e81ba82f4cd4dee81ff2fbf3295bcJaikumar Ganesh String objectPath = getObjectPathFromAddress(device.getAddress()); 1707de07503a382e81ba82f4cd4dee81ff2fbf3295bcJaikumar Ganesh handleInputDeviceStateChange(device, BluetoothInputDevice.STATE_DISCONNECTING); 1708de07503a382e81ba82f4cd4dee81ff2fbf3295bcJaikumar Ganesh if (!disconnectInputDeviceNative(objectPath)) { 1709de07503a382e81ba82f4cd4dee81ff2fbf3295bcJaikumar Ganesh handleInputDeviceStateChange(device, BluetoothInputDevice.STATE_CONNECTED); 1710de07503a382e81ba82f4cd4dee81ff2fbf3295bcJaikumar Ganesh return false; 1711de07503a382e81ba82f4cd4dee81ff2fbf3295bcJaikumar Ganesh } 1712de07503a382e81ba82f4cd4dee81ff2fbf3295bcJaikumar Ganesh return true; 1713de07503a382e81ba82f4cd4dee81ff2fbf3295bcJaikumar Ganesh } 1714de07503a382e81ba82f4cd4dee81ff2fbf3295bcJaikumar Ganesh 1715545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh public synchronized int getInputDeviceState(BluetoothDevice device) { 1716545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1717545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh 1718545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh if (mInputDevices.get(device) == null) { 1719545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh return BluetoothInputDevice.STATE_DISCONNECTED; 1720545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh } 1721df7627db715a7a2e7f646f02a07caf2347bb90b8Adam Powell return mInputDevices.get(device); 1722545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh } 1723545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh 1724545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh public synchronized BluetoothDevice[] getConnectedInputDevices() { 1725545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1726545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh Set<BluetoothDevice> devices = lookupInputDevicesMatchingStates( 1727545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh new int[] {BluetoothInputDevice.STATE_CONNECTED}); 1728545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh return devices.toArray(new BluetoothDevice[devices.size()]); 1729545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh } 1730545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh 1731545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh public synchronized int getInputDevicePriority(BluetoothDevice device) { 1732545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1733545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh return Settings.Secure.getInt(mContext.getContentResolver(), 1734545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh Settings.Secure.getBluetoothInputDevicePriorityKey(device.getAddress()), 1735545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh BluetoothInputDevice.PRIORITY_UNDEFINED); 1736545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh } 1737545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh 1738545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh public synchronized boolean setInputDevicePriority(BluetoothDevice device, int priority) { 1739545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 1740545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh "Need BLUETOOTH_ADMIN permission"); 1741545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh if (!BluetoothAdapter.checkBluetoothAddress(device.getAddress())) { 1742545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh return false; 1743545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh } 1744545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh return Settings.Secure.putInt(mContext.getContentResolver(), 1745545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh Settings.Secure.getBluetoothInputDevicePriorityKey(device.getAddress()), 1746545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh priority); 1747545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh } 1748545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh 1749545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh /*package*/synchronized Set<BluetoothDevice> lookupInputDevicesMatchingStates(int[] states) { 1750545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh Set<BluetoothDevice> inputDevices = new HashSet<BluetoothDevice>(); 1751545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh if (mInputDevices.isEmpty()) { 1752545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh return inputDevices; 1753545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh } 1754545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh for (BluetoothDevice device: mInputDevices.keySet()) { 1755545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh int inputDeviceState = getInputDeviceState(device); 1756545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh for (int state : states) { 1757545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh if (state == inputDeviceState) { 1758545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh inputDevices.add(device); 1759545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh break; 1760545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh } 1761545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh } 1762545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh } 1763545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh return inputDevices; 1764545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh } 1765545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh 1766545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh private synchronized void handleInputDeviceStateChange(BluetoothDevice device, int state) { 1767545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh int prevState; 1768545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh if (mInputDevices.get(device) == null) { 1769545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh prevState = BluetoothInputDevice.STATE_DISCONNECTED; 1770545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh } else { 1771545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh prevState = mInputDevices.get(device); 1772545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh } 1773545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh if (prevState == state) return; 1774545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh 1775545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh mInputDevices.put(device, state); 1776545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh 1777545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh if (getInputDevicePriority(device) > 1778545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh BluetoothInputDevice.PRIORITY_OFF && 1779545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh state == BluetoothInputDevice.STATE_CONNECTING || 1780545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh state == BluetoothInputDevice.STATE_CONNECTED) { 1781545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh // We have connected or attempting to connect. 1782545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh // Bump priority 1783545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh setInputDevicePriority(device, BluetoothInputDevice.PRIORITY_AUTO_CONNECT); 1784545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh } 1785545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh 1786545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh Intent intent = new Intent(BluetoothInputDevice.ACTION_INPUT_DEVICE_STATE_CHANGED); 1787545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); 1788545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh intent.putExtra(BluetoothInputDevice.EXTRA_PREVIOUS_INPUT_DEVICE_STATE, prevState); 1789545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh intent.putExtra(BluetoothInputDevice.EXTRA_INPUT_DEVICE_STATE, state); 1790545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh mContext.sendBroadcast(intent, BLUETOOTH_PERM); 1791545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh 1792545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh if (DBG) log("InputDevice state : device: " + device + " State:" + prevState + "->" + state); 1793545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh 1794545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh } 1795545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh 179656d26139659c2414d289194c63860ff27ab80da0Jaikumar Ganesh /*package*/ void handleInputDevicePropertyChange(String address, boolean connected) { 1797545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh int state = connected ? BluetoothInputDevice.STATE_CONNECTED : 1798545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh BluetoothInputDevice.STATE_DISCONNECTED; 1799545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh BluetoothDevice device = mAdapter.getRemoteDevice(address); 1800545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh handleInputDeviceStateChange(device, state); 1801545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh } 1802545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh 1803c3ee99d9eb7e8b4b20c2b8f1c548373e1017e0d3Jaikumar Ganesh private void setInitialInputDevicePriority(BluetoothDevice device, int state) { 1804c3ee99d9eb7e8b4b20c2b8f1c548373e1017e0d3Jaikumar Ganesh switch (state) { 1805c3ee99d9eb7e8b4b20c2b8f1c548373e1017e0d3Jaikumar Ganesh case BluetoothDevice.BOND_BONDED: 1806c3ee99d9eb7e8b4b20c2b8f1c548373e1017e0d3Jaikumar Ganesh if (getInputDevicePriority(device) == BluetoothInputDevice.PRIORITY_UNDEFINED) { 1807c3ee99d9eb7e8b4b20c2b8f1c548373e1017e0d3Jaikumar Ganesh setInputDevicePriority(device, BluetoothInputDevice.PRIORITY_ON); 1808c3ee99d9eb7e8b4b20c2b8f1c548373e1017e0d3Jaikumar Ganesh } 1809c3ee99d9eb7e8b4b20c2b8f1c548373e1017e0d3Jaikumar Ganesh break; 1810c3ee99d9eb7e8b4b20c2b8f1c548373e1017e0d3Jaikumar Ganesh case BluetoothDevice.BOND_NONE: 1811c3ee99d9eb7e8b4b20c2b8f1c548373e1017e0d3Jaikumar Ganesh setInputDevicePriority(device, BluetoothInputDevice.PRIORITY_UNDEFINED); 1812c3ee99d9eb7e8b4b20c2b8f1c548373e1017e0d3Jaikumar Ganesh break; 1813c3ee99d9eb7e8b4b20c2b8f1c548373e1017e0d3Jaikumar Ganesh } 1814c3ee99d9eb7e8b4b20c2b8f1c548373e1017e0d3Jaikumar Ganesh } 1815c3ee99d9eb7e8b4b20c2b8f1c548373e1017e0d3Jaikumar Ganesh 18169488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh /*package*/ boolean isRemoteDeviceInCache(String address) { 1817bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly return (mDeviceProperties.get(address) != null); 18189488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh } 18199488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh 18209488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh /*package*/ String[] getRemoteDeviceProperties(String address) { 18218c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh if (!isEnabledInternal()) return null; 18228c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh 18239488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh String objectPath = getObjectPathFromAddress(address); 18249488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh return (String [])getDevicePropertiesNative(objectPath); 18259488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh } 18269488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh 1827d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh /*package*/ synchronized String getRemoteDeviceProperty(String address, String property) { 1828bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly Map<String, String> properties = mDeviceProperties.get(address); 1829d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh if (properties != null) { 1830d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh return properties.get(property); 1831d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh } else { 1832d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh // Query for remote device properties, again. 1833d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh // We will need to reload the cache when we switch Bluetooth on / off 1834d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh // or if we crash. 183510eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh if (updateRemoteDevicePropertiesCache(address)) 1836d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh return getRemoteDeviceProperty(address, property); 18379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 18386fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang Log.e(TAG, "getRemoteDeviceProperty: " + property + " not present: " + address); 1839d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh return null; 18409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 18419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 184210eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh /* package */ synchronized boolean updateRemoteDevicePropertiesCache(String address) { 184310eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh String[] propValues = getRemoteDeviceProperties(address); 184410eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh if (propValues != null) { 184510eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh addRemoteDeviceProperties(address, propValues); 184610eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh return true; 184710eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh } 184810eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh return false; 184910eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh } 185010eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh 1851d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh /* package */ synchronized void addRemoteDeviceProperties(String address, String[] properties) { 1852395d1023660c5caedf7888def17f8ad826f51bf8Jaikumar Ganesh /* 1853395d1023660c5caedf7888def17f8ad826f51bf8Jaikumar Ganesh * We get a DeviceFound signal every time RSSI changes or name changes. 1854395d1023660c5caedf7888def17f8ad826f51bf8Jaikumar Ganesh * Don't create a new Map object every time */ 1855bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly Map<String, String> propertyValues = mDeviceProperties.get(address); 1856efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh if (propertyValues == null) { 1857395d1023660c5caedf7888def17f8ad826f51bf8Jaikumar Ganesh propertyValues = new HashMap<String, String>(); 1858395d1023660c5caedf7888def17f8ad826f51bf8Jaikumar Ganesh } 1859395d1023660c5caedf7888def17f8ad826f51bf8Jaikumar Ganesh 18608bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh for (int i = 0; i < properties.length; i++) { 18618bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh String name = properties[i]; 1862efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh String newValue = null; 18638bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh int len; 18648bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh if (name == null) { 18658bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh Log.e(TAG, "Error: Remote Device Property at index" + i + "is null"); 18668bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh continue; 18678bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh } 18688bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh if (name.equals("UUIDs") || name.equals("Nodes")) { 1869efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh StringBuilder str = new StringBuilder(); 18708bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh len = Integer.valueOf(properties[++i]); 18718bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh for (int j = 0; j < len; j++) { 1872efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh str.append(properties[++i]); 1873efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh str.append(","); 1874efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh } 1875efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh if (len > 0) { 1876efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh newValue = str.toString(); 18778bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh } 1878d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh } else { 18798bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh newValue = properties[++i]; 1880d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh } 1881efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh 18828bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh propertyValues.put(name, newValue); 18839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1884bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly mDeviceProperties.put(address, propertyValues); 188510eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh 188610eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh // We have added a new remote device or updated its properties. 188710eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh // Also update the serviceChannel cache. 188810eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh updateDeviceServiceChannelCache(address); 18899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 18909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1891d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh /* package */ void removeRemoteDeviceProperties(String address) { 1892bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly mDeviceProperties.remove(address); 18939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 18949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1895d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh /* package */ synchronized void setRemoteDeviceProperty(String address, String name, 1896d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh String value) { 1897bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly Map <String, String> propVal = mDeviceProperties.get(address); 1898d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh if (propVal != null) { 1899d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh propVal.put(name, value); 1900bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly mDeviceProperties.put(address, propVal); 1901d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh } else { 1902d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh Log.e(TAG, "setRemoteDeviceProperty for a device not in cache:" + address); 19039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 19049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 19059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 19069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1907efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue * Sets the remote device trust state. 1908efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue * 1909efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue * @return boolean to indicate operation success or fail 1910efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue */ 1911efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue public synchronized boolean setTrust(String address, boolean value) { 1912005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly if (!BluetoothAdapter.checkBluetoothAddress(address)) { 1913e6ee3be1c254404dad842298f6f56c11cc6c7ac8Nick Pelly mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 1914e6ee3be1c254404dad842298f6f56c11cc6c7ac8Nick Pelly "Need BLUETOOTH_ADMIN permission"); 1915efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue return false; 1916efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue } 1917efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue 19188c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh if (!isEnabledInternal()) return false; 19198c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh 1920efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue return setDevicePropertyBooleanNative(getObjectPathFromAddress(address), "Trusted", 1921efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue value ? 1 : 0); 1922efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue } 1923efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue 1924efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue /** 1925efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue * Gets the remote device trust state as boolean. 1926efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue * Note: this value may be 1927efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue * retrieved from cache if we retrieved the data before * 1928efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue * 1929efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue * @return boolean to indicate trust or untrust state 1930efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue */ 1931efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue public synchronized boolean getTrustState(String address) { 1932005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly if (!BluetoothAdapter.checkBluetoothAddress(address)) { 1933efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1934efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue return false; 1935efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue } 1936efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue 1937efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue String val = getRemoteDeviceProperty(address, "Trusted"); 1938efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue if (val == null) { 1939efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue return false; 1940efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue } else { 1941efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue return val.equals("true") ? true : false; 1942efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue } 1943efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue } 1944efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue 1945efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue /** 1946d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh * Gets the remote major, minor classes encoded as a 32-bit 19479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * integer. 19489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 19499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Note: this value is retrieved from cache, because we get it during 19509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * remote-device discovery. 19519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 19529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return 32-bit integer encoding the remote major, minor, and service 19539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * classes. 19549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 19559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public synchronized int getRemoteClass(String address) { 1956005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly if (!BluetoothAdapter.checkBluetoothAddress(address)) { 1957ea600ccfb7568f60377c4abc85f56c80af7fdbfcNick Pelly mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1958ea600ccfb7568f60377c4abc85f56c80af7fdbfcNick Pelly return BluetoothClass.ERROR; 19599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1960d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh String val = getRemoteDeviceProperty(address, "Class"); 1961d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh if (val == null) 1962d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh return BluetoothClass.ERROR; 1963d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh else { 1964d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh return Integer.valueOf(val); 1965d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh } 19669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1967d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh 19689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 19699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1970dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh * Gets the UUIDs supported by the remote device 19719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 1972dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh * @return array of 128bit ParcelUuids 19739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1974dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh public synchronized ParcelUuid[] getRemoteUuids(String address) { 19759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1976005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly if (!BluetoothAdapter.checkBluetoothAddress(address)) { 19779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return null; 19789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 19791caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh return getUuidFromCache(address); 19801caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh } 19811caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh 19821caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh private ParcelUuid[] getUuidFromCache(String address) { 1983d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh String value = getRemoteDeviceProperty(address, "UUIDs"); 1984dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh if (value == null) return null; 1985dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh 1986dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh String[] uuidStrings = null; 1987d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh // The UUIDs are stored as a "," separated string. 1988dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh uuidStrings = value.split(","); 1989dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh ParcelUuid[] uuids = new ParcelUuid[uuidStrings.length]; 1990dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh 1991dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh for (int i = 0; i < uuidStrings.length; i++) { 1992dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh uuids[i] = ParcelUuid.fromString(uuidStrings[i]); 1993dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh } 1994d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh return uuids; 19959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 19969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 199716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly /** 199816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly * Connect and fetch new UUID's using SDP. 199916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly * The UUID's found are broadcast as intents. 200016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly * Optionally takes a uuid and callback to fetch the RFCOMM channel for the 200116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly * a given uuid. 200216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly * TODO: Don't wait UUID_INTENT_DELAY to broadcast UUID intents on success 200316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly * TODO: Don't wait UUID_INTENT_DELAY to handle the failure case for 200416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly * callback and broadcast intents. 200516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly */ 200616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly public synchronized boolean fetchRemoteUuids(String address, ParcelUuid uuid, 200716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly IBluetoothCallback callback) { 20081caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 20098c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh if (!isEnabledInternal()) return false; 20108c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh 20111caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh if (!BluetoothAdapter.checkBluetoothAddress(address)) { 20121caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh return false; 20131caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh } 20141caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh 201516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly RemoteService service = new RemoteService(address, uuid); 201616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly if (uuid != null && mUuidCallbackTracker.get(service) != null) { 201716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly // An SDP query for this address & uuid is already in progress 201816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly // Do not add this callback for the uuid 201916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly return false; 202016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } 202116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly 20221caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh if (mUuidIntentTracker.contains(address)) { 20231caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh // An SDP query for this address is already in progress 202416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly // Add this uuid onto the in-progress SDP query 202516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly if (uuid != null) { 202616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly mUuidCallbackTracker.put(new RemoteService(address, uuid), callback); 202716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } 20281caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh return true; 20291caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh } 20301caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh 20311caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh boolean ret; 20320e09030977aea8b40fd177139528d4b5637c9771Jaikumar Ganesh // Just do the SDP if the device is already created and UUIDs are not 20330e09030977aea8b40fd177139528d4b5637c9771Jaikumar Ganesh // NULL, else create the device and then do SDP. 20340e09030977aea8b40fd177139528d4b5637c9771Jaikumar Ganesh if (isRemoteDeviceInCache(address) && getRemoteUuids(address) != null) { 20351caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh String path = getObjectPathFromAddress(address); 20361caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh if (path == null) return false; 20371caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh 20381caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh // Use an empty string for the UUID pattern 20391caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh ret = discoverServicesNative(path, ""); 20401caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh } else { 20411caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh ret = createDeviceNative(address); 20421caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh } 20431caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh 20441caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh mUuidIntentTracker.add(address); 204516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly if (uuid != null) { 204616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly mUuidCallbackTracker.put(new RemoteService(address, uuid), callback); 204716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } 20481caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh 20491caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh Message message = mHandler.obtainMessage(MESSAGE_UUID_INTENT); 20501caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh message.obj = address; 20511caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh mHandler.sendMessageDelayed(message, UUID_INTENT_DELAY); 20521caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh return ret; 20531caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh } 20541caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh 20559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 2056d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh * Gets the rfcomm channel associated with the UUID. 205716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly * Pulls records from the cache only. 20589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 2059d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh * @param address Address of the remote device 2060dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh * @param uuid ParcelUuid of the service attribute 20619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 2062d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh * @return rfcomm channel associated with the service attribute 206310eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh * -1 on error 20649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 2065dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh public int getRemoteServiceChannel(String address, ParcelUuid uuid) { 20669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 20678c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh if (!isEnabledInternal()) return -1; 20688c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh 2069005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly if (!BluetoothAdapter.checkBluetoothAddress(address)) { 2070b24e11baac589fe16426f2d243b460ab84991c7bNick Pelly return BluetoothDevice.ERROR; 20719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 207210eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh // Check if we are recovering from a crash. 207310eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh if (mDeviceProperties.isEmpty()) { 207410eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh if (!updateRemoteDevicePropertiesCache(address)) 207510eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh return -1; 207610eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh } 207710eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh 207810eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh Map<ParcelUuid, Integer> value = mDeviceServiceChannelCache.get(address); 207910eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh if (value != null && value.containsKey(uuid)) 208010eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh return value.get(uuid); 208110eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh return -1; 20829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 20839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 20849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public synchronized boolean setPin(String address, byte[] pin) { 20859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 20869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Need BLUETOOTH_ADMIN permission"); 20878c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh if (!isEnabledInternal()) return false; 20888c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh 20899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (pin == null || pin.length <= 0 || pin.length > 16 || 2090005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly !BluetoothAdapter.checkBluetoothAddress(address)) { 20919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 20929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 20939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project address = address.toUpperCase(); 20949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Integer data = mEventLoop.getPasskeyAgentRequestData().remove(address); 20959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (data == null) { 20969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.w(TAG, "setPin(" + address + ") called but no native data available, " + 20979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "ignoring. Maybe the PasskeyAgent Request was cancelled by the remote device" + 20989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project " or by bluez.\n"); 20999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 21009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 21019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // bluez API wants pin as a string 21029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String pinString; 21039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 21049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project pinString = new String(pin, "UTF8"); 21059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (UnsupportedEncodingException uee) { 21069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.e(TAG, "UTF8 not supported?!?"); 21079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 21089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 21099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return setPinNative(address, pinString, data.intValue()); 21109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 21119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2112b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh public synchronized boolean setPasskey(String address, int passkey) { 2113b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 2114b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh "Need BLUETOOTH_ADMIN permission"); 21158c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh if (!isEnabledInternal()) return false; 21168c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh 2117005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly if (passkey < 0 || passkey > 999999 || !BluetoothAdapter.checkBluetoothAddress(address)) { 2118b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh return false; 2119b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh } 2120b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh address = address.toUpperCase(); 2121b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh Integer data = mEventLoop.getPasskeyAgentRequestData().remove(address); 2122b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh if (data == null) { 2123b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh Log.w(TAG, "setPasskey(" + address + ") called but no native data available, " + 2124b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh "ignoring. Maybe the PasskeyAgent Request was cancelled by the remote device" + 2125b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh " or by bluez.\n"); 2126b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh return false; 2127b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh } 2128b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh return setPasskeyNative(address, passkey, data.intValue()); 2129b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh } 2130b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh 2131b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh public synchronized boolean setPairingConfirmation(String address, boolean confirm) { 2132b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 2133b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh "Need BLUETOOTH_ADMIN permission"); 21348c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh if (!isEnabledInternal()) return false; 21358c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh 2136b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh address = address.toUpperCase(); 2137b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh Integer data = mEventLoop.getPasskeyAgentRequestData().remove(address); 2138b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh if (data == null) { 2139b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh Log.w(TAG, "setPasskey(" + address + ") called but no native data available, " + 2140b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh "ignoring. Maybe the PasskeyAgent Request was cancelled by the remote device" + 2141b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh " or by bluez.\n"); 2142b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh return false; 2143b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh } 2144b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh return setPairingConfirmationNative(address, confirm, data.intValue()); 2145b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh } 2146b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh 2147cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh public synchronized boolean setRemoteOutOfBandData(String address) { 2148cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 2149cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh "Need BLUETOOTH_ADMIN permission"); 2150cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh if (!isEnabledInternal()) return false; 2151cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh address = address.toUpperCase(); 2152cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh Integer data = mEventLoop.getPasskeyAgentRequestData().remove(address); 2153cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh if (data == null) { 2154cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh Log.w(TAG, "setRemoteOobData(" + address + ") called but no native data available, " + 2155cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh "ignoring. Maybe the PasskeyAgent Request was cancelled by the remote device" + 2156cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh " or by bluez.\n"); 2157cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh return false; 2158cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh } 2159cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh 2160cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh Pair<byte[], byte[]> val = mDeviceOobData.get(address); 2161cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh byte[] hash, randomizer; 2162cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh if (val == null) { 2163cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh // TODO: check what should be passed in this case. 2164cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh hash = new byte[16]; 2165cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh randomizer = new byte[16]; 2166cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh } else { 2167cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh hash = val.first; 2168cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh randomizer = val.second; 2169cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh } 2170cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh return setRemoteOutOfBandDataNative(address, hash, randomizer, data.intValue()); 2171cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh } 2172cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh 2173b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh public synchronized boolean cancelPairingUserInput(String address) { 21749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 21759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Need BLUETOOTH_ADMIN permission"); 21768c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh if (!isEnabledInternal()) return false; 21778c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh 2178005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly if (!BluetoothAdapter.checkBluetoothAddress(address)) { 21799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 21809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2181005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly mBondState.setBondState(address, BluetoothDevice.BOND_NONE, 2182397d8f4f4829a45f4fe7a672cc395466bbc0f442Jaikumar Ganesh BluetoothDevice.UNBOND_REASON_AUTH_CANCELED); 21839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project address = address.toUpperCase(); 21849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Integer data = mEventLoop.getPasskeyAgentRequestData().remove(address); 21859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (data == null) { 2186b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh Log.w(TAG, "cancelUserInputNative(" + address + ") called but no native data " + 2187b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh "available, ignoring. Maybe the PasskeyAgent Request was already cancelled " + 2188b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh "by the remote or by bluez.\n"); 21899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 21909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2191b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh return cancelPairingUserInputNative(address, data.intValue()); 21929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 21939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 21948c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh /*package*/ void updateDeviceServiceChannelCache(String address) { 219510eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh ParcelUuid[] deviceUuids = getRemoteUuids(address); 219610eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh // We are storing the rfcomm channel numbers only for the uuids 219710eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh // we are interested in. 219810eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh int channel; 219916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly if (DBG) log("updateDeviceServiceChannelCache(" + address + ")"); 220016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly 220116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly ArrayList<ParcelUuid> applicationUuids = new ArrayList(); 220216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly 220316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly synchronized (this) { 220416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly for (RemoteService service : mUuidCallbackTracker.keySet()) { 220516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly if (service.address.equals(address)) { 220616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly applicationUuids.add(service.uuid); 220716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } 220816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } 220916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } 221010eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh 221110eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh Map <ParcelUuid, Integer> value = new HashMap<ParcelUuid, Integer>(); 221216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly 221316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly // Retrieve RFCOMM channel for default uuids 221416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly for (ParcelUuid uuid : RFCOMM_UUIDS) { 221510eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh if (BluetoothUuid.isUuidPresent(deviceUuids, uuid)) { 221616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly channel = getDeviceServiceChannelNative(getObjectPathFromAddress(address), 221716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly uuid.toString(), 0x0004); 221816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly if (DBG) log("\tuuid(system): " + uuid + " " + channel); 221910eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh value.put(uuid, channel); 222010eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh } 222110eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh } 222216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly // Retrieve RFCOMM channel for application requested uuids 222316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly for (ParcelUuid uuid : applicationUuids) { 222416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly if (BluetoothUuid.isUuidPresent(deviceUuids, uuid)) { 222516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly channel = getDeviceServiceChannelNative(getObjectPathFromAddress(address), 222616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly uuid.toString(), 0x0004); 222716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly if (DBG) log("\tuuid(application): " + uuid + " " + channel); 222816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly value.put(uuid, channel); 222916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } 223016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } 223116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly 223216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly synchronized (this) { 223316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly // Make application callbacks 223416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly for (Iterator<RemoteService> iter = mUuidCallbackTracker.keySet().iterator(); 223516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly iter.hasNext();) { 223616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly RemoteService service = iter.next(); 223716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly if (service.address.equals(address)) { 223816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly channel = -1; 223916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly if (value.get(service.uuid) != null) { 224016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly channel = value.get(service.uuid); 224116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } 224216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly if (channel != -1) { 224316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly if (DBG) log("Making callback for " + service.uuid + " with result " + 224416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly channel); 224516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly IBluetoothCallback callback = mUuidCallbackTracker.get(service); 224616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly if (callback != null) { 224716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly try { 224816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly callback.onRfcommChannelFound(channel); 224916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } catch (RemoteException e) {Log.e(TAG, "", e);} 225016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } 225116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly 225216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly iter.remove(); 225316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } 225416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } 225516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } 225616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly 225716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly // Update cache 225816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly mDeviceServiceChannelCache.put(address, value); 225916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } 226010eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh } 226110eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh 226224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly /** 226324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly * b is a handle to a Binder instance, so that this service can be notified 226424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly * for Applications that terminate unexpectedly, to clean there service 226524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly * records 226624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly */ 226724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly public synchronized int addRfcommServiceRecord(String serviceName, ParcelUuid uuid, 226824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly int channel, IBinder b) { 22698c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 22708c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh if (!isEnabledInternal()) return -1; 22718c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh 227224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly if (serviceName == null || uuid == null || channel < 1 || 227324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly channel > BluetoothSocket.MAX_RFCOMM_CHANNEL) { 227424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly return -1; 227524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly } 227624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly if (BluetoothUuid.isUuidPresent(BluetoothUuid.RESERVED_UUIDS, uuid)) { 227724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly Log.w(TAG, "Attempted to register a reserved UUID: " + uuid); 227824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly return -1; 227924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly } 228024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly int handle = addRfcommServiceRecordNative(serviceName, 228124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly uuid.getUuid().getMostSignificantBits(), uuid.getUuid().getLeastSignificantBits(), 228224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly (short)channel); 228324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly if (DBG) log("new handle " + Integer.toHexString(handle)); 228424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly if (handle == -1) { 228524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly return -1; 228624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly } 228724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly 228824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly int pid = Binder.getCallingPid(); 228924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly mServiceRecordToPid.put(new Integer(handle), new Integer(pid)); 229024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly try { 229124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly b.linkToDeath(new Reaper(handle, pid), 0); 229224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly } catch (RemoteException e) {} 229324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly return handle; 229424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly } 229524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly 229624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly public void removeServiceRecord(int handle) { 229724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, 229824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly "Need BLUETOOTH permission"); 229924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly checkAndRemoveRecord(handle, Binder.getCallingPid()); 230024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly } 230124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly 230224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly private synchronized void checkAndRemoveRecord(int handle, int pid) { 230324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly Integer handleInt = new Integer(handle); 230424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly Integer owner = mServiceRecordToPid.get(handleInt); 230524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly if (owner != null && pid == owner.intValue()) { 230624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly if (DBG) log("Removing service record " + Integer.toHexString(handle) + " for pid " + 230724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly pid); 230824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly mServiceRecordToPid.remove(handleInt); 230924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly removeServiceRecordNative(handle); 231024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly } 231124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly } 231224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly 231324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly private class Reaper implements IBinder.DeathRecipient { 231424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly int pid; 231524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly int handle; 231624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly Reaper(int handle, int pid) { 231724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly this.pid = pid; 231824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly this.handle = handle; 231924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly } 232024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly public void binderDied() { 232124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly synchronized (BluetoothService.this) { 232224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly if (DBG) log("Tracked app " + pid + " died"); 232324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly checkAndRemoveRecord(handle, pid); 232424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly } 232524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly } 232624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly } 232724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly 23289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private final BroadcastReceiver mReceiver = new BroadcastReceiver() { 23299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 23309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void onReceive(Context context, Intent intent) { 23316e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh if (intent == null) return; 23326e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh 23339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String action = intent.getAction(); 23349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (action.equals(Intent.ACTION_AIRPLANE_MODE_CHANGED)) { 23359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ContentResolver resolver = context.getContentResolver(); 23369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Query the airplane mode from Settings.System just to make sure that 23379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // some random app is not sending this intent and disabling bluetooth 23389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean enabled = !isAirplaneModeOn(); 23399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // If bluetooth is currently expected to be on, then enable or disable bluetooth 23409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (Settings.Secure.getInt(resolver, Settings.Secure.BLUETOOTH_ON, 0) > 0) { 23419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (enabled) { 2342105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project enable(false); 23439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 23449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project disable(false); 23459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 23469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 23476e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh } else if (Intent.ACTION_DOCK_EVENT.equals(action)) { 23486e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh int state = intent.getIntExtra(Intent.EXTRA_DOCK_STATE, 23496e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh Intent.EXTRA_DOCK_STATE_UNDOCKED); 23506e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh if (DBG) Log.v(TAG, "Received ACTION_DOCK_EVENT with State:" + state); 23516e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh if (state == Intent.EXTRA_DOCK_STATE_UNDOCKED) { 23526e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh mDockAddress = null; 23536e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh mDockPin = null; 23546e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh } else { 23556e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh SharedPreferences.Editor editor = 23566e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh mContext.getSharedPreferences(SHARED_PREFERENCES_NAME, 23576e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh mContext.MODE_PRIVATE).edit(); 23586e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh editor.putBoolean(SHARED_PREFERENCE_DOCK_ADDRESS + mDockAddress, true); 235966fce5068a8a3aeb28aaf713843891b286a75280Brad Fitzpatrick editor.apply(); 23606e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh } 23619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 23629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 23639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project }; 23649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 23656e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh private void registerForAirplaneMode(IntentFilter filter) { 236644303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey final ContentResolver resolver = mContext.getContentResolver(); 236744303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey final String airplaneModeRadios = Settings.System.getString(resolver, 23689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Settings.System.AIRPLANE_MODE_RADIOS); 236944303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey final String toggleableRadios = Settings.System.getString(resolver, 237044303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey Settings.System.AIRPLANE_MODE_TOGGLEABLE_RADIOS); 237144303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey 237244303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey mIsAirplaneSensitive = airplaneModeRadios == null ? true : 237344303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey airplaneModeRadios.contains(Settings.System.RADIO_BLUETOOTH); 237444303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey mIsAirplaneToggleable = toggleableRadios == null ? false : 237544303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey toggleableRadios.contains(Settings.System.RADIO_BLUETOOTH); 237644303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey 23779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mIsAirplaneSensitive) { 23786e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED); 23799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 23809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 23819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 23829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* Returns true if airplane mode is currently on */ 23839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private final boolean isAirplaneModeOn() { 23849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return Settings.System.getInt(mContext.getContentResolver(), 23859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Settings.System.AIRPLANE_MODE_ON, 0) == 1; 23869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 23879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 23881caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh /* Broadcast the Uuid intent */ 23891caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh /*package*/ synchronized void sendUuidIntent(String address) { 23906179965e85ec17b836084a4a3d7963d8a7a1e1ccJaikumar Ganesh ParcelUuid[] uuid = getUuidFromCache(address); 23916179965e85ec17b836084a4a3d7963d8a7a1e1ccJaikumar Ganesh Intent intent = new Intent(BluetoothDevice.ACTION_UUID); 23922d3b98d868cda30535505b2a2fba47aa1c9c052bJaikumar Ganesh intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mAdapter.getRemoteDevice(address)); 23936179965e85ec17b836084a4a3d7963d8a7a1e1ccJaikumar Ganesh intent.putExtra(BluetoothDevice.EXTRA_UUID, uuid); 23946179965e85ec17b836084a4a3d7963d8a7a1e1ccJaikumar Ganesh mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM); 23951caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh 23966179965e85ec17b836084a4a3d7963d8a7a1e1ccJaikumar Ganesh if (mUuidIntentTracker.contains(address)) 23971caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh mUuidIntentTracker.remove(address); 239816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly 239916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } 240016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly 240116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly /*package*/ synchronized void makeServiceChannelCallbacks(String address) { 240216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly for (Iterator<RemoteService> iter = mUuidCallbackTracker.keySet().iterator(); 240316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly iter.hasNext();) { 240416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly RemoteService service = iter.next(); 240516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly if (service.address.equals(address)) { 240616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly if (DBG) log("Cleaning up failed UUID channel lookup: " + service.address + 240716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly " " + service.uuid); 240816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly IBluetoothCallback callback = mUuidCallbackTracker.get(service); 240916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly if (callback != null) { 241016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly try { 241116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly callback.onRfcommChannelFound(-1); 241216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } catch (RemoteException e) {Log.e(TAG, "", e);} 241316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } 241416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly 241516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly iter.remove(); 241616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } 241716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } 24181caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh } 24191caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh 24209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 24219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 2422105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project switch(mBluetoothState) { 2423de893f550301a60274e87aa8168225e7a7a42184Nick Pelly case BluetoothAdapter.STATE_OFF: 242424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly pw.println("Bluetooth OFF\n"); 2425105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project return; 2426de893f550301a60274e87aa8168225e7a7a42184Nick Pelly case BluetoothAdapter.STATE_TURNING_ON: 242724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly pw.println("Bluetooth TURNING ON\n"); 2428105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project return; 2429de893f550301a60274e87aa8168225e7a7a42184Nick Pelly case BluetoothAdapter.STATE_TURNING_OFF: 243024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly pw.println("Bluetooth TURNING OFF\n"); 2431105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project return; 2432de893f550301a60274e87aa8168225e7a7a42184Nick Pelly case BluetoothAdapter.STATE_ON: 243324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly pw.println("Bluetooth ON\n"); 2434105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project } 2435105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project 243624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly pw.println("mIsAirplaneSensitive = " + mIsAirplaneSensitive); 243744303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey pw.println("mIsAirplaneToggleable = " + mIsAirplaneToggleable); 243824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly 243924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly pw.println("Local address = " + getAddress()); 244024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly pw.println("Local name = " + getName()); 244124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly pw.println("isDiscovering() = " + isDiscovering()); 2442105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project 244396a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh mAdapter.getProfileProxy(mContext, 244496a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh mBluetoothProfileServiceListener, BluetoothProfile.HEADSET); 2445105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project 2446105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project pw.println("\n--Known devices--"); 2447bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly for (String address : mDeviceProperties.keySet()) { 24481eada0d3d655d6396bf862da954d254856a1bc03Nick Pelly int bondState = mBondState.getBondState(address); 2449105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project pw.printf("%s %10s (%d) %s\n", address, 24501eada0d3d655d6396bf862da954d254856a1bc03Nick Pelly toBondStateString(bondState), 2451105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project mBondState.getAttempt(address), 2452105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project getRemoteName(address)); 245324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly 245424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly Map<ParcelUuid, Integer> uuidChannels = mDeviceServiceChannelCache.get(address); 245524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly if (uuidChannels == null) { 245624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly pw.println("\tuuids = null"); 245724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly } else { 245824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly for (ParcelUuid uuid : uuidChannels.keySet()) { 245924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly Integer channel = uuidChannels.get(uuid); 246024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly if (channel == null) { 246124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly pw.println("\t" + uuid); 246224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly } else { 246324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly pw.println("\t" + uuid + " RFCOMM channel = " + channel); 24641eada0d3d655d6396bf862da954d254856a1bc03Nick Pelly } 24651eada0d3d655d6396bf862da954d254856a1bc03Nick Pelly } 24661eada0d3d655d6396bf862da954d254856a1bc03Nick Pelly } 246716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly for (RemoteService service : mUuidCallbackTracker.keySet()) { 246816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly if (service.address.equals(address)) { 246916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly pw.println("\tPENDING CALLBACK: " + service.uuid); 247016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } 247116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } 2472105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project } 2473105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project 2474d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh String value = getProperty("Devices"); 24751eada0d3d655d6396bf862da954d254856a1bc03Nick Pelly String[] devicesObjectPath = null; 2476d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh if (value != null) { 2477d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh devicesObjectPath = value.split(","); 2478d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh } 2479105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project pw.println("\n--ACL connected devices--"); 248024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly if (devicesObjectPath != null) { 248124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly for (String device : devicesObjectPath) { 248224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly pw.println(getAddressFromObjectPath(device)); 248324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly } 2484105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project } 2485105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project 2486105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project // Rather not do this from here, but no-where else and I need this 2487105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project // dump 2488105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project pw.println("\n--Headset Service--"); 248996a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh if (mBluetoothHeadset != null) { 249096a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh Set<BluetoothDevice> deviceSet = mBluetoothHeadset.getConnectedDevices(); 249196a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh if (deviceSet.size() == 0) { 249296a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh pw.println("\n--No headsets connected--"); 249396a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh } 249496a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh BluetoothDevice device = (BluetoothDevice) deviceSet.toArray()[0]; 249596a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh 249696a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh switch (mBluetoothHeadset.getConnectionState(device)) { 249796a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh case BluetoothHeadset.STATE_DISCONNECTED: 249896a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh pw.println("getConnectionState() = STATE_DISCONNECTED"); 249996a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh break; 250096a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh case BluetoothHeadset.STATE_CONNECTING: 250196a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh pw.println("getConnectionState() = STATE_CONNECTING"); 250296a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh break; 250396a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh case BluetoothHeadset.STATE_CONNECTED: 250496a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh pw.println("getConnectionState() = STATE_CONNECTED"); 250596a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh break; 250696a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh case BluetoothHeadset.STATE_DISCONNECTING: 250796a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh pw.println("getConnectionState() = STATE_DISCONNECTING"); 250896a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh break; 250996a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh case BluetoothHeadset.STATE_AUDIO_CONNECTED: 251096a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh pw.println("getConnectionState() = STATE_AUDIO_CONNECTED"); 251196a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh break; 251296a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh } 251396a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh 251496a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh deviceSet.clear(); 251596a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh deviceSet = mBluetoothHeadset.getDevicesMatchingConnectionStates(new int[] { 251696a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh BluetoothProfile.STATE_CONNECTED, BluetoothProfile.STATE_DISCONNECTED}); 251796a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh pw.println("\n--Connected and Disconnected Headsets"); 251896a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh for (BluetoothDevice dev: deviceSet) { 251996a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh pw.println(device); 252096a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh if (mBluetoothHeadset.isAudioConnected(device)) { 252196a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh pw.println("SCO audio connected to device:" + device); 252296a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh } 252396a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh } 252496a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh 252596a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh pw.println("\ngetCurrentHeadset() = " + device); 252696a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh pw.println("getBatteryUsageHint() = " + 252796a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh mBluetoothHeadset.getBatteryUsageHint(device)); 252896a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh mAdapter.closeProfileProxy(BluetoothProfile.HEADSET, mBluetoothHeadset); 2529105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project } 25306c901db72dbaf57d8fdf26adae6721de14ecae22Nick Pelly 253124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly pw.println("\n--Application Service Records--"); 253224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly for (Integer handle : mServiceRecordToPid.keySet()) { 253324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly Integer pid = mServiceRecordToPid.get(handle); 253424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly pw.println("\tpid " + pid + " handle " + Integer.toHexString(handle)); 253524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly } 25369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 25379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 253896a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh private BluetoothProfile.ServiceListener mBluetoothProfileServiceListener = 253996a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh new BluetoothProfile.ServiceListener() { 254096a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh public void onServiceConnected(int profile, BluetoothProfile proxy) { 254196a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh mBluetoothHeadset = (BluetoothHeadset) proxy; 254296a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh } 254396a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh public void onServiceDisconnected(int profile) { 254496a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh mBluetoothHeadset = null; 254596a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh } 254696a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh }; 254796a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh 2548d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh /* package */ static int bluezStringToScanMode(boolean pairable, boolean discoverable) { 2549d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh if (pairable && discoverable) 2550bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly return BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE; 2551d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh else if (pairable && !discoverable) 2552bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly return BluetoothAdapter.SCAN_MODE_CONNECTABLE; 2553d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh else 2554bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly return BluetoothAdapter.SCAN_MODE_NONE; 25559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 25569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 25579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* package */ static String scanModeToBluezString(int mode) { 25589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project switch (mode) { 2559bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly case BluetoothAdapter.SCAN_MODE_NONE: 25609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return "off"; 2561bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly case BluetoothAdapter.SCAN_MODE_CONNECTABLE: 25629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return "connectable"; 2563bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly case BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE: 25649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return "discoverable"; 25659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 25669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return null; 25679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 25689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2569d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh /*package*/ String getAddressFromObjectPath(String objectPath) { 2570b148bc844e5eddb07bef2fd1b4b754716decb43eJaikumar Ganesh String adapterObjectPath = getPropertyInternal("ObjectPath"); 2571d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh if (adapterObjectPath == null || objectPath == null) { 2572f51eadaf1f83abfe16a609a4ded6d789494689b2Jake Hamby Log.e(TAG, "getAddressFromObjectPath: AdapterObjectPath:" + adapterObjectPath + 2573d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh " or deviceObjectPath:" + objectPath + " is null"); 2574d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh return null; 2575d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh } 2576d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh if (!objectPath.startsWith(adapterObjectPath)) { 2577f51eadaf1f83abfe16a609a4ded6d789494689b2Jake Hamby Log.e(TAG, "getAddressFromObjectPath: AdapterObjectPath:" + adapterObjectPath + 2578d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh " is not a prefix of deviceObjectPath:" + objectPath + 2579d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh "bluetoothd crashed ?"); 2580d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh return null; 2581d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh } 2582d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh String address = objectPath.substring(adapterObjectPath.length()); 2583d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh if (address != null) return address.replace('_', ':'); 2584d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh 2585d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh Log.e(TAG, "getAddressFromObjectPath: Address being returned is null"); 2586d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh return null; 2587d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh } 2588d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh 2589d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh /*package*/ String getObjectPathFromAddress(String address) { 2590b148bc844e5eddb07bef2fd1b4b754716decb43eJaikumar Ganesh String path = getPropertyInternal("ObjectPath"); 2591d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh if (path == null) { 2592d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh Log.e(TAG, "Error: Object Path is null"); 2593d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh return null; 2594d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh } 2595d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh path = path + address.replace(":", "_"); 2596d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh return path; 2597d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh } 2598d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh 2599b7e029d03c115ed65cdea9b2bba307e882c308e2Jaikumar Ganesh /*package */ void setLinkTimeout(String address, int num_slots) { 2600b7e029d03c115ed65cdea9b2bba307e882c308e2Jaikumar Ganesh String path = getObjectPathFromAddress(address); 2601b7e029d03c115ed65cdea9b2bba307e882c308e2Jaikumar Ganesh boolean result = setLinkTimeoutNative(path, num_slots); 2602b7e029d03c115ed65cdea9b2bba307e882c308e2Jaikumar Ganesh 2603b7e029d03c115ed65cdea9b2bba307e882c308e2Jaikumar Ganesh if (!result) log("Set Link Timeout to:" + num_slots + " slots failed"); 2604b7e029d03c115ed65cdea9b2bba307e882c308e2Jaikumar Ganesh } 2605b7e029d03c115ed65cdea9b2bba307e882c308e2Jaikumar Ganesh 26069b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh public boolean connectHeadset(String address) { 260796a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh if (getBondState(address) != BluetoothDevice.BOND_BONDED) return false; 260896a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh 2609f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh BluetoothDeviceProfileState state = mDeviceProfileState.get(address); 26109b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh if (state != null) { 2611f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh Message msg = new Message(); 2612f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh msg.arg1 = BluetoothDeviceProfileState.CONNECT_HFP_OUTGOING; 2613f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh msg.obj = state; 2614f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh mHfpProfileState.sendMessage(msg); 2615f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh return true; 26169b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh } 26179b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh return false; 26189b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh } 26199b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh 26209b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh public boolean disconnectHeadset(String address) { 262196a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh if (getBondState(address) != BluetoothDevice.BOND_BONDED) return false; 262296a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh 2623f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh BluetoothDeviceProfileState state = mDeviceProfileState.get(address); 26249b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh if (state != null) { 2625f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh Message msg = new Message(); 2626f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh msg.arg1 = BluetoothDeviceProfileState.DISCONNECT_HFP_OUTGOING; 2627f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh msg.obj = state; 2628f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh mHfpProfileState.sendMessage(msg); 26299b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh return true; 26309b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh } 26319b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh return false; 26329b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh } 26339b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh 26349b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh public boolean connectSink(String address) { 263596a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh if (getBondState(address) != BluetoothDevice.BOND_BONDED) return false; 263696a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh 2637f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh BluetoothDeviceProfileState state = mDeviceProfileState.get(address); 26389b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh if (state != null) { 2639f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh Message msg = new Message(); 2640f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh msg.arg1 = BluetoothDeviceProfileState.CONNECT_A2DP_OUTGOING; 2641f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh msg.obj = state; 2642f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh mA2dpProfileState.sendMessage(msg); 2643f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh return true; 26449b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh } 26459b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh return false; 26469b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh } 26479b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh 26489b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh public boolean disconnectSink(String address) { 264996a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh if (getBondState(address) != BluetoothDevice.BOND_BONDED) return false; 265096a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh 2651f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh BluetoothDeviceProfileState state = mDeviceProfileState.get(address); 26529b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh if (state != null) { 2653f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh Message msg = new Message(); 2654f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh msg.arg1 = BluetoothDeviceProfileState.DISCONNECT_A2DP_OUTGOING; 2655f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh msg.obj = state; 2656f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh mA2dpProfileState.sendMessage(msg); 26579b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh return true; 26589b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh } 26599b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh return false; 26609b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh } 26619b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh 2662f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh private BluetoothDeviceProfileState addProfileState(String address) { 2663f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh BluetoothDeviceProfileState state = mDeviceProfileState.get(address); 26649b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh if (state != null) return state; 26659b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh 2666f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh state = new BluetoothDeviceProfileState(mContext, address, this, mA2dpService); 2667f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh mDeviceProfileState.put(address, state); 26689b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh state.start(); 26699b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh return state; 26709b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh } 26719b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh 26729b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh private void removeProfileState(String address) { 2673f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh mDeviceProfileState.remove(address); 26749b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh } 26759b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh 26769b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh private void initProfileState() { 26779b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh String []bonds = null; 26789b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh String val = getPropertyInternal("Devices"); 26799b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh if (val != null) { 26809b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh bonds = val.split(","); 26819b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh } 26829b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh if (bonds == null) { 26839b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh return; 26849b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh } 26859b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh 26869b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh for (String path : bonds) { 26879b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh String address = getAddressFromObjectPath(path); 2688f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh BluetoothDeviceProfileState state = addProfileState(address); 26899b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh // Allow 8 secs for SDP records to get registered. 26909b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh Message msg = new Message(); 2691f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh msg.what = BluetoothDeviceProfileState.AUTO_CONNECT_PROFILES; 26929b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh state.sendMessageDelayed(msg, 8000); 26939b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh } 26949b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh } 26959b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh 26969b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh public boolean notifyIncomingConnection(String address) { 2697f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh BluetoothDeviceProfileState state = 2698f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh mDeviceProfileState.get(address); 26999b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh if (state != null) { 27009b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh Message msg = new Message(); 2701f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh msg.what = BluetoothDeviceProfileState.CONNECT_HFP_INCOMING; 27029b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh state.sendMessage(msg); 27039b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh return true; 27049b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh } 27059b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh return false; 27069b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh } 27079b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh 27089b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh /*package*/ boolean notifyIncomingA2dpConnection(String address) { 2709f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh BluetoothDeviceProfileState state = 2710f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh mDeviceProfileState.get(address); 27119b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh if (state != null) { 27129b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh Message msg = new Message(); 2713f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh msg.what = BluetoothDeviceProfileState.CONNECT_A2DP_INCOMING; 27149b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh state.sendMessage(msg); 27159b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh return true; 27169b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh } 27179b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh return false; 27189b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh } 27199b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh 27209b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh /*package*/ void setA2dpService(BluetoothA2dpService a2dpService) { 27219b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh mA2dpService = a2dpService; 27229b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh } 27239b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh 272470a053bf1ba331d727e2fbfca8f39d96b3b324b4Jaikumar Ganesh public void sendProfileStateMessage(int profile, int cmd) { 272570a053bf1ba331d727e2fbfca8f39d96b3b324b4Jaikumar Ganesh Message msg = new Message(); 272670a053bf1ba331d727e2fbfca8f39d96b3b324b4Jaikumar Ganesh msg.what = cmd; 272770a053bf1ba331d727e2fbfca8f39d96b3b324b4Jaikumar Ganesh if (profile == BluetoothProfileState.HFP) { 272870a053bf1ba331d727e2fbfca8f39d96b3b324b4Jaikumar Ganesh mHfpProfileState.sendMessage(msg); 272970a053bf1ba331d727e2fbfca8f39d96b3b324b4Jaikumar Ganesh } else if (profile == BluetoothProfileState.A2DP) { 273070a053bf1ba331d727e2fbfca8f39d96b3b324b4Jaikumar Ganesh mA2dpProfileState.sendMessage(msg); 273170a053bf1ba331d727e2fbfca8f39d96b3b324b4Jaikumar Ganesh } 273270a053bf1ba331d727e2fbfca8f39d96b3b324b4Jaikumar Ganesh } 273370a053bf1ba331d727e2fbfca8f39d96b3b324b4Jaikumar Ganesh 27349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static void log(String msg) { 27359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.d(TAG, msg); 27369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2737d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh 2738d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh private native static void classInitNative(); 2739d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh private native void initializeNativeDataNative(); 2740d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh private native boolean setupNativeDataNative(); 2741d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh private native boolean tearDownNativeDataNative(); 2742d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh private native void cleanupNativeDataNative(); 2743d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh private native String getAdapterPathNative(); 2744d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh 2745d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh private native int isEnabledNative(); 2746d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh private native int enableNative(); 2747d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh private native int disableNative(); 2748d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh 2749d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh private native Object[] getAdapterPropertiesNative(); 2750d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh private native Object[] getDevicePropertiesNative(String objectPath); 2751d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh private native boolean setAdapterPropertyStringNative(String key, String value); 2752d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh private native boolean setAdapterPropertyIntegerNative(String key, int value); 2753d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh private native boolean setAdapterPropertyBooleanNative(String key, int value); 2754d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh 2755d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh private native boolean startDiscoveryNative(); 2756d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh private native boolean stopDiscoveryNative(); 2757d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh 2758d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh private native boolean createPairedDeviceNative(String address, int timeout_ms); 2759cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh private native boolean createPairedDeviceOutOfBandNative(String address, int timeout_ms); 2760cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh private native byte[] readAdapterOutOfBandDataNative(); 2761cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh 2762d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh private native boolean cancelDeviceCreationNative(String address); 2763d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh private native boolean removeDeviceNative(String objectPath); 2764d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh private native int getDeviceServiceChannelNative(String objectPath, String uuid, 2765d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh int attributeId); 2766d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh 2767b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh private native boolean cancelPairingUserInputNative(String address, int nativeData); 2768d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh private native boolean setPinNative(String address, String pin, int nativeData); 2769b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh private native boolean setPasskeyNative(String address, int passkey, int nativeData); 2770b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh private native boolean setPairingConfirmationNative(String address, boolean confirm, 2771b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh int nativeData); 2772cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh private native boolean setRemoteOutOfBandDataNative(String address, byte[] hash, 2773cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh byte[] randomizer, int nativeData); 2774cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh 277524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly private native boolean setDevicePropertyBooleanNative(String objectPath, String key, 277624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly int value); 27771caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh private native boolean createDeviceNative(String address); 277816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly /*package*/ native boolean discoverServicesNative(String objectPath, String pattern); 277910eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh 278024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly private native int addRfcommServiceRecordNative(String name, long uuidMsb, long uuidLsb, 278124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly short channel); 278224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly private native boolean removeServiceRecordNative(int handle); 2783b7e029d03c115ed65cdea9b2bba307e882c308e2Jaikumar Ganesh private native boolean setLinkTimeoutNative(String path, int num_slots); 2784545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh private native boolean connectInputDeviceNative(String path); 2785545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh private native boolean disconnectInputDeviceNative(String path); 27866fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang 27876fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang private native boolean setBluetoothTetheringNative(boolean value, String nap, String bridge); 27886fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang private native boolean connectPanDeviceNative(String path, String srcRole, String dstRole); 27896fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang private native boolean disconnectPanDeviceNative(String path); 27909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 2791