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; 3124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pellyimport android.bluetooth.BluetoothSocket; 3210eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganeshimport android.bluetooth.BluetoothUuid; 33bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pellyimport android.bluetooth.IBluetooth; 3416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pellyimport android.bluetooth.IBluetoothCallback; 359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.BroadcastReceiver; 369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.ContentResolver; 379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Context; 389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Intent; 399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.IntentFilter; 406e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganeshimport android.content.SharedPreferences; 419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Binder; 429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Handler; 433fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganeshimport android.os.IBinder; 449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Message; 453fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganeshimport android.os.ParcelUuid; 469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.RemoteException; 47105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Projectimport android.os.ServiceManager; 489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.SystemService; 499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.provider.Settings; 509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.Log; 519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 52d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganeshimport com.android.internal.app.IBatteryStats; 53d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh 543fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganeshimport java.io.BufferedInputStream; 55c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganeshimport java.io.BufferedReader; 563fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganeshimport java.io.BufferedWriter; 57c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganeshimport java.io.DataInputStream; 58c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganeshimport java.io.File; 599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.FileDescriptor; 603fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganeshimport java.io.FileInputStream; 613fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganeshimport java.io.FileNotFoundException; 62c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganeshimport java.io.FileOutputStream; 633fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganeshimport java.io.FileWriter; 643fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganeshimport java.io.IOException; 65c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganeshimport java.io.InputStreamReader; 669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.PrintWriter; 679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.UnsupportedEncodingException; 689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.ArrayList; 699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.Arrays; 709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.HashMap; 7116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pellyimport java.util.Iterator; 729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.Map; 739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 74bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pellypublic class BluetoothService extends IBluetooth.Stub { 75bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly private static final String TAG = "BluetoothService"; 769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final boolean DBG = true; 779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mNativeData; 799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private BluetoothEventLoop mEventLoop; 809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private boolean mIsAirplaneSensitive; 8144303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey private boolean mIsAirplaneToggleable; 82105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project private int mBluetoothState; 83997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly private boolean mRestart = false; // need to call enable() after disable() 84bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly private boolean mIsDiscovering; 85997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly 86bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly private BluetoothAdapter mAdapter; // constant after init() 87997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly private final BondState mBondState = new BondState(); // local cache of bondings 88105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project private final IBatteryStats mBatteryStats; 899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private final Context mContext; 909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final String BLUETOOTH_ADMIN_PERM = android.Manifest.permission.BLUETOOTH_ADMIN; 929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final String BLUETOOTH_PERM = android.Manifest.permission.BLUETOOTH; 939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 943fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh private static final String DOCK_ADDRESS_PATH = "/sys/class/switch/dock/bt_addr"; 953fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh private static final String DOCK_PIN_PATH = "/sys/class/switch/dock/bt_pin"; 963fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh 976e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh private static final String SHARED_PREFERENCE_DOCK_ADDRESS = "dock_bluetooth_address"; 986e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh private static final String SHARED_PREFERENCES_NAME = "bluetooth_service_settings"; 996e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh 100105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project private static final int MESSAGE_REGISTER_SDP_RECORDS = 1; 101105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project private static final int MESSAGE_FINISH_DISABLE = 2; 1021caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh private static final int MESSAGE_UUID_INTENT = 3; 10312835478ee687a493d1b5882e67b6725bd539c26Nick Pelly private static final int MESSAGE_DISCOVERABLE_TIMEOUT = 4; 1041caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh 1051caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh // The timeout used to sent the UUIDs Intent 1061caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh // This timeout should be greater than the page timeout 1071caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh private static final int UUID_INTENT_DELAY = 6000; 108105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project 10916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly /** Always retrieve RFCOMM channel for these SDP UUIDs */ 11016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly private static final ParcelUuid[] RFCOMM_UUIDS = { 11116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly BluetoothUuid.Handsfree, 11216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly BluetoothUuid.HSP, 11316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly BluetoothUuid.ObexObjectPush }; 11416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly 11516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly 116bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly private final Map<String, String> mAdapterProperties; 11716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly private final HashMap<String, Map<String, String>> mDeviceProperties; 118d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh 11916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly private final HashMap<String, Map<ParcelUuid, Integer>> mDeviceServiceChannelCache; 12016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly private final ArrayList<String> mUuidIntentTracker; 12116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly private final HashMap<RemoteService, IBluetoothCallback> mUuidCallbackTracker; 1221caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh 12324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly private final HashMap<Integer, Integer> mServiceRecordToPid; 12424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly 1253fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh private static String mDockAddress; 1263fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh private String mDockPin; 1273fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh 12816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly private static class RemoteService { 12916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly public String address; 13016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly public ParcelUuid uuid; 13116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly public RemoteService(String address, ParcelUuid uuid) { 13216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly this.address = address; 13316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly this.uuid = uuid; 13416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } 13516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly @Override 13616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly public boolean equals(Object o) { 13716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly if (o instanceof RemoteService) { 13816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly RemoteService service = (RemoteService)o; 13916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly return address.equals(service.address) && uuid.equals(service.uuid); 14016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } 14116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly return false; 14216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } 1435f61416305c47c4db0b94c0cf500e9a9d11d4cdbKenny Root 1445f61416305c47c4db0b94c0cf500e9a9d11d4cdbKenny Root @Override 1455f61416305c47c4db0b94c0cf500e9a9d11d4cdbKenny Root public int hashCode() { 1465f61416305c47c4db0b94c0cf500e9a9d11d4cdbKenny Root int hash = 1; 1475f61416305c47c4db0b94c0cf500e9a9d11d4cdbKenny Root hash = hash * 31 + (address == null ? 0 : address.hashCode()); 1485f61416305c47c4db0b94c0cf500e9a9d11d4cdbKenny Root hash = hash * 31 + (uuid == null ? 0 : uuid.hashCode()); 1495f61416305c47c4db0b94c0cf500e9a9d11d4cdbKenny Root return hash; 1505f61416305c47c4db0b94c0cf500e9a9d11d4cdbKenny Root } 15116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } 15216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly 1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project static { 1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project classInitNative(); 1559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 157bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly public BluetoothService(Context context) { 1589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mContext = context; 159105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project 160105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project // Need to do this in place of: 161105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project // mBatteryStats = BatteryStatsService.getService(); 162105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project // Since we can not import BatteryStatsService from here. This class really needs to be 163105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project // moved to java/services/com/android/server/ 164105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService("batteryinfo")); 1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project initializeNativeDataNative(); 167ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project 168ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project if (isEnabledNative() == 1) { 169ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project Log.w(TAG, "Bluetooth daemons already running - runtime restart? "); 170ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project disableNative(); 1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 172ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project 173de893f550301a60274e87aa8168225e7a7a42184Nick Pelly mBluetoothState = BluetoothAdapter.STATE_OFF; 1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mIsDiscovering = false; 175bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly mAdapterProperties = new HashMap<String, String>(); 176bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly mDeviceProperties = new HashMap<String, Map<String,String>>(); 17710eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh 17810eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh mDeviceServiceChannelCache = new HashMap<String, Map<ParcelUuid, Integer>>(); 1791caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh mUuidIntentTracker = new ArrayList<String>(); 18016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly mUuidCallbackTracker = new HashMap<RemoteService, IBluetoothCallback>(); 18124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly mServiceRecordToPid = new HashMap<Integer, Integer>(); 1823fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh 1833fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh IntentFilter filter = new IntentFilter(); 1846e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh registerForAirplaneMode(filter); 1856e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh 1863fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh filter.addAction(Intent.ACTION_DOCK_EVENT); 1876e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh mContext.registerReceiver(mReceiver, filter); 1883fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh } 1893fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh 1903fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh public static synchronized String readDockBluetoothAddress() { 1913fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh if (mDockAddress != null) return mDockAddress; 1923fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh 1933fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh BufferedInputStream file = null; 1943fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh String dockAddress; 1953fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh try { 1963fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh file = new BufferedInputStream(new FileInputStream(DOCK_ADDRESS_PATH)); 1973fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh byte[] address = new byte[17]; 1983fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh file.read(address); 1993fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh dockAddress = new String(address); 2003fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh dockAddress = dockAddress.toUpperCase(); 2013fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh if (BluetoothAdapter.checkBluetoothAddress(dockAddress)) { 2023fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh mDockAddress = dockAddress; 2033fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh return mDockAddress; 2043fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh } else { 2053fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh log("CheckBluetoothAddress failed for car dock address:" + dockAddress); 2063fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh } 2073fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh } catch (FileNotFoundException e) { 2083fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh log("FileNotFoundException while trying to read dock address"); 2093fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh } catch (IOException e) { 2103fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh log("IOException while trying to read dock address"); 2113fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh } finally { 2123fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh if (file != null) { 2133fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh try { 2143fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh file.close(); 2153fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh } catch (IOException e) { 2163fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh // Ignore 2173fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh } 2183fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh } 2193fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh } 2203fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh mDockAddress = null; 2213fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh return null; 2223fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh } 2233fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh 2243fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh private synchronized boolean writeDockPin() { 2253fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh BufferedWriter out = null; 2263fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh try { 2273fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh out = new BufferedWriter(new FileWriter(DOCK_PIN_PATH)); 2283fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh 2293fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh // Generate a random 4 digit pin between 0000 and 9999 2303fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh // This is not truly random but good enough for our purposes. 2313fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh int pin = (int) Math.floor(Math.random() * 10000); 2323fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh 2333fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh mDockPin = String.format("%04d", pin); 2343fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh out.write(mDockPin); 2353fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh return true; 2363fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh } catch (FileNotFoundException e) { 2373fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh log("FileNotFoundException while trying to write dock pairing pin"); 2383fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh } catch (IOException e) { 2393fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh log("IOException while while trying to write dock pairing pin"); 2403fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh } finally { 2413fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh if (out != null) { 2423fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh try { 2433fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh out.close(); 2443fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh } catch (IOException e) { 2453fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh // Ignore 2463fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh } 2473fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh } 2483fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh } 2493fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh mDockPin = null; 2503fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh return false; 2513fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh } 2523fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh 2533fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh /*package*/ synchronized String getDockPin() { 2543fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh return mDockPin; 255bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly } 256bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly 257bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly public synchronized void initAfterRegistration() { 258f242b7b931898856bcbcb7ec36cacf43098ba544Nick Pelly mAdapter = BluetoothAdapter.getDefaultAdapter(); 259bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly mEventLoop = new BluetoothEventLoop(mContext, mAdapter, this); 2609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 2639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project protected void finalize() throws Throwable { 2646e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh mContext.unregisterReceiver(mReceiver); 2659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 2669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project cleanupNativeDataNative(); 2679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } finally { 2689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project super.finalize(); 2699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean isEnabled() { 2739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 2748c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh return isEnabledInternal(); 2758c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh } 2768c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh 2778c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh private boolean isEnabledInternal() { 278de893f550301a60274e87aa8168225e7a7a42184Nick Pelly return mBluetoothState == BluetoothAdapter.STATE_ON; 2799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 281105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project public int getBluetoothState() { 282105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 283105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project return mBluetoothState; 284105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project } 285105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project 286105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project 2879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 2889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Bring down bluetooth and disable BT in settings. Returns true on success. 2899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 2909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean disable() { 2919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return disable(true); 2929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 2959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Bring down bluetooth. Returns true on success. 2969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 297e6ee3be1c254404dad842298f6f56c11cc6c7ac8Nick Pelly * @param saveSetting If true, persist the new setting 2989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 2999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public synchronized boolean disable(boolean saveSetting) { 300e6ee3be1c254404dad842298f6f56c11cc6c7ac8Nick Pelly mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH_ADMIN permission"); 3019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 302105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project switch (mBluetoothState) { 303de893f550301a60274e87aa8168225e7a7a42184Nick Pelly case BluetoothAdapter.STATE_OFF: 304105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project return true; 305de893f550301a60274e87aa8168225e7a7a42184Nick Pelly case BluetoothAdapter.STATE_ON: 306105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project break; 307105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project default: 308105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project return false; 309105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project } 3109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mEnableThread != null && mEnableThread.isAlive()) { 3119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 3129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 313de893f550301a60274e87aa8168225e7a7a42184Nick Pelly setBluetoothState(BluetoothAdapter.STATE_TURNING_OFF); 314bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly mHandler.removeMessages(MESSAGE_REGISTER_SDP_RECORDS); 315105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project 316105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project // Allow 3 seconds for profiles to gracefully disconnect 317105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project // TODO: Introduce a callback mechanism so that each profile can notify 318bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly // BluetoothService when it is done shutting down 319105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project mHandler.sendMessageDelayed( 320105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project mHandler.obtainMessage(MESSAGE_FINISH_DISABLE, saveSetting ? 1 : 0, 0), 3000); 321105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project return true; 322105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project } 323105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project 324105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project 325105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project private synchronized void finishDisable(boolean saveSetting) { 326de893f550301a60274e87aa8168225e7a7a42184Nick Pelly if (mBluetoothState != BluetoothAdapter.STATE_TURNING_OFF) { 327105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project return; 3289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mEventLoop.stop(); 330d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh tearDownNativeDataNative(); 3319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project disableNative(); 3329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // mark in progress bondings as cancelled 3349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (String address : mBondState.listInState(BluetoothDevice.BOND_BONDING)) { 335005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly mBondState.setBondState(address, BluetoothDevice.BOND_NONE, 3369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project BluetoothDevice.UNBOND_REASON_AUTH_CANCELED); 3379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // update mode 340de893f550301a60274e87aa8168225e7a7a42184Nick Pelly Intent intent = new Intent(BluetoothAdapter.ACTION_SCAN_MODE_CHANGED); 341de893f550301a60274e87aa8168225e7a7a42184Nick Pelly intent.putExtra(BluetoothAdapter.EXTRA_SCAN_MODE, BluetoothAdapter.SCAN_MODE_NONE); 3429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mContext.sendBroadcast(intent, BLUETOOTH_PERM); 3439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 344105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project mIsDiscovering = false; 345bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly mAdapterProperties.clear(); 34624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly mServiceRecordToPid.clear(); 347105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project 3489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (saveSetting) { 3499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project persistBluetoothOnSetting(false); 3509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 351105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project 352de893f550301a60274e87aa8168225e7a7a42184Nick Pelly setBluetoothState(BluetoothAdapter.STATE_OFF); 353105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project 354105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project // Log bluetooth off to battery stats. 355105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project long ident = Binder.clearCallingIdentity(); 356105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project try { 357105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project mBatteryStats.noteBluetoothOff(); 358105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project } catch (RemoteException e) { 359105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project } finally { 360105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project Binder.restoreCallingIdentity(ident); 361105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project } 362997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly 363997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly if (mRestart) { 364997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly mRestart = false; 365997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly enable(); 366997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly } 3679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 369105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project /** Bring up BT and persist BT on in settings */ 370105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project public boolean enable() { 371105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project return enable(true); 3729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 3759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Enable this Bluetooth device, asynchronously. 3769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * This turns on/off the underlying hardware. 3779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 378105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project * @param saveSetting If true, persist the new state of BT in settings 379105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project * @return True on success (so far) 3809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 381105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project public synchronized boolean enable(boolean saveSetting) { 3829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 3839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Need BLUETOOTH_ADMIN permission"); 3849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Airplane mode can prevent Bluetooth radio from being turned on. 38644303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey if (mIsAirplaneSensitive && isAirplaneModeOn() && !mIsAirplaneToggleable) { 3879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 3889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 389de893f550301a60274e87aa8168225e7a7a42184Nick Pelly if (mBluetoothState != BluetoothAdapter.STATE_OFF) { 3909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 3919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mEnableThread != null && mEnableThread.isAlive()) { 3939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 3949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 395de893f550301a60274e87aa8168225e7a7a42184Nick Pelly setBluetoothState(BluetoothAdapter.STATE_TURNING_ON); 396105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project mEnableThread = new EnableThread(saveSetting); 3979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mEnableThread.start(); 3989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 3999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 401997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly /** Forcibly restart Bluetooth if it is on */ 402997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly /* package */ synchronized void restart() { 403de893f550301a60274e87aa8168225e7a7a42184Nick Pelly if (mBluetoothState != BluetoothAdapter.STATE_ON) { 404997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly return; 405997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly } 406997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly mRestart = true; 407997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly if (!disable(false)) { 408997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly mRestart = false; 409997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly } 410d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh } 411997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly 412105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project private synchronized void setBluetoothState(int state) { 413105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project if (state == mBluetoothState) { 414105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project return; 415105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project } 416105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project 417105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project if (DBG) log("Bluetooth state " + mBluetoothState + " -> " + state); 418105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project 419de893f550301a60274e87aa8168225e7a7a42184Nick Pelly Intent intent = new Intent(BluetoothAdapter.ACTION_STATE_CHANGED); 420de893f550301a60274e87aa8168225e7a7a42184Nick Pelly intent.putExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, mBluetoothState); 421de893f550301a60274e87aa8168225e7a7a42184Nick Pelly intent.putExtra(BluetoothAdapter.EXTRA_STATE, state); 422105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 423105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project 424105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project mBluetoothState = state; 425105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project 426105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project mContext.sendBroadcast(intent, BLUETOOTH_PERM); 427105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project } 428105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project 4299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private final Handler mHandler = new Handler() { 4309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 4319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void handleMessage(Message msg) { 4329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project switch (msg.what) { 433105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project case MESSAGE_REGISTER_SDP_RECORDS: 4348c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh if (!isEnabledInternal()) { 435bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly return; 436bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly } 437bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly // SystemService.start() forks sdptool to register service 438bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly // records. It can fail to register some records if it is 439bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly // forked multiple times in a row, probably because there is 440bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly // some race in sdptool or bluez when operated in parallel. 441bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly // As a workaround, delay 500ms between each fork of sdptool. 442bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly // TODO: Don't fork sdptool in order to regsiter service 443bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly // records, use a DBUS call instead. 444bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly switch (msg.arg1) { 445bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly case 1: 44677b4ad0e496941a28382eb938a05831f1f8d2d4aJaikumar Ganesh Log.d(TAG, "Registering hfag record"); 44777b4ad0e496941a28382eb938a05831f1f8d2d4aJaikumar Ganesh SystemService.start("hfag"); 448bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly mHandler.sendMessageDelayed( 449bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly mHandler.obtainMessage(MESSAGE_REGISTER_SDP_RECORDS, 2, -1), 500); 450bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly break; 451bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly case 2: 45277b4ad0e496941a28382eb938a05831f1f8d2d4aJaikumar Ganesh Log.d(TAG, "Registering hsag record"); 45377b4ad0e496941a28382eb938a05831f1f8d2d4aJaikumar Ganesh SystemService.start("hsag"); 454bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly mHandler.sendMessageDelayed( 455bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly mHandler.obtainMessage(MESSAGE_REGISTER_SDP_RECORDS, 3, -1), 500); 456bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly break; 457bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly case 3: 458bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly Log.d(TAG, "Registering opush record"); 45903c707ab6fc97e99b1603b8d6edc604dbea3cd6fNick Pelly SystemService.start("opush"); 460bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly mHandler.sendMessageDelayed( 461bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly mHandler.obtainMessage(MESSAGE_REGISTER_SDP_RECORDS, 4, -1), 500); 462bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly break; 463bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly case 4: 464bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly Log.d(TAG, "Registering pbap record"); 46567542964876aa7e4216e8f69f21dda68e7463b9aJaikumar Ganesh SystemService.start("pbap"); 466bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly break; 4679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 468105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project break; 469105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project case MESSAGE_FINISH_DISABLE: 470105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project finishDisable(msg.arg1 != 0); 471105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project break; 4721caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh case MESSAGE_UUID_INTENT: 4731caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh String address = (String)msg.obj; 47416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly if (address != null) { 4751caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh sendUuidIntent(address); 47616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly makeServiceChannelCallbacks(address); 47716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } 4781caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh break; 47912835478ee687a493d1b5882e67b6725bd539c26Nick Pelly case MESSAGE_DISCOVERABLE_TIMEOUT: 48012835478ee687a493d1b5882e67b6725bd539c26Nick Pelly int mode = msg.arg1; 4818c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh if (isEnabledInternal()) { 48212835478ee687a493d1b5882e67b6725bd539c26Nick Pelly // TODO: Switch back to the previous scan mode 48312835478ee687a493d1b5882e67b6725bd539c26Nick Pelly // This is ok for now, because we only use 48412835478ee687a493d1b5882e67b6725bd539c26Nick Pelly // CONNECTABLE and CONNECTABLE_DISCOVERABLE 48512835478ee687a493d1b5882e67b6725bd539c26Nick Pelly setScanMode(BluetoothAdapter.SCAN_MODE_CONNECTABLE, -1); 48612835478ee687a493d1b5882e67b6725bd539c26Nick Pelly } 48712835478ee687a493d1b5882e67b6725bd539c26Nick Pelly break; 4889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project }; 4919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private EnableThread mEnableThread; 4939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private class EnableThread extends Thread { 4959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private final boolean mSaveSetting; 496105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project public EnableThread(boolean saveSetting) { 4979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mSaveSetting = saveSetting; 4989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void run() { 5009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean res = (enableNative() == 0); 5019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (res) { 502b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project int retryCount = 2; 503b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project boolean running = false; 504b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project while ((retryCount-- > 0) && !running) { 505b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project mEventLoop.start(); 506105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project // it may take a momement for the other thread to do its 507b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project // thing. Check periodically for a while. 508b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project int pollCount = 5; 509b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project while ((pollCount-- > 0) && !running) { 510b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project if (mEventLoop.isEventLoopRunning()) { 511b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project running = true; 512b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project break; 513b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project } 514b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project try { 515b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project Thread.sleep(100); 516b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project } catch (InterruptedException e) {} 517b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project } 518b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project } 519b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project if (!running) { 520b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project log("bt EnableThread giving up"); 521b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project res = false; 522b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project disableNative(); 523b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project } 5249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (res) { 528d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh if (!setupNativeDataNative()) { 529d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh return; 530d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh } 5319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mSaveSetting) { 5329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project persistBluetoothOnSetting(true); 5339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mIsDiscovering = false; 535c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh mBondState.readAutoPairingData(); 5369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mBondState.loadBondState(); 537bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly mHandler.sendMessageDelayed( 538bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly mHandler.obtainMessage(MESSAGE_REGISTER_SDP_RECORDS, 1, -1), 3000); 5399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 540105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project // Log bluetooth on to battery stats. 541105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project long ident = Binder.clearCallingIdentity(); 542105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project try { 543105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project mBatteryStats.noteBluetoothOn(); 544105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project } catch (RemoteException e) { 545105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project } finally { 546105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project Binder.restoreCallingIdentity(ident); 547105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project } 5489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 549105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project 550105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project mEnableThread = null; 551105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project 552105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project setBluetoothState(res ? 553de893f550301a60274e87aa8168225e7a7a42184Nick Pelly BluetoothAdapter.STATE_ON : 554de893f550301a60274e87aa8168225e7a7a42184Nick Pelly BluetoothAdapter.STATE_OFF); 555105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project 556b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project if (res) { 557105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project // Update mode 558d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh String[] propVal = {"Pairable", getProperty("Pairable")}; 559d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh mEventLoop.onPropertyChanged(propVal); 560b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project } 561b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project 56244303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey if (mIsAirplaneSensitive && isAirplaneModeOn() && !mIsAirplaneToggleable) { 5635c43f735d94a538dc273c8f859d1100a7cdd5c71Daisuke Miyakawa disable(false); 5645c43f735d94a538dc273c8f859d1100a7cdd5c71Daisuke Miyakawa } 5655c43f735d94a538dc273c8f859d1100a7cdd5c71Daisuke Miyakawa 5669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void persistBluetoothOnSetting(boolean bluetoothOn) { 5709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project long origCallerIdentityToken = Binder.clearCallingIdentity(); 5719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Settings.Secure.putInt(mContext.getContentResolver(), Settings.Secure.BLUETOOTH_ON, 5729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project bluetoothOn ? 1 : 0); 5739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Binder.restoreCallingIdentity(origCallerIdentityToken); 5749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* package */ BondState getBondState() { 5779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mBondState; 5789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** local cache of bonding state. 5819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* we keep our own state to track the intermediate state BONDING, which 5829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* bluez does not track. 5839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * All addreses must be passed in upper case. 5849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 5859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public class BondState { 5869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private final HashMap<String, Integer> mState = new HashMap<String, Integer>(); 5879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private final HashMap<String, Integer> mPinAttempt = new HashMap<String, Integer>(); 588c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh 589c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh private static final String AUTO_PAIRING_BLACKLIST = 590c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh "/etc/bluetooth/auto_pairing.conf"; 591c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh private static final String DYNAMIC_AUTO_PAIRING_BLACKLIST = 592c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh "/data/misc/bluetooth/dynamic_auto_pairing.conf"; 593c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh private ArrayList<String> mAutoPairingAddressBlacklist; 594c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh private ArrayList<String> mAutoPairingExactNameBlacklist; 595c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh private ArrayList<String> mAutoPairingPartialNameBlacklist; 596c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh // Addresses added to blacklist dynamically based on usage. 597c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh private ArrayList<String> mAutoPairingDynamicAddressBlacklist; 598c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh 599482d54bb0cd9e00fd929185c31fea3ad845d97bcJaikumar Ganesh 6002092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh // If this is an outgoing connection, store the address. 6012092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh // There can be only 1 pending outgoing connection at a time, 6022092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh private String mPendingOutgoingBonding; 6032092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh 6042092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh private synchronized void setPendingOutgoingBonding(String address) { 6052092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh mPendingOutgoingBonding = address; 6062092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh } 6072092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh 6082092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh public synchronized String getPendingOutgoingBonding() { 6092092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh return mPendingOutgoingBonding; 6102092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh } 6112092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh 6129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public synchronized void loadBondState() { 613de893f550301a60274e87aa8168225e7a7a42184Nick Pelly if (mBluetoothState != BluetoothAdapter.STATE_TURNING_ON) { 6149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 6159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 616d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh String []bonds = null; 617b148bc844e5eddb07bef2fd1b4b754716decb43eJaikumar Ganesh String val = getPropertyInternal("Devices"); 618d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh if (val != null) { 619d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh bonds = val.split(","); 620d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh } 6219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (bonds == null) { 6229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 6239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mState.clear(); 6259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (DBG) log("found " + bonds.length + " bonded devices"); 626d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh for (String device : bonds) { 627d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh mState.put(getAddressFromObjectPath(device).toUpperCase(), 628d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh BluetoothDevice.BOND_BONDED); 6299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public synchronized void setBondState(String address, int state) { 6339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project setBondState(address, state, 0); 6349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** reason is ignored unless state == BOND_NOT_BONDED */ 6379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public synchronized void setBondState(String address, int state, int reason) { 6389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int oldState = getBondState(address); 6399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (oldState == state) { 6409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 6419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6422092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh 6432092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh // Check if this was an pending outgoing bonding. 6442092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh // If yes, reset the state. 6452092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh if (oldState == BluetoothDevice.BOND_BONDING) { 6462092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh if (address.equals(mPendingOutgoingBonding)) { 6472092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh mPendingOutgoingBonding = null; 6482092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh } 6492092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh } 6502092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh 6519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (DBG) log(address + " bond state " + oldState + " -> " + state + " (" + 6529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project reason + ")"); 653005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly Intent intent = new Intent(BluetoothDevice.ACTION_BOND_STATE_CHANGED); 654005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mAdapter.getRemoteDevice(address)); 655005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly intent.putExtra(BluetoothDevice.EXTRA_BOND_STATE, state); 656005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly intent.putExtra(BluetoothDevice.EXTRA_PREVIOUS_BOND_STATE, oldState); 657005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly if (state == BluetoothDevice.BOND_NONE) { 6589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (reason <= 0) { 6599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.w(TAG, "setBondState() called to unbond device, but reason code is " + 6609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "invalid. Overriding reason code with BOND_RESULT_REMOVED"); 6619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project reason = BluetoothDevice.UNBOND_REASON_REMOVED; 6629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 663005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly intent.putExtra(BluetoothDevice.EXTRA_REASON, reason); 6649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mState.remove(address); 6659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 6669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mState.put(address, state); 6679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mContext.sendBroadcast(intent, BLUETOOTH_PERM); 6709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean isAutoPairingBlacklisted(String address) { 673c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh if (mAutoPairingAddressBlacklist != null) { 674c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh for (String blacklistAddress : mAutoPairingAddressBlacklist) { 675c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh if (address.startsWith(blacklistAddress)) return true; 676c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh } 6779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 678482d54bb0cd9e00fd929185c31fea3ad845d97bcJaikumar Ganesh 679c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh if (mAutoPairingDynamicAddressBlacklist != null) { 680c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh for (String blacklistAddress: mAutoPairingDynamicAddressBlacklist) { 681c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh if (address.equals(blacklistAddress)) return true; 682c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh } 683c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh } 684482d54bb0cd9e00fd929185c31fea3ad845d97bcJaikumar Ganesh String name = getRemoteName(address); 685482d54bb0cd9e00fd929185c31fea3ad845d97bcJaikumar Ganesh if (name != null) { 686c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh if (mAutoPairingExactNameBlacklist != null) { 687c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh for (String blacklistName : mAutoPairingExactNameBlacklist) { 688c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh if (name.equals(blacklistName)) return true; 689c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh } 690738ed80262aa26128924c51f59ffd49e1163eb8dJaikumar Ganesh } 691738ed80262aa26128924c51f59ffd49e1163eb8dJaikumar Ganesh 692c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh if (mAutoPairingPartialNameBlacklist != null) { 693c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh for (String blacklistName : mAutoPairingPartialNameBlacklist) { 694c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh if (name.startsWith(blacklistName)) return true; 695c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh } 696482d54bb0cd9e00fd929185c31fea3ad845d97bcJaikumar Ganesh } 697482d54bb0cd9e00fd929185c31fea3ad845d97bcJaikumar Ganesh } 6989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 6999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public synchronized int getBondState(String address) { 7029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Integer state = mState.get(address); 7039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (state == null) { 704005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly return BluetoothDevice.BOND_NONE; 7059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return state.intValue(); 7079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 709e5d93b7ed983f98855555d560faf060836f1a52fJaikumar Ganesh /*package*/ synchronized String[] listInState(int state) { 7109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ArrayList<String> result = new ArrayList<String>(mState.size()); 7119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (Map.Entry<String, Integer> e : mState.entrySet()) { 7129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (e.getValue().intValue() == state) { 7139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project result.add(e.getKey()); 7149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return result.toArray(new String[result.size()]); 7179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public synchronized void addAutoPairingFailure(String address) { 720c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh if (mAutoPairingDynamicAddressBlacklist == null) { 721c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh mAutoPairingDynamicAddressBlacklist = new ArrayList<String>(); 7229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 723c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh 724c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh updateAutoPairingData(address); 725c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh mAutoPairingDynamicAddressBlacklist.add(address); 7269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public synchronized boolean isAutoPairingAttemptsInProgress(String address) { 7299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return getAttempt(address) != 0; 7309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public synchronized void clearPinAttempts(String address) { 7339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPinAttempt.remove(address); 7349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public synchronized boolean hasAutoPairingFailed(String address) { 737c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh if (mAutoPairingDynamicAddressBlacklist == null) return false; 738c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh 739c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh return mAutoPairingDynamicAddressBlacklist.contains(address); 7409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public synchronized int getAttempt(String address) { 7439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Integer attempt = mPinAttempt.get(address); 7449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (attempt == null) { 7459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return 0; 7469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return attempt.intValue(); 7489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public synchronized void attempt(String address) { 7519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Integer attempt = mPinAttempt.get(address); 7529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int newAttempt; 7539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (attempt == null) { 7549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project newAttempt = 1; 7559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 7569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project newAttempt = attempt.intValue() + 1; 7579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPinAttempt.put(address, new Integer(newAttempt)); 7599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 761c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh private void copyAutoPairingData() { 762c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh File file = null; 763c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh FileInputStream in = null; 764c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh FileOutputStream out = null; 765c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh try { 766c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh file = new File(DYNAMIC_AUTO_PAIRING_BLACKLIST); 767c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh if (file.exists()) return; 768c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh 769c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh in = new FileInputStream(AUTO_PAIRING_BLACKLIST); 770c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh out= new FileOutputStream(DYNAMIC_AUTO_PAIRING_BLACKLIST); 771c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh 772c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh byte[] buf = new byte[1024]; 773c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh int len; 774c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh while ((len = in.read(buf)) > 0) { 775c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh out.write(buf, 0, len); 776c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh } 777c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh } catch (FileNotFoundException e) { 778c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh log("FileNotFoundException: in copyAutoPairingData"); 779c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh } catch (IOException e) { 780c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh log("IOException: in copyAutoPairingData"); 781c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh } finally { 782c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh try { 783c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh if (in != null) in.close(); 784c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh if (out != null) out.close(); 785c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh } catch (IOException e) {} 786c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh } 787c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh } 788c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh 789c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh public void readAutoPairingData() { 790c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh if (mAutoPairingAddressBlacklist != null) return; 791c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh copyAutoPairingData(); 792c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh FileInputStream fstream = null; 793c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh try { 794c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh fstream = new FileInputStream(DYNAMIC_AUTO_PAIRING_BLACKLIST); 795c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh DataInputStream in = new DataInputStream(fstream); 796c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh BufferedReader file = new BufferedReader(new InputStreamReader(in)); 797c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh String line; 798c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh while((line = file.readLine()) != null) { 799c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh line = line.trim(); 800c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh if (line.length() == 0 || line.startsWith("//")) continue; 801c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh String[] value = line.split("="); 802c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh if (value != null && value.length == 2) { 803c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh String[] val = value[1].split(","); 804c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh if (value[0].equalsIgnoreCase("AddressBlacklist")) { 805c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh mAutoPairingAddressBlacklist = 806c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh new ArrayList<String>(Arrays.asList(val)); 807c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh } else if (value[0].equalsIgnoreCase("ExactNameBlacklist")) { 808c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh mAutoPairingExactNameBlacklist = 809c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh new ArrayList<String>(Arrays.asList(val)); 810c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh } else if (value[0].equalsIgnoreCase("PartialNameBlacklist")) { 811c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh mAutoPairingPartialNameBlacklist = 812c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh new ArrayList<String>(Arrays.asList(val)); 813c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh } else if (value[0].equalsIgnoreCase("DynamicAddressBlacklist")) { 814c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh mAutoPairingDynamicAddressBlacklist = 815c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh new ArrayList<String>(Arrays.asList(val)); 816c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh } else { 817c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh Log.e(TAG, "Error parsing Auto pairing blacklist file"); 818c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh } 819c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh } 820c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh } 821c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh } catch (FileNotFoundException e) { 822c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh log("FileNotFoundException: readAutoPairingData" + e.toString()); 823c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh } catch (IOException e) { 824c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh log("IOException: readAutoPairingData" + e.toString()); 825c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh } finally { 826c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh if (fstream != null) { 827c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh try { 828c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh fstream.close(); 829c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh } catch (IOException e) { 830c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh // Ignore 831c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh } 832c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh } 833c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh } 834c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh } 835c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh 836c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh // This function adds a bluetooth address to the auto pairing blacklis 837c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh // file. These addresses are added to DynamicAddressBlacklistSection 838c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh private void updateAutoPairingData(String address) { 839c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh BufferedWriter out = null; 840c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh try { 841c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh out = new BufferedWriter(new FileWriter(DYNAMIC_AUTO_PAIRING_BLACKLIST, true)); 842c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh StringBuilder str = new StringBuilder(); 843c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh if (mAutoPairingDynamicAddressBlacklist.size() == 0) { 844c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh str.append("DynamicAddressBlacklist="); 845c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh } 846c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh str.append(address); 847c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh str.append(","); 848c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh out.write(str.toString()); 849c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh } catch (FileNotFoundException e) { 850c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh log("FileNotFoundException: updateAutoPairingData" + e.toString()); 851c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh } catch (IOException e) { 852c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh log("IOException: updateAutoPairingData" + e.toString()); 853c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh } finally { 854c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh if (out != null) { 855c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh try { 856c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh out.close(); 857c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh } catch (IOException e) { 858c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh // Ignore 859c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh } 860c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh } 861c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh } 862c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh } 8639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static String toBondStateString(int bondState) { 8669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project switch (bondState) { 867005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly case BluetoothDevice.BOND_NONE: 8689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return "not bonded"; 8699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case BluetoothDevice.BOND_BONDING: 8709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return "bonding"; 8719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case BluetoothDevice.BOND_BONDED: 8729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return "bonded"; 8739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project default: 8749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return "??????"; 8759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8789519ce75f15ba287a641166c1b7ed10f2aa73f74Jaikumar Ganesh /*package*/ synchronized boolean isAdapterPropertiesEmpty() { 8799519ce75f15ba287a641166c1b7ed10f2aa73f74Jaikumar Ganesh return mAdapterProperties.isEmpty(); 8809519ce75f15ba287a641166c1b7ed10f2aa73f74Jaikumar Ganesh } 8819519ce75f15ba287a641166c1b7ed10f2aa73f74Jaikumar Ganesh 882d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh /*package*/synchronized void getAllProperties() { 8838c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh 8849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 885bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly mAdapterProperties.clear(); 886d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh 887d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh String properties[] = (String [])getAdapterPropertiesNative(); 888d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh // The String Array consists of key-value pairs. 889d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh if (properties == null) { 890d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh Log.e(TAG, "*Error*: GetAdapterProperties returned NULL"); 891d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh return; 892d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh } 893d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh 8948bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh for (int i = 0; i < properties.length; i++) { 8958bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh String name = properties[i]; 896efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh String newValue = null; 8978bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh int len; 8988bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh if (name == null) { 8998bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh Log.e(TAG, "Error:Adapter Property at index" + i + "is null"); 9008bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh continue; 9018bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh } 9028bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh if (name.equals("Devices")) { 903efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh StringBuilder str = new StringBuilder(); 9048bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh len = Integer.valueOf(properties[++i]); 9058bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh for (int j = 0; j < len; j++) { 906efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh str.append(properties[++i]); 907efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh str.append(","); 908efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh } 909efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh if (len > 0) { 910efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh newValue = str.toString(); 9118bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh } 9128bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh } else { 9138bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh newValue = properties[++i]; 9148bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh } 915bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly mAdapterProperties.put(name, newValue); 916d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh } 917d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh 918d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh // Add adapter object path property. 919d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh String adapterPath = getAdapterPathNative(); 920d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh if (adapterPath != null) 921bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly mAdapterProperties.put("ObjectPath", adapterPath + "/dev_"); 9229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 924d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh /* package */ synchronized void setProperty(String name, String value) { 925bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly mAdapterProperties.put(name, value); 9269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public synchronized boolean setName(String name) { 9299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 9309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Need BLUETOOTH_ADMIN permission"); 9319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (name == null) { 9329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 9339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 934d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh return setPropertyString("Name", name); 9359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 937d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh //TODO(): setPropertyString, setPropertyInteger, setPropertyBoolean 938d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh // Either have a single property function with Object as the parameter 939d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh // or have a function for each property and then obfuscate in the JNI layer. 940d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh // The following looks dirty. 941d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh private boolean setPropertyString(String key, String value) { 9429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 9438c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh if (!isEnabledInternal()) return false; 944d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh return setAdapterPropertyStringNative(key, value); 9459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 947d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh private boolean setPropertyInteger(String key, int value) { 948d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 9498c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh if (!isEnabledInternal()) return false; 950d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh return setAdapterPropertyIntegerNative(key, value); 951d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh } 9529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 953d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh private boolean setPropertyBoolean(String key, boolean value) { 954d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 9558c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh if (!isEnabledInternal()) return false; 956d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh return setAdapterPropertyBooleanNative(key, value ? 1 : 0); 9579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 959d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh /** 960d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh * Set the discoverability window for the device. A timeout of zero 961d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh * makes the device permanently discoverable (if the device is 962d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh * discoverable). Setting the timeout to a nonzero value does not make 963d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh * a device discoverable; you need to call setMode() to make the device 964d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh * explicitly discoverable. 965d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh * 966d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh * @param timeout_s The discoverable timeout in seconds. 967d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh */ 968d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh public synchronized boolean setDiscoverableTimeout(int timeout) { 9699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 9709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Need BLUETOOTH_ADMIN permission"); 971d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh return setPropertyInteger("DiscoverableTimeout", timeout); 9729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 97412835478ee687a493d1b5882e67b6725bd539c26Nick Pelly public synchronized boolean setScanMode(int mode, int duration) { 97518b1e79a123b979d25bfa5d0b0ee5d0382dbd64bNick Pelly mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS, 97618b1e79a123b979d25bfa5d0b0ee5d0382dbd64bNick Pelly "Need WRITE_SECURE_SETTINGS permission"); 977de893f550301a60274e87aa8168225e7a7a42184Nick Pelly boolean pairable = false; 978de893f550301a60274e87aa8168225e7a7a42184Nick Pelly boolean discoverable = false; 97912835478ee687a493d1b5882e67b6725bd539c26Nick Pelly 980de893f550301a60274e87aa8168225e7a7a42184Nick Pelly switch (mode) { 981de893f550301a60274e87aa8168225e7a7a42184Nick Pelly case BluetoothAdapter.SCAN_MODE_NONE: 98212835478ee687a493d1b5882e67b6725bd539c26Nick Pelly mHandler.removeMessages(MESSAGE_DISCOVERABLE_TIMEOUT); 983d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh pairable = false; 984d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh discoverable = false; 985de893f550301a60274e87aa8168225e7a7a42184Nick Pelly break; 986de893f550301a60274e87aa8168225e7a7a42184Nick Pelly case BluetoothAdapter.SCAN_MODE_CONNECTABLE: 98712835478ee687a493d1b5882e67b6725bd539c26Nick Pelly mHandler.removeMessages(MESSAGE_DISCOVERABLE_TIMEOUT); 988d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh pairable = true; 989d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh discoverable = false; 990005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly break; 991de893f550301a60274e87aa8168225e7a7a42184Nick Pelly case BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE: 99212835478ee687a493d1b5882e67b6725bd539c26Nick Pelly mHandler.removeMessages(MESSAGE_DISCOVERABLE_TIMEOUT); 993d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh pairable = true; 994d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh discoverable = true; 99512835478ee687a493d1b5882e67b6725bd539c26Nick Pelly Message msg = mHandler.obtainMessage(MESSAGE_DISCOVERABLE_TIMEOUT); 99612835478ee687a493d1b5882e67b6725bd539c26Nick Pelly mHandler.sendMessageDelayed(msg, duration * 1000); 99712835478ee687a493d1b5882e67b6725bd539c26Nick Pelly if (DBG) Log.d(TAG, "BT Discoverable for " + duration + " seconds"); 998005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly break; 999de893f550301a60274e87aa8168225e7a7a42184Nick Pelly default: 1000de893f550301a60274e87aa8168225e7a7a42184Nick Pelly Log.w(TAG, "Requested invalid scan mode " + mode); 1001de893f550301a60274e87aa8168225e7a7a42184Nick Pelly return false; 1002d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh } 1003d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh setPropertyBoolean("Pairable", pairable); 1004d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh setPropertyBoolean("Discoverable", discoverable); 10059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1006d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh return true; 10079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1009b148bc844e5eddb07bef2fd1b4b754716decb43eJaikumar Ganesh /*package*/ synchronized String getProperty(String name) { 1010b148bc844e5eddb07bef2fd1b4b754716decb43eJaikumar Ganesh if (!isEnabledInternal()) return null; 1011b148bc844e5eddb07bef2fd1b4b754716decb43eJaikumar Ganesh return getPropertyInternal(name); 1012b148bc844e5eddb07bef2fd1b4b754716decb43eJaikumar Ganesh } 1013b148bc844e5eddb07bef2fd1b4b754716decb43eJaikumar Ganesh 1014b148bc844e5eddb07bef2fd1b4b754716decb43eJaikumar Ganesh /*package*/ synchronized String getPropertyInternal(String name) { 1015bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly if (!mAdapterProperties.isEmpty()) 1016bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly return mAdapterProperties.get(name); 1017d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh getAllProperties(); 1018bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly return mAdapterProperties.get(name); 10199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1021d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh public synchronized String getAddress() { 1022d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1023d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh return getProperty("Address"); 10249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1026d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh public synchronized String getName() { 10279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1028d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh return getProperty("Name"); 10299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1032d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh * Returns the user-friendly name of a remote device. This value is 1033d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh * returned from our local cache, which is updated when onPropertyChange 1034d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh * event is received. 1035d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh * Do not expect to retrieve the updated remote name immediately after 1036d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh * changing the name on the remote device. 10379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 1038d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh * @param address Bluetooth address of remote device. 1039d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh * 1040d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh * @return The user-friendly name of the specified remote device. 10419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1042d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh public synchronized String getRemoteName(String address) { 1043d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1044005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly if (!BluetoothAdapter.checkBluetoothAddress(address)) { 1045d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh return null; 1046d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh } 104755929a958bf0e482c8e4d7df3dd75957f1e9d871Jaikumar Ganesh return getRemoteDeviceProperty(address, "Name"); 10489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 10519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Get the discoverability window for the device. A timeout of zero 10529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * means that the device is permanently discoverable (if the device is 10539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * in the discoverable mode). 10549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 10559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return The discoverability window of the device, in seconds. A negative 10569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * value indicates an error. 10579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 10589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public synchronized int getDiscoverableTimeout() { 10599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1060d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh String timeout = getProperty("DiscoverableTimeout"); 1061d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh if (timeout != null) 1062d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh return Integer.valueOf(timeout); 1063d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh else 1064d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh return -1; 10659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public synchronized int getScanMode() { 10689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 10698c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh if (!isEnabledInternal()) 1070de893f550301a60274e87aa8168225e7a7a42184Nick Pelly return BluetoothAdapter.SCAN_MODE_NONE; 1071d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh 1072d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh boolean pairable = getProperty("Pairable").equals("true"); 1073d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh boolean discoverable = getProperty("Discoverable").equals("true"); 1074d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh return bluezStringToScanMode (pairable, discoverable); 10759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1077d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh public synchronized boolean startDiscovery() { 10789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 10799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Need BLUETOOTH_ADMIN permission"); 10808c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh if (!isEnabledInternal()) return false; 10818c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh 1082d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh return startDiscoveryNative(); 10839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1085d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh public synchronized boolean cancelDiscovery() { 10869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 10879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Need BLUETOOTH_ADMIN permission"); 10888c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh if (!isEnabledInternal()) return false; 10898c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh 1090d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh return stopDiscoveryNative(); 1091d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh } 1092d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh 1093d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh public synchronized boolean isDiscovering() { 1094d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1095d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh return mIsDiscovering; 1096d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh } 1097d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh 1098d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh /* package */ void setIsDiscovering(boolean isDiscovering) { 1099d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh mIsDiscovering = isDiscovering; 11009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public synchronized boolean createBond(String address) { 11039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 11049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Need BLUETOOTH_ADMIN permission"); 11058c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh if (!isEnabledInternal()) return false; 11068c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh 1107005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly if (!BluetoothAdapter.checkBluetoothAddress(address)) { 11089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 11099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project address = address.toUpperCase(); 11119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11122092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh if (mBondState.getPendingOutgoingBonding() != null) { 11139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project log("Ignoring createBond(): another device is bonding"); 11149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // a different device is currently bonding, fail 11159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 11169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Check for bond state only if we are not performing auto 11199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // pairing exponential back-off attempts. 11209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!mBondState.isAutoPairingAttemptsInProgress(address) && 1121005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly mBondState.getBondState(address) != BluetoothDevice.BOND_NONE) { 11229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project log("Ignoring createBond(): this device is already bonding or bonded"); 11239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 11249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11263fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh if (address.equals(mDockAddress)) { 11273fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh if (!writeDockPin()) { 11283fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh log("Error while writing Pin for the dock"); 11293fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh return false; 11303fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh } 11313fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh } 11323fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh 1133d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh if (!createPairedDeviceNative(address, 60000 /* 1 minute */)) { 11349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 11359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11372092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh mBondState.setPendingOutgoingBonding(address); 11389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mBondState.setBondState(address, BluetoothDevice.BOND_BONDING); 11392092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh 11409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 11419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public synchronized boolean cancelBondProcess(String address) { 11449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 11459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Need BLUETOOTH_ADMIN permission"); 11468c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh if (!isEnabledInternal()) return false; 11478c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh 1148005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly if (!BluetoothAdapter.checkBluetoothAddress(address)) { 11499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 11509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project address = address.toUpperCase(); 11529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mBondState.getBondState(address) != BluetoothDevice.BOND_BONDING) { 11539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 11549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1156005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly mBondState.setBondState(address, BluetoothDevice.BOND_NONE, 11579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project BluetoothDevice.UNBOND_REASON_AUTH_CANCELED); 1158d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh cancelDeviceCreationNative(address); 11599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 11609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public synchronized boolean removeBond(String address) { 11639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 11649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Need BLUETOOTH_ADMIN permission"); 11658c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh if (!isEnabledInternal()) return false; 11668c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh 1167005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly if (!BluetoothAdapter.checkBluetoothAddress(address)) { 11689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 11699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1170d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh return removeDeviceNative(getObjectPathFromAddress(address)); 11719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public synchronized String[] listBonds() { 11749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 11759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mBondState.listInState(BluetoothDevice.BOND_BONDED); 11769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public synchronized int getBondState(String address) { 11799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1180005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly if (!BluetoothAdapter.checkBluetoothAddress(address)) { 1181b24e11baac589fe16426f2d243b460ab84991c7bNick Pelly return BluetoothDevice.ERROR; 11829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mBondState.getBondState(address.toUpperCase()); 11849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11863fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh public synchronized boolean isBluetoothDock(String address) { 11876e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh SharedPreferences sp = mContext.getSharedPreferences(SHARED_PREFERENCES_NAME, 11886e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh mContext.MODE_PRIVATE); 11896e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh 11906e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh return sp.contains(SHARED_PREFERENCE_DOCK_ADDRESS + address); 11913fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh } 11923fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh 11939488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh /*package*/ boolean isRemoteDeviceInCache(String address) { 1194bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly return (mDeviceProperties.get(address) != null); 11959488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh } 11969488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh 11979488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh /*package*/ String[] getRemoteDeviceProperties(String address) { 11988c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh if (!isEnabledInternal()) return null; 11998c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh 12009488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh String objectPath = getObjectPathFromAddress(address); 12019488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh return (String [])getDevicePropertiesNative(objectPath); 12029488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh } 12039488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh 1204d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh /*package*/ synchronized String getRemoteDeviceProperty(String address, String property) { 1205bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly Map<String, String> properties = mDeviceProperties.get(address); 1206d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh if (properties != null) { 1207d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh return properties.get(property); 1208d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh } else { 1209d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh // Query for remote device properties, again. 1210d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh // We will need to reload the cache when we switch Bluetooth on / off 1211d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh // or if we crash. 121210eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh if (updateRemoteDevicePropertiesCache(address)) 1213d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh return getRemoteDeviceProperty(address, property); 12149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1215d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh Log.e(TAG, "getRemoteDeviceProperty: " + property + "not present:" + address); 1216d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh return null; 12179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 121910eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh /* package */ synchronized boolean updateRemoteDevicePropertiesCache(String address) { 122010eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh String[] propValues = getRemoteDeviceProperties(address); 122110eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh if (propValues != null) { 122210eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh addRemoteDeviceProperties(address, propValues); 122310eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh return true; 122410eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh } 122510eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh return false; 122610eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh } 122710eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh 1228d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh /* package */ synchronized void addRemoteDeviceProperties(String address, String[] properties) { 1229395d1023660c5caedf7888def17f8ad826f51bf8Jaikumar Ganesh /* 1230395d1023660c5caedf7888def17f8ad826f51bf8Jaikumar Ganesh * We get a DeviceFound signal every time RSSI changes or name changes. 1231395d1023660c5caedf7888def17f8ad826f51bf8Jaikumar Ganesh * Don't create a new Map object every time */ 1232bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly Map<String, String> propertyValues = mDeviceProperties.get(address); 1233efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh if (propertyValues == null) { 1234395d1023660c5caedf7888def17f8ad826f51bf8Jaikumar Ganesh propertyValues = new HashMap<String, String>(); 1235395d1023660c5caedf7888def17f8ad826f51bf8Jaikumar Ganesh } 1236395d1023660c5caedf7888def17f8ad826f51bf8Jaikumar Ganesh 12378bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh for (int i = 0; i < properties.length; i++) { 12388bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh String name = properties[i]; 1239efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh String newValue = null; 12408bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh int len; 12418bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh if (name == null) { 12428bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh Log.e(TAG, "Error: Remote Device Property at index" + i + "is null"); 12438bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh continue; 12448bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh } 12458bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh if (name.equals("UUIDs") || name.equals("Nodes")) { 1246efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh StringBuilder str = new StringBuilder(); 12478bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh len = Integer.valueOf(properties[++i]); 12488bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh for (int j = 0; j < len; j++) { 1249efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh str.append(properties[++i]); 1250efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh str.append(","); 1251efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh } 1252efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh if (len > 0) { 1253efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh newValue = str.toString(); 12548bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh } 1255d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh } else { 12568bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh newValue = properties[++i]; 1257d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh } 1258efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh 12598bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh propertyValues.put(name, newValue); 12609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1261bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly mDeviceProperties.put(address, propertyValues); 126210eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh 126310eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh // We have added a new remote device or updated its properties. 126410eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh // Also update the serviceChannel cache. 126510eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh updateDeviceServiceChannelCache(address); 12669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1268d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh /* package */ void removeRemoteDeviceProperties(String address) { 1269bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly mDeviceProperties.remove(address); 12709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1272d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh /* package */ synchronized void setRemoteDeviceProperty(String address, String name, 1273d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh String value) { 1274bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly Map <String, String> propVal = mDeviceProperties.get(address); 1275d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh if (propVal != null) { 1276d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh propVal.put(name, value); 1277bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly mDeviceProperties.put(address, propVal); 1278d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh } else { 1279d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh Log.e(TAG, "setRemoteDeviceProperty for a device not in cache:" + address); 12809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1284efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue * Sets the remote device trust state. 1285efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue * 1286efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue * @return boolean to indicate operation success or fail 1287efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue */ 1288efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue public synchronized boolean setTrust(String address, boolean value) { 1289005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly if (!BluetoothAdapter.checkBluetoothAddress(address)) { 1290e6ee3be1c254404dad842298f6f56c11cc6c7ac8Nick Pelly mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 1291e6ee3be1c254404dad842298f6f56c11cc6c7ac8Nick Pelly "Need BLUETOOTH_ADMIN permission"); 1292efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue return false; 1293efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue } 1294efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue 12958c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh if (!isEnabledInternal()) return false; 12968c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh 1297efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue return setDevicePropertyBooleanNative(getObjectPathFromAddress(address), "Trusted", 1298efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue value ? 1 : 0); 1299efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue } 1300efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue 1301efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue /** 1302efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue * Gets the remote device trust state as boolean. 1303efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue * Note: this value may be 1304efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue * retrieved from cache if we retrieved the data before * 1305efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue * 1306efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue * @return boolean to indicate trust or untrust state 1307efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue */ 1308efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue public synchronized boolean getTrustState(String address) { 1309005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly if (!BluetoothAdapter.checkBluetoothAddress(address)) { 1310efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1311efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue return false; 1312efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue } 1313efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue 1314efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue String val = getRemoteDeviceProperty(address, "Trusted"); 1315efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue if (val == null) { 1316efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue return false; 1317efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue } else { 1318efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue return val.equals("true") ? true : false; 1319efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue } 1320efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue } 1321efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue 1322efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue /** 1323d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh * Gets the remote major, minor classes encoded as a 32-bit 13249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * integer. 13259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 13269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Note: this value is retrieved from cache, because we get it during 13279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * remote-device discovery. 13289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 13299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return 32-bit integer encoding the remote major, minor, and service 13309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * classes. 13319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 13329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public synchronized int getRemoteClass(String address) { 1333005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly if (!BluetoothAdapter.checkBluetoothAddress(address)) { 1334ea600ccfb7568f60377c4abc85f56c80af7fdbfcNick Pelly mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1335ea600ccfb7568f60377c4abc85f56c80af7fdbfcNick Pelly return BluetoothClass.ERROR; 13369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1337d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh String val = getRemoteDeviceProperty(address, "Class"); 1338d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh if (val == null) 1339d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh return BluetoothClass.ERROR; 1340d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh else { 1341d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh return Integer.valueOf(val); 1342d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh } 13439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1344d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh 13459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1347dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh * Gets the UUIDs supported by the remote device 13489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 1349dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh * @return array of 128bit ParcelUuids 13509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1351dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh public synchronized ParcelUuid[] getRemoteUuids(String address) { 13529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1353005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly if (!BluetoothAdapter.checkBluetoothAddress(address)) { 13549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return null; 13559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13561caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh return getUuidFromCache(address); 13571caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh } 13581caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh 13591caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh private ParcelUuid[] getUuidFromCache(String address) { 1360d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh String value = getRemoteDeviceProperty(address, "UUIDs"); 1361dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh if (value == null) return null; 1362dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh 1363dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh String[] uuidStrings = null; 1364d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh // The UUIDs are stored as a "," separated string. 1365dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh uuidStrings = value.split(","); 1366dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh ParcelUuid[] uuids = new ParcelUuid[uuidStrings.length]; 1367dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh 1368dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh for (int i = 0; i < uuidStrings.length; i++) { 1369dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh uuids[i] = ParcelUuid.fromString(uuidStrings[i]); 1370dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh } 1371d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh return uuids; 13729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 137416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly /** 137516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly * Connect and fetch new UUID's using SDP. 137616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly * The UUID's found are broadcast as intents. 137716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly * Optionally takes a uuid and callback to fetch the RFCOMM channel for the 137816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly * a given uuid. 137916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly * TODO: Don't wait UUID_INTENT_DELAY to broadcast UUID intents on success 138016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly * TODO: Don't wait UUID_INTENT_DELAY to handle the failure case for 138116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly * callback and broadcast intents. 138216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly */ 138316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly public synchronized boolean fetchRemoteUuids(String address, ParcelUuid uuid, 138416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly IBluetoothCallback callback) { 13851caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 13868c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh if (!isEnabledInternal()) return false; 13878c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh 13881caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh if (!BluetoothAdapter.checkBluetoothAddress(address)) { 13891caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh return false; 13901caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh } 13911caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh 139216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly RemoteService service = new RemoteService(address, uuid); 139316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly if (uuid != null && mUuidCallbackTracker.get(service) != null) { 139416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly // An SDP query for this address & uuid is already in progress 139516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly // Do not add this callback for the uuid 139616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly return false; 139716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } 139816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly 13991caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh if (mUuidIntentTracker.contains(address)) { 14001caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh // An SDP query for this address is already in progress 140116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly // Add this uuid onto the in-progress SDP query 140216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly if (uuid != null) { 140316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly mUuidCallbackTracker.put(new RemoteService(address, uuid), callback); 140416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } 14051caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh return true; 14061caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh } 14071caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh 14081caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh boolean ret; 14090e09030977aea8b40fd177139528d4b5637c9771Jaikumar Ganesh // Just do the SDP if the device is already created and UUIDs are not 14100e09030977aea8b40fd177139528d4b5637c9771Jaikumar Ganesh // NULL, else create the device and then do SDP. 14110e09030977aea8b40fd177139528d4b5637c9771Jaikumar Ganesh if (isRemoteDeviceInCache(address) && getRemoteUuids(address) != null) { 14121caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh String path = getObjectPathFromAddress(address); 14131caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh if (path == null) return false; 14141caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh 14151caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh // Use an empty string for the UUID pattern 14161caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh ret = discoverServicesNative(path, ""); 14171caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh } else { 14181caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh ret = createDeviceNative(address); 14191caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh } 14201caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh 14211caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh mUuidIntentTracker.add(address); 142216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly if (uuid != null) { 142316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly mUuidCallbackTracker.put(new RemoteService(address, uuid), callback); 142416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } 14251caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh 14261caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh Message message = mHandler.obtainMessage(MESSAGE_UUID_INTENT); 14271caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh message.obj = address; 14281caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh mHandler.sendMessageDelayed(message, UUID_INTENT_DELAY); 14291caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh return ret; 14301caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh } 14311caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh 14329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1433d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh * Gets the rfcomm channel associated with the UUID. 143416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly * Pulls records from the cache only. 14359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 1436d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh * @param address Address of the remote device 1437dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh * @param uuid ParcelUuid of the service attribute 14389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 1439d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh * @return rfcomm channel associated with the service attribute 144010eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh * -1 on error 14419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1442dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh public int getRemoteServiceChannel(String address, ParcelUuid uuid) { 14439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 14448c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh if (!isEnabledInternal()) return -1; 14458c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh 1446005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly if (!BluetoothAdapter.checkBluetoothAddress(address)) { 1447b24e11baac589fe16426f2d243b460ab84991c7bNick Pelly return BluetoothDevice.ERROR; 14489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 144910eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh // Check if we are recovering from a crash. 145010eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh if (mDeviceProperties.isEmpty()) { 145110eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh if (!updateRemoteDevicePropertiesCache(address)) 145210eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh return -1; 145310eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh } 145410eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh 145510eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh Map<ParcelUuid, Integer> value = mDeviceServiceChannelCache.get(address); 145610eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh if (value != null && value.containsKey(uuid)) 145710eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh return value.get(uuid); 145810eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh return -1; 14599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public synchronized boolean setPin(String address, byte[] pin) { 14629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 14639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Need BLUETOOTH_ADMIN permission"); 14648c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh if (!isEnabledInternal()) return false; 14658c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh 14669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (pin == null || pin.length <= 0 || pin.length > 16 || 1467005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly !BluetoothAdapter.checkBluetoothAddress(address)) { 14689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 14699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project address = address.toUpperCase(); 14719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Integer data = mEventLoop.getPasskeyAgentRequestData().remove(address); 14729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (data == null) { 14739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.w(TAG, "setPin(" + address + ") called but no native data available, " + 14749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "ignoring. Maybe the PasskeyAgent Request was cancelled by the remote device" + 14759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project " or by bluez.\n"); 14769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 14779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // bluez API wants pin as a string 14799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String pinString; 14809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 14819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project pinString = new String(pin, "UTF8"); 14829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (UnsupportedEncodingException uee) { 14839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.e(TAG, "UTF8 not supported?!?"); 14849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 14859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return setPinNative(address, pinString, data.intValue()); 14879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1489b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh public synchronized boolean setPasskey(String address, int passkey) { 1490b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 1491b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh "Need BLUETOOTH_ADMIN permission"); 14928c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh if (!isEnabledInternal()) return false; 14938c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh 1494005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly if (passkey < 0 || passkey > 999999 || !BluetoothAdapter.checkBluetoothAddress(address)) { 1495b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh return false; 1496b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh } 1497b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh address = address.toUpperCase(); 1498b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh Integer data = mEventLoop.getPasskeyAgentRequestData().remove(address); 1499b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh if (data == null) { 1500b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh Log.w(TAG, "setPasskey(" + address + ") called but no native data available, " + 1501b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh "ignoring. Maybe the PasskeyAgent Request was cancelled by the remote device" + 1502b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh " or by bluez.\n"); 1503b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh return false; 1504b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh } 1505b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh return setPasskeyNative(address, passkey, data.intValue()); 1506b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh } 1507b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh 1508b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh public synchronized boolean setPairingConfirmation(String address, boolean confirm) { 1509b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 1510b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh "Need BLUETOOTH_ADMIN permission"); 15118c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh if (!isEnabledInternal()) return false; 15128c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh 1513b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh address = address.toUpperCase(); 1514b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh Integer data = mEventLoop.getPasskeyAgentRequestData().remove(address); 1515b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh if (data == null) { 1516b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh Log.w(TAG, "setPasskey(" + address + ") called but no native data available, " + 1517b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh "ignoring. Maybe the PasskeyAgent Request was cancelled by the remote device" + 1518b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh " or by bluez.\n"); 1519b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh return false; 1520b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh } 1521b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh return setPairingConfirmationNative(address, confirm, data.intValue()); 1522b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh } 1523b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh 1524b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh public synchronized boolean cancelPairingUserInput(String address) { 15259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 15269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Need BLUETOOTH_ADMIN permission"); 15278c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh if (!isEnabledInternal()) return false; 15288c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh 1529005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly if (!BluetoothAdapter.checkBluetoothAddress(address)) { 15309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 15319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1532005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly mBondState.setBondState(address, BluetoothDevice.BOND_NONE, 1533397d8f4f4829a45f4fe7a672cc395466bbc0f442Jaikumar Ganesh BluetoothDevice.UNBOND_REASON_AUTH_CANCELED); 15349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project address = address.toUpperCase(); 15359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Integer data = mEventLoop.getPasskeyAgentRequestData().remove(address); 15369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (data == null) { 1537b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh Log.w(TAG, "cancelUserInputNative(" + address + ") called but no native data " + 1538b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh "available, ignoring. Maybe the PasskeyAgent Request was already cancelled " + 1539b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh "by the remote or by bluez.\n"); 15409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 15419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1542b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh return cancelPairingUserInputNative(address, data.intValue()); 15439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 15458c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh /*package*/ void updateDeviceServiceChannelCache(String address) { 154610eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh ParcelUuid[] deviceUuids = getRemoteUuids(address); 154710eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh // We are storing the rfcomm channel numbers only for the uuids 154810eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh // we are interested in. 154910eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh int channel; 155016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly if (DBG) log("updateDeviceServiceChannelCache(" + address + ")"); 155116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly 155216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly ArrayList<ParcelUuid> applicationUuids = new ArrayList(); 155316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly 155416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly synchronized (this) { 155516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly for (RemoteService service : mUuidCallbackTracker.keySet()) { 155616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly if (service.address.equals(address)) { 155716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly applicationUuids.add(service.uuid); 155816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } 155916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } 156016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } 156110eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh 156210eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh Map <ParcelUuid, Integer> value = new HashMap<ParcelUuid, Integer>(); 156316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly 156416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly // Retrieve RFCOMM channel for default uuids 156516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly for (ParcelUuid uuid : RFCOMM_UUIDS) { 156610eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh if (BluetoothUuid.isUuidPresent(deviceUuids, uuid)) { 156716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly channel = getDeviceServiceChannelNative(getObjectPathFromAddress(address), 156816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly uuid.toString(), 0x0004); 156916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly if (DBG) log("\tuuid(system): " + uuid + " " + channel); 157010eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh value.put(uuid, channel); 157110eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh } 157210eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh } 157316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly // Retrieve RFCOMM channel for application requested uuids 157416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly for (ParcelUuid uuid : applicationUuids) { 157516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly if (BluetoothUuid.isUuidPresent(deviceUuids, uuid)) { 157616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly channel = getDeviceServiceChannelNative(getObjectPathFromAddress(address), 157716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly uuid.toString(), 0x0004); 157816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly if (DBG) log("\tuuid(application): " + uuid + " " + channel); 157916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly value.put(uuid, channel); 158016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } 158116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } 158216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly 158316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly synchronized (this) { 158416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly // Make application callbacks 158516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly for (Iterator<RemoteService> iter = mUuidCallbackTracker.keySet().iterator(); 158616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly iter.hasNext();) { 158716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly RemoteService service = iter.next(); 158816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly if (service.address.equals(address)) { 158916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly channel = -1; 159016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly if (value.get(service.uuid) != null) { 159116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly channel = value.get(service.uuid); 159216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } 159316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly if (channel != -1) { 159416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly if (DBG) log("Making callback for " + service.uuid + " with result " + 159516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly channel); 159616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly IBluetoothCallback callback = mUuidCallbackTracker.get(service); 159716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly if (callback != null) { 159816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly try { 159916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly callback.onRfcommChannelFound(channel); 160016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } catch (RemoteException e) {Log.e(TAG, "", e);} 160116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } 160216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly 160316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly iter.remove(); 160416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } 160516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } 160616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } 160716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly 160816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly // Update cache 160916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly mDeviceServiceChannelCache.put(address, value); 161016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } 161110eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh } 161210eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh 161324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly /** 161424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly * b is a handle to a Binder instance, so that this service can be notified 161524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly * for Applications that terminate unexpectedly, to clean there service 161624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly * records 161724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly */ 161824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly public synchronized int addRfcommServiceRecord(String serviceName, ParcelUuid uuid, 161924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly int channel, IBinder b) { 16208c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 16218c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh if (!isEnabledInternal()) return -1; 16228c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh 162324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly if (serviceName == null || uuid == null || channel < 1 || 162424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly channel > BluetoothSocket.MAX_RFCOMM_CHANNEL) { 162524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly return -1; 162624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly } 162724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly if (BluetoothUuid.isUuidPresent(BluetoothUuid.RESERVED_UUIDS, uuid)) { 162824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly Log.w(TAG, "Attempted to register a reserved UUID: " + uuid); 162924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly return -1; 163024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly } 163124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly int handle = addRfcommServiceRecordNative(serviceName, 163224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly uuid.getUuid().getMostSignificantBits(), uuid.getUuid().getLeastSignificantBits(), 163324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly (short)channel); 163424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly if (DBG) log("new handle " + Integer.toHexString(handle)); 163524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly if (handle == -1) { 163624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly return -1; 163724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly } 163824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly 163924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly int pid = Binder.getCallingPid(); 164024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly mServiceRecordToPid.put(new Integer(handle), new Integer(pid)); 164124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly try { 164224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly b.linkToDeath(new Reaper(handle, pid), 0); 164324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly } catch (RemoteException e) {} 164424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly return handle; 164524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly } 164624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly 164724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly public void removeServiceRecord(int handle) { 164824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, 164924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly "Need BLUETOOTH permission"); 165024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly checkAndRemoveRecord(handle, Binder.getCallingPid()); 165124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly } 165224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly 165324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly private synchronized void checkAndRemoveRecord(int handle, int pid) { 165424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly Integer handleInt = new Integer(handle); 165524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly Integer owner = mServiceRecordToPid.get(handleInt); 165624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly if (owner != null && pid == owner.intValue()) { 165724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly if (DBG) log("Removing service record " + Integer.toHexString(handle) + " for pid " + 165824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly pid); 165924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly mServiceRecordToPid.remove(handleInt); 166024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly removeServiceRecordNative(handle); 166124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly } 166224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly } 166324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly 166424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly private class Reaper implements IBinder.DeathRecipient { 166524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly int pid; 166624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly int handle; 166724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly Reaper(int handle, int pid) { 166824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly this.pid = pid; 166924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly this.handle = handle; 167024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly } 167124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly public void binderDied() { 167224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly synchronized (BluetoothService.this) { 167324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly if (DBG) log("Tracked app " + pid + " died"); 167424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly checkAndRemoveRecord(handle, pid); 167524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly } 167624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly } 167724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly } 167824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly 16799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private final BroadcastReceiver mReceiver = new BroadcastReceiver() { 16809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 16819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void onReceive(Context context, Intent intent) { 16826e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh if (intent == null) return; 16836e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh 16849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String action = intent.getAction(); 16859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (action.equals(Intent.ACTION_AIRPLANE_MODE_CHANGED)) { 16869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ContentResolver resolver = context.getContentResolver(); 16879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Query the airplane mode from Settings.System just to make sure that 16889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // some random app is not sending this intent and disabling bluetooth 16899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean enabled = !isAirplaneModeOn(); 16909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // If bluetooth is currently expected to be on, then enable or disable bluetooth 16919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (Settings.Secure.getInt(resolver, Settings.Secure.BLUETOOTH_ON, 0) > 0) { 16929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (enabled) { 1693105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project enable(false); 16949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 16959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project disable(false); 16969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16986e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh } else if (Intent.ACTION_DOCK_EVENT.equals(action)) { 16996e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh int state = intent.getIntExtra(Intent.EXTRA_DOCK_STATE, 17006e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh Intent.EXTRA_DOCK_STATE_UNDOCKED); 17016e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh if (DBG) Log.v(TAG, "Received ACTION_DOCK_EVENT with State:" + state); 17026e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh if (state == Intent.EXTRA_DOCK_STATE_UNDOCKED) { 17036e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh mDockAddress = null; 17046e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh mDockPin = null; 17056e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh } else { 17066e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh SharedPreferences.Editor editor = 17076e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh mContext.getSharedPreferences(SHARED_PREFERENCES_NAME, 17086e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh mContext.MODE_PRIVATE).edit(); 17096e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh editor.putBoolean(SHARED_PREFERENCE_DOCK_ADDRESS + mDockAddress, true); 17106e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh editor.commit(); 17116e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh } 17129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project }; 17159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 17166e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh private void registerForAirplaneMode(IntentFilter filter) { 171744303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey final ContentResolver resolver = mContext.getContentResolver(); 171844303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey final String airplaneModeRadios = Settings.System.getString(resolver, 17199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Settings.System.AIRPLANE_MODE_RADIOS); 172044303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey final String toggleableRadios = Settings.System.getString(resolver, 172144303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey Settings.System.AIRPLANE_MODE_TOGGLEABLE_RADIOS); 172244303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey 172344303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey mIsAirplaneSensitive = airplaneModeRadios == null ? true : 172444303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey airplaneModeRadios.contains(Settings.System.RADIO_BLUETOOTH); 172544303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey mIsAirplaneToggleable = toggleableRadios == null ? false : 172644303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey toggleableRadios.contains(Settings.System.RADIO_BLUETOOTH); 172744303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey 17289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mIsAirplaneSensitive) { 17296e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED); 17309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 17339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* Returns true if airplane mode is currently on */ 17349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private final boolean isAirplaneModeOn() { 17359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return Settings.System.getInt(mContext.getContentResolver(), 17369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Settings.System.AIRPLANE_MODE_ON, 0) == 1; 17379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 17391caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh /* Broadcast the Uuid intent */ 17401caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh /*package*/ synchronized void sendUuidIntent(String address) { 17416179965e85ec17b836084a4a3d7963d8a7a1e1ccJaikumar Ganesh ParcelUuid[] uuid = getUuidFromCache(address); 17426179965e85ec17b836084a4a3d7963d8a7a1e1ccJaikumar Ganesh Intent intent = new Intent(BluetoothDevice.ACTION_UUID); 17432d3b98d868cda30535505b2a2fba47aa1c9c052bJaikumar Ganesh intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mAdapter.getRemoteDevice(address)); 17446179965e85ec17b836084a4a3d7963d8a7a1e1ccJaikumar Ganesh intent.putExtra(BluetoothDevice.EXTRA_UUID, uuid); 17456179965e85ec17b836084a4a3d7963d8a7a1e1ccJaikumar Ganesh mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM); 17461caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh 17476179965e85ec17b836084a4a3d7963d8a7a1e1ccJaikumar Ganesh if (mUuidIntentTracker.contains(address)) 17481caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh mUuidIntentTracker.remove(address); 174916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly 175016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } 175116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly 175216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly /*package*/ synchronized void makeServiceChannelCallbacks(String address) { 175316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly for (Iterator<RemoteService> iter = mUuidCallbackTracker.keySet().iterator(); 175416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly iter.hasNext();) { 175516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly RemoteService service = iter.next(); 175616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly if (service.address.equals(address)) { 175716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly if (DBG) log("Cleaning up failed UUID channel lookup: " + service.address + 175816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly " " + service.uuid); 175916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly IBluetoothCallback callback = mUuidCallbackTracker.get(service); 176016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly if (callback != null) { 176116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly try { 176216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly callback.onRfcommChannelFound(-1); 176316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } catch (RemoteException e) {Log.e(TAG, "", e);} 176416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } 176516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly 176616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly iter.remove(); 176716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } 176816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } 17691caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh } 17701caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh 17719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 17729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 1773105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project switch(mBluetoothState) { 1774de893f550301a60274e87aa8168225e7a7a42184Nick Pelly case BluetoothAdapter.STATE_OFF: 177524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly pw.println("Bluetooth OFF\n"); 1776105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project return; 1777de893f550301a60274e87aa8168225e7a7a42184Nick Pelly case BluetoothAdapter.STATE_TURNING_ON: 177824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly pw.println("Bluetooth TURNING ON\n"); 1779105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project return; 1780de893f550301a60274e87aa8168225e7a7a42184Nick Pelly case BluetoothAdapter.STATE_TURNING_OFF: 178124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly pw.println("Bluetooth TURNING OFF\n"); 1782105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project return; 1783de893f550301a60274e87aa8168225e7a7a42184Nick Pelly case BluetoothAdapter.STATE_ON: 178424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly pw.println("Bluetooth ON\n"); 1785105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project } 1786105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project 178724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly pw.println("mIsAirplaneSensitive = " + mIsAirplaneSensitive); 178844303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey pw.println("mIsAirplaneToggleable = " + mIsAirplaneToggleable); 178924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly 179024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly pw.println("Local address = " + getAddress()); 179124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly pw.println("Local name = " + getName()); 179224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly pw.println("isDiscovering() = " + isDiscovering()); 1793105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project 1794105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project BluetoothHeadset headset = new BluetoothHeadset(mContext, null); 1795105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project 1796105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project pw.println("\n--Known devices--"); 1797bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly for (String address : mDeviceProperties.keySet()) { 17981eada0d3d655d6396bf862da954d254856a1bc03Nick Pelly int bondState = mBondState.getBondState(address); 1799105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project pw.printf("%s %10s (%d) %s\n", address, 18001eada0d3d655d6396bf862da954d254856a1bc03Nick Pelly toBondStateString(bondState), 1801105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project mBondState.getAttempt(address), 1802105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project getRemoteName(address)); 180324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly 180424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly Map<ParcelUuid, Integer> uuidChannels = mDeviceServiceChannelCache.get(address); 180524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly if (uuidChannels == null) { 180624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly pw.println("\tuuids = null"); 180724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly } else { 180824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly for (ParcelUuid uuid : uuidChannels.keySet()) { 180924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly Integer channel = uuidChannels.get(uuid); 181024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly if (channel == null) { 181124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly pw.println("\t" + uuid); 181224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly } else { 181324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly pw.println("\t" + uuid + " RFCOMM channel = " + channel); 18141eada0d3d655d6396bf862da954d254856a1bc03Nick Pelly } 18151eada0d3d655d6396bf862da954d254856a1bc03Nick Pelly } 18161eada0d3d655d6396bf862da954d254856a1bc03Nick Pelly } 181716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly for (RemoteService service : mUuidCallbackTracker.keySet()) { 181816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly if (service.address.equals(address)) { 181916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly pw.println("\tPENDING CALLBACK: " + service.uuid); 182016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } 182116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } 1822105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project } 1823105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project 1824d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh String value = getProperty("Devices"); 18251eada0d3d655d6396bf862da954d254856a1bc03Nick Pelly String[] devicesObjectPath = null; 1826d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh if (value != null) { 1827d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh devicesObjectPath = value.split(","); 1828d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh } 1829105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project pw.println("\n--ACL connected devices--"); 183024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly if (devicesObjectPath != null) { 183124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly for (String device : devicesObjectPath) { 183224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly pw.println(getAddressFromObjectPath(device)); 183324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly } 1834105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project } 1835105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project 1836105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project // Rather not do this from here, but no-where else and I need this 1837105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project // dump 1838105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project pw.println("\n--Headset Service--"); 1839105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project switch (headset.getState()) { 1840105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project case BluetoothHeadset.STATE_DISCONNECTED: 1841105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project pw.println("getState() = STATE_DISCONNECTED"); 1842105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project break; 1843105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project case BluetoothHeadset.STATE_CONNECTING: 1844105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project pw.println("getState() = STATE_CONNECTING"); 1845105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project break; 1846105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project case BluetoothHeadset.STATE_CONNECTED: 1847105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project pw.println("getState() = STATE_CONNECTED"); 1848105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project break; 1849105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project case BluetoothHeadset.STATE_ERROR: 1850105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project pw.println("getState() = STATE_ERROR"); 1851105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project break; 1852105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project } 18536c901db72dbaf57d8fdf26adae6721de14ecae22Nick Pelly 185424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly pw.println("\ngetCurrentHeadset() = " + headset.getCurrentHeadset()); 185524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly pw.println("getBatteryUsageHint() = " + headset.getBatteryUsageHint()); 1856105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project headset.close(); 185724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly pw.println("\n--Application Service Records--"); 185824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly for (Integer handle : mServiceRecordToPid.keySet()) { 185924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly Integer pid = mServiceRecordToPid.get(handle); 186024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly pw.println("\tpid " + pid + " handle " + Integer.toHexString(handle)); 186124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly } 18629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 18639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1864d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh /* package */ static int bluezStringToScanMode(boolean pairable, boolean discoverable) { 1865d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh if (pairable && discoverable) 1866bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly return BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE; 1867d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh else if (pairable && !discoverable) 1868bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly return BluetoothAdapter.SCAN_MODE_CONNECTABLE; 1869d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh else 1870bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly return BluetoothAdapter.SCAN_MODE_NONE; 18719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 18729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 18739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* package */ static String scanModeToBluezString(int mode) { 18749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project switch (mode) { 1875bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly case BluetoothAdapter.SCAN_MODE_NONE: 18769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return "off"; 1877bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly case BluetoothAdapter.SCAN_MODE_CONNECTABLE: 18789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return "connectable"; 1879bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly case BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE: 18809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return "discoverable"; 18819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 18829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return null; 18839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 18849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1885d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh /*package*/ String getAddressFromObjectPath(String objectPath) { 1886b148bc844e5eddb07bef2fd1b4b754716decb43eJaikumar Ganesh String adapterObjectPath = getPropertyInternal("ObjectPath"); 1887d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh if (adapterObjectPath == null || objectPath == null) { 1888d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh Log.e(TAG, "getAddressFromObjectPath: AdpaterObjectPath:" + adapterObjectPath + 1889d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh " or deviceObjectPath:" + objectPath + " is null"); 1890d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh return null; 1891d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh } 1892d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh if (!objectPath.startsWith(adapterObjectPath)) { 1893d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh Log.e(TAG, "getAddressFromObjectPath: AdpaterObjectPath:" + adapterObjectPath + 1894d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh " is not a prefix of deviceObjectPath:" + objectPath + 1895d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh "bluetoothd crashed ?"); 1896d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh return null; 1897d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh } 1898d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh String address = objectPath.substring(adapterObjectPath.length()); 1899d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh if (address != null) return address.replace('_', ':'); 1900d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh 1901d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh Log.e(TAG, "getAddressFromObjectPath: Address being returned is null"); 1902d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh return null; 1903d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh } 1904d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh 1905d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh /*package*/ String getObjectPathFromAddress(String address) { 1906b148bc844e5eddb07bef2fd1b4b754716decb43eJaikumar Ganesh String path = getPropertyInternal("ObjectPath"); 1907d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh if (path == null) { 1908d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh Log.e(TAG, "Error: Object Path is null"); 1909d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh return null; 1910d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh } 1911d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh path = path + address.replace(":", "_"); 1912d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh return path; 1913d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh } 1914d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh 1915b7e029d03c115ed65cdea9b2bba307e882c308e2Jaikumar Ganesh /*package */ void setLinkTimeout(String address, int num_slots) { 1916b7e029d03c115ed65cdea9b2bba307e882c308e2Jaikumar Ganesh String path = getObjectPathFromAddress(address); 1917b7e029d03c115ed65cdea9b2bba307e882c308e2Jaikumar Ganesh boolean result = setLinkTimeoutNative(path, num_slots); 1918b7e029d03c115ed65cdea9b2bba307e882c308e2Jaikumar Ganesh 1919b7e029d03c115ed65cdea9b2bba307e882c308e2Jaikumar Ganesh if (!result) log("Set Link Timeout to:" + num_slots + " slots failed"); 1920b7e029d03c115ed65cdea9b2bba307e882c308e2Jaikumar Ganesh } 1921b7e029d03c115ed65cdea9b2bba307e882c308e2Jaikumar Ganesh 19229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static void log(String msg) { 19239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.d(TAG, msg); 19249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1925d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh 1926d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh private native static void classInitNative(); 1927d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh private native void initializeNativeDataNative(); 1928d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh private native boolean setupNativeDataNative(); 1929d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh private native boolean tearDownNativeDataNative(); 1930d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh private native void cleanupNativeDataNative(); 1931d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh private native String getAdapterPathNative(); 1932d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh 1933d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh private native int isEnabledNative(); 1934d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh private native int enableNative(); 1935d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh private native int disableNative(); 1936d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh 1937d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh private native Object[] getAdapterPropertiesNative(); 1938d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh private native Object[] getDevicePropertiesNative(String objectPath); 1939d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh private native boolean setAdapterPropertyStringNative(String key, String value); 1940d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh private native boolean setAdapterPropertyIntegerNative(String key, int value); 1941d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh private native boolean setAdapterPropertyBooleanNative(String key, int value); 1942d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh 1943d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh private native boolean startDiscoveryNative(); 1944d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh private native boolean stopDiscoveryNative(); 1945d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh 1946d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh private native boolean createPairedDeviceNative(String address, int timeout_ms); 1947d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh private native boolean cancelDeviceCreationNative(String address); 1948d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh private native boolean removeDeviceNative(String objectPath); 1949d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh private native int getDeviceServiceChannelNative(String objectPath, String uuid, 1950d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh int attributeId); 1951d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh 1952b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh private native boolean cancelPairingUserInputNative(String address, int nativeData); 1953d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh private native boolean setPinNative(String address, String pin, int nativeData); 1954b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh private native boolean setPasskeyNative(String address, int passkey, int nativeData); 1955b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh private native boolean setPairingConfirmationNative(String address, boolean confirm, 1956b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh int nativeData); 195724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly private native boolean setDevicePropertyBooleanNative(String objectPath, String key, 195824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly int value); 19591caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh private native boolean createDeviceNative(String address); 196016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly /*package*/ native boolean discoverServicesNative(String objectPath, String pattern); 196110eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh 196224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly private native int addRfcommServiceRecordNative(String name, long uuidMsb, long uuidLsb, 196324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly short channel); 196424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly private native boolean removeServiceRecordNative(int handle); 1965b7e029d03c115ed65cdea9b2bba307e882c308e2Jaikumar Ganesh private native boolean setLinkTimeoutNative(String path, int num_slots); 19669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 1967