BluetoothService.java revision 8c9dd7d8b99e1b064fc064a3c6737eaf179eae68
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; 35aef439e6f825c0cb99a2ac08c8207f48b7a9fe10Nick Pellyimport android.os.ParcelUuid; 369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.BroadcastReceiver; 379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.ContentResolver; 389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Context; 399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Intent; 409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.IntentFilter; 419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Binder; 4224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pellyimport android.os.IBinder; 439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Handler; 449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Message; 459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.RemoteException; 46105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Projectimport android.os.ServiceManager; 479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.SystemService; 489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.provider.Settings; 499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.Log; 509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 51d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganeshimport com.android.internal.app.IBatteryStats; 52d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh 539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.FileDescriptor; 549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.PrintWriter; 559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.UnsupportedEncodingException; 569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.ArrayList; 579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.Arrays; 589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.HashMap; 5916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pellyimport java.util.Iterator; 609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.Map; 619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 62bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pellypublic class BluetoothService extends IBluetooth.Stub { 63bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly private static final String TAG = "BluetoothService"; 64db7ae10d6b8e86ff5311512de45afa65a1b0a738Nick Pelly private static final boolean DBG = false; 659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mNativeData; 679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private BluetoothEventLoop mEventLoop; 689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private IntentFilter mIntentFilter; 699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private boolean mIsAirplaneSensitive; 70105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project private int mBluetoothState; 71997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly private boolean mRestart = false; // need to call enable() after disable() 72bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly private boolean mIsDiscovering; 73997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly 74bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly private BluetoothAdapter mAdapter; // constant after init() 75997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly private final BondState mBondState = new BondState(); // local cache of bondings 76105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project private final IBatteryStats mBatteryStats; 779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private final Context mContext; 789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final String BLUETOOTH_ADMIN_PERM = android.Manifest.permission.BLUETOOTH_ADMIN; 809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final String BLUETOOTH_PERM = android.Manifest.permission.BLUETOOTH; 819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 82105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project private static final int MESSAGE_REGISTER_SDP_RECORDS = 1; 83105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project private static final int MESSAGE_FINISH_DISABLE = 2; 841caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh private static final int MESSAGE_UUID_INTENT = 3; 8512835478ee687a493d1b5882e67b6725bd539c26Nick Pelly private static final int MESSAGE_DISCOVERABLE_TIMEOUT = 4; 861caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh 871caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh // The timeout used to sent the UUIDs Intent 881caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh // This timeout should be greater than the page timeout 891caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh private static final int UUID_INTENT_DELAY = 6000; 90105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project 9116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly /** Always retrieve RFCOMM channel for these SDP UUIDs */ 9216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly private static final ParcelUuid[] RFCOMM_UUIDS = { 9316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly BluetoothUuid.Handsfree, 9416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly BluetoothUuid.HSP, 9516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly BluetoothUuid.ObexObjectPush }; 9616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly 9716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly 98bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly private final Map<String, String> mAdapterProperties; 9916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly private final HashMap<String, Map<String, String>> mDeviceProperties; 100d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh 10116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly private final HashMap<String, Map<ParcelUuid, Integer>> mDeviceServiceChannelCache; 10216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly private final ArrayList<String> mUuidIntentTracker; 10316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly private final HashMap<RemoteService, IBluetoothCallback> mUuidCallbackTracker; 1041caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh 10524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly private final HashMap<Integer, Integer> mServiceRecordToPid; 10624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly 10716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly private static class RemoteService { 10816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly public String address; 10916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly public ParcelUuid uuid; 11016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly public RemoteService(String address, ParcelUuid uuid) { 11116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly this.address = address; 11216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly this.uuid = uuid; 11316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } 11416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly @Override 11516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly public boolean equals(Object o) { 11616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly if (o instanceof RemoteService) { 11716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly RemoteService service = (RemoteService)o; 11816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly return address.equals(service.address) && uuid.equals(service.uuid); 11916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } 12016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly return false; 12116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } 12216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } 12316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly 1249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project static { 1259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project classInitNative(); 1269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 128bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly public BluetoothService(Context context) { 1299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mContext = context; 130105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project 131105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project // Need to do this in place of: 132105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project // mBatteryStats = BatteryStatsService.getService(); 133105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project // Since we can not import BatteryStatsService from here. This class really needs to be 134105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project // moved to java/services/com/android/server/ 135105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService("batteryinfo")); 1369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project initializeNativeDataNative(); 138ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project 139ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project if (isEnabledNative() == 1) { 140ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project Log.w(TAG, "Bluetooth daemons already running - runtime restart? "); 141ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project disableNative(); 1429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 143ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project 144de893f550301a60274e87aa8168225e7a7a42184Nick Pelly mBluetoothState = BluetoothAdapter.STATE_OFF; 1459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mIsDiscovering = false; 146bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly mAdapterProperties = new HashMap<String, String>(); 147bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly mDeviceProperties = new HashMap<String, Map<String,String>>(); 14810eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh 14910eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh mDeviceServiceChannelCache = new HashMap<String, Map<ParcelUuid, Integer>>(); 1501caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh mUuidIntentTracker = new ArrayList<String>(); 15116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly mUuidCallbackTracker = new HashMap<RemoteService, IBluetoothCallback>(); 15224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly mServiceRecordToPid = new HashMap<Integer, Integer>(); 1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project registerForAirplaneMode(); 154bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly } 155bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly 156bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly public synchronized void initAfterRegistration() { 157f242b7b931898856bcbcb7ec36cacf43098ba544Nick Pelly mAdapter = BluetoothAdapter.getDefaultAdapter(); 158bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly mEventLoop = new BluetoothEventLoop(mContext, mAdapter, this); 1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project protected void finalize() throws Throwable { 1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mIsAirplaneSensitive) { 1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mContext.unregisterReceiver(mReceiver); 1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project cleanupNativeDataNative(); 1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } finally { 1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project super.finalize(); 1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean isEnabled() { 1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1758c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh return isEnabledInternal(); 1768c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh } 1778c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh 1788c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh private boolean isEnabledInternal() { 179de893f550301a60274e87aa8168225e7a7a42184Nick Pelly return mBluetoothState == BluetoothAdapter.STATE_ON; 1809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 182105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project public int getBluetoothState() { 183105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 184105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project return mBluetoothState; 185105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project } 186105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project 187105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project 1889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Bring down bluetooth and disable BT in settings. Returns true on success. 1909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean disable() { 1929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return disable(true); 1939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Bring down bluetooth. Returns true on success. 1979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 198e6ee3be1c254404dad842298f6f56c11cc6c7ac8Nick Pelly * @param saveSetting If true, persist the new setting 1999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 2009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public synchronized boolean disable(boolean saveSetting) { 201e6ee3be1c254404dad842298f6f56c11cc6c7ac8Nick Pelly mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH_ADMIN permission"); 2029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 203105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project switch (mBluetoothState) { 204de893f550301a60274e87aa8168225e7a7a42184Nick Pelly case BluetoothAdapter.STATE_OFF: 205105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project return true; 206de893f550301a60274e87aa8168225e7a7a42184Nick Pelly case BluetoothAdapter.STATE_ON: 207105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project break; 208105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project default: 209105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project return false; 210105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project } 2119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mEnableThread != null && mEnableThread.isAlive()) { 2129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 2139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 214de893f550301a60274e87aa8168225e7a7a42184Nick Pelly setBluetoothState(BluetoothAdapter.STATE_TURNING_OFF); 215bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly mHandler.removeMessages(MESSAGE_REGISTER_SDP_RECORDS); 216105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project 217105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project // Allow 3 seconds for profiles to gracefully disconnect 218105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project // TODO: Introduce a callback mechanism so that each profile can notify 219bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly // BluetoothService when it is done shutting down 220105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project mHandler.sendMessageDelayed( 221105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project mHandler.obtainMessage(MESSAGE_FINISH_DISABLE, saveSetting ? 1 : 0, 0), 3000); 222105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project return true; 223105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project } 224105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project 225105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project 226105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project private synchronized void finishDisable(boolean saveSetting) { 227de893f550301a60274e87aa8168225e7a7a42184Nick Pelly if (mBluetoothState != BluetoothAdapter.STATE_TURNING_OFF) { 228105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project return; 2299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mEventLoop.stop(); 231d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh tearDownNativeDataNative(); 2329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project disableNative(); 2339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // mark in progress bondings as cancelled 2359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (String address : mBondState.listInState(BluetoothDevice.BOND_BONDING)) { 236005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly mBondState.setBondState(address, BluetoothDevice.BOND_NONE, 2379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project BluetoothDevice.UNBOND_REASON_AUTH_CANCELED); 2389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // update mode 241de893f550301a60274e87aa8168225e7a7a42184Nick Pelly Intent intent = new Intent(BluetoothAdapter.ACTION_SCAN_MODE_CHANGED); 242de893f550301a60274e87aa8168225e7a7a42184Nick Pelly intent.putExtra(BluetoothAdapter.EXTRA_SCAN_MODE, BluetoothAdapter.SCAN_MODE_NONE); 2439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mContext.sendBroadcast(intent, BLUETOOTH_PERM); 2449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 245105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project mIsDiscovering = false; 246bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly mAdapterProperties.clear(); 24724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly mServiceRecordToPid.clear(); 248105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project 2499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (saveSetting) { 2509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project persistBluetoothOnSetting(false); 2519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 252105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project 253de893f550301a60274e87aa8168225e7a7a42184Nick Pelly setBluetoothState(BluetoothAdapter.STATE_OFF); 254105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project 255105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project // Log bluetooth off to battery stats. 256105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project long ident = Binder.clearCallingIdentity(); 257105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project try { 258105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project mBatteryStats.noteBluetoothOff(); 259105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project } catch (RemoteException e) { 260105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project } finally { 261105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project Binder.restoreCallingIdentity(ident); 262105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project } 263997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly 264997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly if (mRestart) { 265997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly mRestart = false; 266997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly enable(); 267997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly } 2689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 270105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project /** Bring up BT and persist BT on in settings */ 271105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project public boolean enable() { 272105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project return enable(true); 2739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 2769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Enable this Bluetooth device, asynchronously. 2779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * This turns on/off the underlying hardware. 2789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 279105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project * @param saveSetting If true, persist the new state of BT in settings 280105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project * @return True on success (so far) 2819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 282105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project public synchronized boolean enable(boolean saveSetting) { 2839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 2849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Need BLUETOOTH_ADMIN permission"); 2859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Airplane mode can prevent Bluetooth radio from being turned on. 2879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mIsAirplaneSensitive && isAirplaneModeOn()) { 2889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 2899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 290de893f550301a60274e87aa8168225e7a7a42184Nick Pelly if (mBluetoothState != BluetoothAdapter.STATE_OFF) { 2919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 2929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mEnableThread != null && mEnableThread.isAlive()) { 2949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 2959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 296de893f550301a60274e87aa8168225e7a7a42184Nick Pelly setBluetoothState(BluetoothAdapter.STATE_TURNING_ON); 297105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project mEnableThread = new EnableThread(saveSetting); 2989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mEnableThread.start(); 2999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 3009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 302997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly /** Forcibly restart Bluetooth if it is on */ 303997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly /* package */ synchronized void restart() { 304de893f550301a60274e87aa8168225e7a7a42184Nick Pelly if (mBluetoothState != BluetoothAdapter.STATE_ON) { 305997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly return; 306997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly } 307997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly mRestart = true; 308997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly if (!disable(false)) { 309997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly mRestart = false; 310997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly } 311d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh } 312997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly 313105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project private synchronized void setBluetoothState(int state) { 314105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project if (state == mBluetoothState) { 315105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project return; 316105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project } 317105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project 318105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project if (DBG) log("Bluetooth state " + mBluetoothState + " -> " + state); 319105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project 320de893f550301a60274e87aa8168225e7a7a42184Nick Pelly Intent intent = new Intent(BluetoothAdapter.ACTION_STATE_CHANGED); 321de893f550301a60274e87aa8168225e7a7a42184Nick Pelly intent.putExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, mBluetoothState); 322de893f550301a60274e87aa8168225e7a7a42184Nick Pelly intent.putExtra(BluetoothAdapter.EXTRA_STATE, state); 323105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 324105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project 325105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project mBluetoothState = state; 326105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project 327105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project mContext.sendBroadcast(intent, BLUETOOTH_PERM); 328105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project } 329105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project 3309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private final Handler mHandler = new Handler() { 3319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 3329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void handleMessage(Message msg) { 3339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project switch (msg.what) { 334105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project case MESSAGE_REGISTER_SDP_RECORDS: 3358c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh if (!isEnabledInternal()) { 336bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly return; 337bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly } 338bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly // SystemService.start() forks sdptool to register service 339bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly // records. It can fail to register some records if it is 340bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly // forked multiple times in a row, probably because there is 341bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly // some race in sdptool or bluez when operated in parallel. 342bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly // As a workaround, delay 500ms between each fork of sdptool. 343bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly // TODO: Don't fork sdptool in order to regsiter service 344bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly // records, use a DBUS call instead. 345bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly switch (msg.arg1) { 346bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly case 1: 347bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly Log.d(TAG, "Registering hsag record"); 3489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SystemService.start("hsag"); 349bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly mHandler.sendMessageDelayed( 350bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly mHandler.obtainMessage(MESSAGE_REGISTER_SDP_RECORDS, 2, -1), 500); 351bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly break; 352bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly case 2: 353bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly Log.d(TAG, "Registering hfag record"); 3549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SystemService.start("hfag"); 355bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly mHandler.sendMessageDelayed( 356bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly mHandler.obtainMessage(MESSAGE_REGISTER_SDP_RECORDS, 3, -1), 500); 357bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly break; 358bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly case 3: 359bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly Log.d(TAG, "Registering opush record"); 36003c707ab6fc97e99b1603b8d6edc604dbea3cd6fNick Pelly SystemService.start("opush"); 361bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly mHandler.sendMessageDelayed( 362bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly mHandler.obtainMessage(MESSAGE_REGISTER_SDP_RECORDS, 4, -1), 500); 363bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly break; 364bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly case 4: 365bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly Log.d(TAG, "Registering pbap record"); 36667542964876aa7e4216e8f69f21dda68e7463b9aJaikumar Ganesh SystemService.start("pbap"); 367bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly break; 3689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 369105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project break; 370105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project case MESSAGE_FINISH_DISABLE: 371105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project finishDisable(msg.arg1 != 0); 372105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project break; 3731caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh case MESSAGE_UUID_INTENT: 3741caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh String address = (String)msg.obj; 37516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly if (address != null) { 3761caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh sendUuidIntent(address); 37716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly makeServiceChannelCallbacks(address); 37816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } 3791caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh break; 38012835478ee687a493d1b5882e67b6725bd539c26Nick Pelly case MESSAGE_DISCOVERABLE_TIMEOUT: 38112835478ee687a493d1b5882e67b6725bd539c26Nick Pelly int mode = msg.arg1; 3828c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh if (isEnabledInternal()) { 38312835478ee687a493d1b5882e67b6725bd539c26Nick Pelly // TODO: Switch back to the previous scan mode 38412835478ee687a493d1b5882e67b6725bd539c26Nick Pelly // This is ok for now, because we only use 38512835478ee687a493d1b5882e67b6725bd539c26Nick Pelly // CONNECTABLE and CONNECTABLE_DISCOVERABLE 38612835478ee687a493d1b5882e67b6725bd539c26Nick Pelly setScanMode(BluetoothAdapter.SCAN_MODE_CONNECTABLE, -1); 38712835478ee687a493d1b5882e67b6725bd539c26Nick Pelly } 38812835478ee687a493d1b5882e67b6725bd539c26Nick Pelly break; 3899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project }; 3929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private EnableThread mEnableThread; 3949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private class EnableThread extends Thread { 3969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private final boolean mSaveSetting; 397105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project public EnableThread(boolean saveSetting) { 3989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mSaveSetting = saveSetting; 3999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void run() { 4019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean res = (enableNative() == 0); 4029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (res) { 403b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project int retryCount = 2; 404b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project boolean running = false; 405b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project while ((retryCount-- > 0) && !running) { 406b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project mEventLoop.start(); 407105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project // it may take a momement for the other thread to do its 408b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project // thing. Check periodically for a while. 409b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project int pollCount = 5; 410b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project while ((pollCount-- > 0) && !running) { 411b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project if (mEventLoop.isEventLoopRunning()) { 412b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project running = true; 413b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project break; 414b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project } 415b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project try { 416b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project Thread.sleep(100); 417b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project } catch (InterruptedException e) {} 418b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project } 419b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project } 420b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project if (!running) { 421b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project log("bt EnableThread giving up"); 422b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project res = false; 423b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project disableNative(); 424b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project } 4259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (res) { 429d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh if (!setupNativeDataNative()) { 430d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh return; 431d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh } 4329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mSaveSetting) { 4339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project persistBluetoothOnSetting(true); 4349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mIsDiscovering = false; 4369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mBondState.loadBondState(); 437bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly mHandler.sendMessageDelayed( 438bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly mHandler.obtainMessage(MESSAGE_REGISTER_SDP_RECORDS, 1, -1), 3000); 4399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 440105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project // Log bluetooth on to battery stats. 441105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project long ident = Binder.clearCallingIdentity(); 442105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project try { 443105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project mBatteryStats.noteBluetoothOn(); 444105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project } catch (RemoteException e) { 445105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project } finally { 446105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project Binder.restoreCallingIdentity(ident); 447105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project } 4489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 449105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project 450105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project mEnableThread = null; 451105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project 452105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project setBluetoothState(res ? 453de893f550301a60274e87aa8168225e7a7a42184Nick Pelly BluetoothAdapter.STATE_ON : 454de893f550301a60274e87aa8168225e7a7a42184Nick Pelly BluetoothAdapter.STATE_OFF); 455105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project 456b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project if (res) { 457105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project // Update mode 458d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh String[] propVal = {"Pairable", getProperty("Pairable")}; 459d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh mEventLoop.onPropertyChanged(propVal); 460b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project } 461b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project 4625c43f735d94a538dc273c8f859d1100a7cdd5c71Daisuke Miyakawa if (mIsAirplaneSensitive && isAirplaneModeOn()) { 4635c43f735d94a538dc273c8f859d1100a7cdd5c71Daisuke Miyakawa disable(false); 4645c43f735d94a538dc273c8f859d1100a7cdd5c71Daisuke Miyakawa } 4655c43f735d94a538dc273c8f859d1100a7cdd5c71Daisuke Miyakawa 4669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void persistBluetoothOnSetting(boolean bluetoothOn) { 4709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project long origCallerIdentityToken = Binder.clearCallingIdentity(); 4719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Settings.Secure.putInt(mContext.getContentResolver(), Settings.Secure.BLUETOOTH_ON, 4729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project bluetoothOn ? 1 : 0); 4739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Binder.restoreCallingIdentity(origCallerIdentityToken); 4749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* package */ BondState getBondState() { 4779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mBondState; 4789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** local cache of bonding state. 4819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* we keep our own state to track the intermediate state BONDING, which 4829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* bluez does not track. 4839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * All addreses must be passed in upper case. 4849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 4859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public class BondState { 4869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private final HashMap<String, Integer> mState = new HashMap<String, Integer>(); 4879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private final HashMap<String, Integer> mPinAttempt = new HashMap<String, Integer>(); 4889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private final ArrayList<String> mAutoPairingFailures = new ArrayList<String>(); 489105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project // List of all the vendor_id prefix of Bluetooth addresses for 490105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project // which auto pairing is not attempted. 491105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project // The following companies are included in the list below: 492105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project // ALPS (lexus), Murata (Prius 2007, Nokia 616), TEMIC SDS (Porsche, Audi), 493105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project // Parrot, Zhongshan General K-mate Electronics, Great Well 494105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project // Electronics, Flaircomm Electronics, Jatty Electronics, Delphi, 495105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project // Clarion, Novero, Denso (Lexus, Toyota), Johnson Controls (Acura), 49621d0dca33e0c16c7de5c42bbcdf5a98ec67ead5dJaikumar Ganesh // Continental Automotive, Harman/Becker, Panasonic/Kyushu Ten, 49721d0dca33e0c16c7de5c42bbcdf5a98ec67ead5dJaikumar Ganesh // BMW (Motorola PCS) 498482d54bb0cd9e00fd929185c31fea3ad845d97bcJaikumar Ganesh private final ArrayList<String> mAutoPairingAddressBlacklist = 4999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project new ArrayList<String>(Arrays.asList( 500105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project "00:02:C7", "00:16:FE", "00:19:C1", "00:1B:FB", "00:1E:3D", "00:21:4F", 501105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project "00:23:06", "00:24:33", "00:A0:79", "00:0E:6D", "00:13:E0", "00:21:E8", 502105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project "00:60:57", "00:0E:9F", "00:12:1C", "00:18:91", "00:18:96", "00:13:04", 503105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project "00:16:FD", "00:22:A0", "00:0B:4C", "00:60:6F", "00:23:3D", "00:C0:59", 50421d0dca33e0c16c7de5c42bbcdf5a98ec67ead5dJaikumar Ganesh "00:0A:30", "00:1E:AE", "00:1C:D7", "00:80:F0", "00:12:8A" 5059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project )); 5069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 507482d54bb0cd9e00fd929185c31fea3ad845d97bcJaikumar Ganesh // List of names of Bluetooth devices for which auto pairing should be 508482d54bb0cd9e00fd929185c31fea3ad845d97bcJaikumar Ganesh // disabled. 509738ed80262aa26128924c51f59ffd49e1163eb8dJaikumar Ganesh private final ArrayList<String> mAutoPairingExactNameBlacklist = 510482d54bb0cd9e00fd929185c31fea3ad845d97bcJaikumar Ganesh new ArrayList<String>(Arrays.asList( 511738ed80262aa26128924c51f59ffd49e1163eb8dJaikumar Ganesh "Motorola IHF1000", "i.TechBlueBAND", "X5 Stereo v1.3")); 512738ed80262aa26128924c51f59ffd49e1163eb8dJaikumar Ganesh 513738ed80262aa26128924c51f59ffd49e1163eb8dJaikumar Ganesh private final ArrayList<String> mAutoPairingPartialNameBlacklist = 514738ed80262aa26128924c51f59ffd49e1163eb8dJaikumar Ganesh new ArrayList<String>(Arrays.asList( 515738ed80262aa26128924c51f59ffd49e1163eb8dJaikumar Ganesh "BMW", "Audi")); 516482d54bb0cd9e00fd929185c31fea3ad845d97bcJaikumar Ganesh 5172092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh // If this is an outgoing connection, store the address. 5182092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh // There can be only 1 pending outgoing connection at a time, 5192092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh private String mPendingOutgoingBonding; 5202092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh 5212092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh private synchronized void setPendingOutgoingBonding(String address) { 5222092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh mPendingOutgoingBonding = address; 5232092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh } 5242092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh 5252092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh public synchronized String getPendingOutgoingBonding() { 5262092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh return mPendingOutgoingBonding; 5272092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh } 5282092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh 5299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public synchronized void loadBondState() { 530de893f550301a60274e87aa8168225e7a7a42184Nick Pelly if (mBluetoothState != BluetoothAdapter.STATE_TURNING_ON) { 5319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 5329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 533d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh String []bonds = null; 534d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh String val = getProperty("Devices"); 535d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh if (val != null) { 536d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh bonds = val.split(","); 537d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh } 5389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (bonds == null) { 5399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 5409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mState.clear(); 5429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (DBG) log("found " + bonds.length + " bonded devices"); 543d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh for (String device : bonds) { 544d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh mState.put(getAddressFromObjectPath(device).toUpperCase(), 545d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh BluetoothDevice.BOND_BONDED); 5469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public synchronized void setBondState(String address, int state) { 5509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project setBondState(address, state, 0); 5519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** reason is ignored unless state == BOND_NOT_BONDED */ 5549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public synchronized void setBondState(String address, int state, int reason) { 5559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int oldState = getBondState(address); 5569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (oldState == state) { 5579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 5589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5592092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh 5602092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh // Check if this was an pending outgoing bonding. 5612092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh // If yes, reset the state. 5622092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh if (oldState == BluetoothDevice.BOND_BONDING) { 5632092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh if (address.equals(mPendingOutgoingBonding)) { 5642092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh mPendingOutgoingBonding = null; 5652092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh } 5662092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh } 5672092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh 5689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (DBG) log(address + " bond state " + oldState + " -> " + state + " (" + 5699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project reason + ")"); 570005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly Intent intent = new Intent(BluetoothDevice.ACTION_BOND_STATE_CHANGED); 571005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mAdapter.getRemoteDevice(address)); 572005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly intent.putExtra(BluetoothDevice.EXTRA_BOND_STATE, state); 573005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly intent.putExtra(BluetoothDevice.EXTRA_PREVIOUS_BOND_STATE, oldState); 574005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly if (state == BluetoothDevice.BOND_NONE) { 5759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (reason <= 0) { 5769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.w(TAG, "setBondState() called to unbond device, but reason code is " + 5779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "invalid. Overriding reason code with BOND_RESULT_REMOVED"); 5789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project reason = BluetoothDevice.UNBOND_REASON_REMOVED; 5799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 580005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly intent.putExtra(BluetoothDevice.EXTRA_REASON, reason); 5819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mState.remove(address); 5829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 5839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mState.put(address, state); 5849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mContext.sendBroadcast(intent, BLUETOOTH_PERM); 5879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean isAutoPairingBlacklisted(String address) { 590482d54bb0cd9e00fd929185c31fea3ad845d97bcJaikumar Ganesh for (String blacklistAddress : mAutoPairingAddressBlacklist) { 5919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (address.startsWith(blacklistAddress)) return true; 5929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 593482d54bb0cd9e00fd929185c31fea3ad845d97bcJaikumar Ganesh 594482d54bb0cd9e00fd929185c31fea3ad845d97bcJaikumar Ganesh String name = getRemoteName(address); 595482d54bb0cd9e00fd929185c31fea3ad845d97bcJaikumar Ganesh if (name != null) { 596738ed80262aa26128924c51f59ffd49e1163eb8dJaikumar Ganesh for (String blacklistName : mAutoPairingExactNameBlacklist) { 597738ed80262aa26128924c51f59ffd49e1163eb8dJaikumar Ganesh if (name.equals(blacklistName)) return true; 598738ed80262aa26128924c51f59ffd49e1163eb8dJaikumar Ganesh } 599738ed80262aa26128924c51f59ffd49e1163eb8dJaikumar Ganesh 600738ed80262aa26128924c51f59ffd49e1163eb8dJaikumar Ganesh for (String blacklistName : mAutoPairingPartialNameBlacklist) { 601738ed80262aa26128924c51f59ffd49e1163eb8dJaikumar Ganesh if (name.startsWith(blacklistName)) return true; 602482d54bb0cd9e00fd929185c31fea3ad845d97bcJaikumar Ganesh } 603482d54bb0cd9e00fd929185c31fea3ad845d97bcJaikumar Ganesh } 6049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 6059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public synchronized int getBondState(String address) { 6089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Integer state = mState.get(address); 6099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (state == null) { 610005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly return BluetoothDevice.BOND_NONE; 6119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return state.intValue(); 6139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 615e5d93b7ed983f98855555d560faf060836f1a52fJaikumar Ganesh /*package*/ synchronized String[] listInState(int state) { 6169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ArrayList<String> result = new ArrayList<String>(mState.size()); 6179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (Map.Entry<String, Integer> e : mState.entrySet()) { 6189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (e.getValue().intValue() == state) { 6199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project result.add(e.getKey()); 6209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return result.toArray(new String[result.size()]); 6239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public synchronized void addAutoPairingFailure(String address) { 6269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!mAutoPairingFailures.contains(address)) { 6279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mAutoPairingFailures.add(address); 6289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public synchronized boolean isAutoPairingAttemptsInProgress(String address) { 6329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return getAttempt(address) != 0; 6339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public synchronized void clearPinAttempts(String address) { 6369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPinAttempt.remove(address); 6379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public synchronized boolean hasAutoPairingFailed(String address) { 6409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mAutoPairingFailures.contains(address); 6419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public synchronized int getAttempt(String address) { 6449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Integer attempt = mPinAttempt.get(address); 6459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (attempt == null) { 6469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return 0; 6479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return attempt.intValue(); 6499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public synchronized void attempt(String address) { 6529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Integer attempt = mPinAttempt.get(address); 6539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int newAttempt; 6549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (attempt == null) { 6559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project newAttempt = 1; 6569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 6579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project newAttempt = attempt.intValue() + 1; 6589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPinAttempt.put(address, new Integer(newAttempt)); 6609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static String toBondStateString(int bondState) { 6659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project switch (bondState) { 666005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly case BluetoothDevice.BOND_NONE: 6679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return "not bonded"; 6689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case BluetoothDevice.BOND_BONDING: 6699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return "bonding"; 6709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case BluetoothDevice.BOND_BONDED: 6719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return "bonded"; 6729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project default: 6739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return "??????"; 6749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6779519ce75f15ba287a641166c1b7ed10f2aa73f74Jaikumar Ganesh /*package*/ synchronized boolean isAdapterPropertiesEmpty() { 6789519ce75f15ba287a641166c1b7ed10f2aa73f74Jaikumar Ganesh return mAdapterProperties.isEmpty(); 6799519ce75f15ba287a641166c1b7ed10f2aa73f74Jaikumar Ganesh } 6809519ce75f15ba287a641166c1b7ed10f2aa73f74Jaikumar Ganesh 681d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh /*package*/synchronized void getAllProperties() { 6828c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh 6839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 6848c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh if (!isEnabledInternal()) return; 685bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly mAdapterProperties.clear(); 686d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh 687d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh String properties[] = (String [])getAdapterPropertiesNative(); 688d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh // The String Array consists of key-value pairs. 689d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh if (properties == null) { 690d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh Log.e(TAG, "*Error*: GetAdapterProperties returned NULL"); 691d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh return; 692d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh } 693d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh 6948bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh for (int i = 0; i < properties.length; i++) { 6958bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh String name = properties[i]; 696efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh String newValue = null; 6978bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh int len; 6988bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh if (name == null) { 6998bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh Log.e(TAG, "Error:Adapter Property at index" + i + "is null"); 7008bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh continue; 7018bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh } 7028bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh if (name.equals("Devices")) { 703efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh StringBuilder str = new StringBuilder(); 7048bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh len = Integer.valueOf(properties[++i]); 7058bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh for (int j = 0; j < len; j++) { 706efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh str.append(properties[++i]); 707efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh str.append(","); 708efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh } 709efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh if (len > 0) { 710efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh newValue = str.toString(); 7118bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh } 7128bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh } else { 7138bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh newValue = properties[++i]; 7148bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh } 715bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly mAdapterProperties.put(name, newValue); 716d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh } 717d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh 718d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh // Add adapter object path property. 719d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh String adapterPath = getAdapterPathNative(); 720d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh if (adapterPath != null) 721bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly mAdapterProperties.put("ObjectPath", adapterPath + "/dev_"); 7229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 724d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh /* package */ synchronized void setProperty(String name, String value) { 725bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly mAdapterProperties.put(name, value); 7269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public synchronized boolean setName(String name) { 7299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 7309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Need BLUETOOTH_ADMIN permission"); 7319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (name == null) { 7329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 7339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 734d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh return setPropertyString("Name", name); 7359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 737d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh //TODO(): setPropertyString, setPropertyInteger, setPropertyBoolean 738d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh // Either have a single property function with Object as the parameter 739d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh // or have a function for each property and then obfuscate in the JNI layer. 740d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh // The following looks dirty. 741d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh private boolean setPropertyString(String key, String value) { 7429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 7438c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh if (!isEnabledInternal()) return false; 744d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh return setAdapterPropertyStringNative(key, value); 7459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 747d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh private boolean setPropertyInteger(String key, int value) { 748d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 7498c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh if (!isEnabledInternal()) return false; 750d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh return setAdapterPropertyIntegerNative(key, value); 751d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh } 7529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 753d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh private boolean setPropertyBoolean(String key, boolean value) { 754d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 7558c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh if (!isEnabledInternal()) return false; 756d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh return setAdapterPropertyBooleanNative(key, value ? 1 : 0); 7579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 759d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh /** 760d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh * Set the discoverability window for the device. A timeout of zero 761d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh * makes the device permanently discoverable (if the device is 762d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh * discoverable). Setting the timeout to a nonzero value does not make 763d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh * a device discoverable; you need to call setMode() to make the device 764d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh * explicitly discoverable. 765d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh * 766d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh * @param timeout_s The discoverable timeout in seconds. 767d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh */ 768d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh public synchronized boolean setDiscoverableTimeout(int timeout) { 7699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 7709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Need BLUETOOTH_ADMIN permission"); 771d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh return setPropertyInteger("DiscoverableTimeout", timeout); 7729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 77412835478ee687a493d1b5882e67b6725bd539c26Nick Pelly public synchronized boolean setScanMode(int mode, int duration) { 77518b1e79a123b979d25bfa5d0b0ee5d0382dbd64bNick Pelly mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS, 77618b1e79a123b979d25bfa5d0b0ee5d0382dbd64bNick Pelly "Need WRITE_SECURE_SETTINGS permission"); 777de893f550301a60274e87aa8168225e7a7a42184Nick Pelly boolean pairable = false; 778de893f550301a60274e87aa8168225e7a7a42184Nick Pelly boolean discoverable = false; 77912835478ee687a493d1b5882e67b6725bd539c26Nick Pelly 780de893f550301a60274e87aa8168225e7a7a42184Nick Pelly switch (mode) { 781de893f550301a60274e87aa8168225e7a7a42184Nick Pelly case BluetoothAdapter.SCAN_MODE_NONE: 78212835478ee687a493d1b5882e67b6725bd539c26Nick Pelly mHandler.removeMessages(MESSAGE_DISCOVERABLE_TIMEOUT); 783d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh pairable = false; 784d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh discoverable = false; 785de893f550301a60274e87aa8168225e7a7a42184Nick Pelly break; 786de893f550301a60274e87aa8168225e7a7a42184Nick Pelly case BluetoothAdapter.SCAN_MODE_CONNECTABLE: 78712835478ee687a493d1b5882e67b6725bd539c26Nick Pelly mHandler.removeMessages(MESSAGE_DISCOVERABLE_TIMEOUT); 788d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh pairable = true; 789d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh discoverable = false; 790005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly break; 791de893f550301a60274e87aa8168225e7a7a42184Nick Pelly case BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE: 79212835478ee687a493d1b5882e67b6725bd539c26Nick Pelly mHandler.removeMessages(MESSAGE_DISCOVERABLE_TIMEOUT); 793d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh pairable = true; 794d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh discoverable = true; 79512835478ee687a493d1b5882e67b6725bd539c26Nick Pelly Message msg = mHandler.obtainMessage(MESSAGE_DISCOVERABLE_TIMEOUT); 79612835478ee687a493d1b5882e67b6725bd539c26Nick Pelly mHandler.sendMessageDelayed(msg, duration * 1000); 79712835478ee687a493d1b5882e67b6725bd539c26Nick Pelly if (DBG) Log.d(TAG, "BT Discoverable for " + duration + " seconds"); 798005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly break; 799de893f550301a60274e87aa8168225e7a7a42184Nick Pelly default: 800de893f550301a60274e87aa8168225e7a7a42184Nick Pelly Log.w(TAG, "Requested invalid scan mode " + mode); 801de893f550301a60274e87aa8168225e7a7a42184Nick Pelly return false; 802d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh } 803d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh setPropertyBoolean("Pairable", pairable); 804d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh setPropertyBoolean("Discoverable", discoverable); 8059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 806d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh return true; 8079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 809d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh /*package*/ synchronized String getProperty (String name) { 810bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly if (!mAdapterProperties.isEmpty()) 811bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly return mAdapterProperties.get(name); 812d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh getAllProperties(); 813bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly return mAdapterProperties.get(name); 8149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 816d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh public synchronized String getAddress() { 817d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 818d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh return getProperty("Address"); 8199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 821d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh public synchronized String getName() { 8229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 823d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh return getProperty("Name"); 8249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 827d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh * Returns the user-friendly name of a remote device. This value is 828d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh * returned from our local cache, which is updated when onPropertyChange 829d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh * event is received. 830d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh * Do not expect to retrieve the updated remote name immediately after 831d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh * changing the name on the remote device. 8329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 833d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh * @param address Bluetooth address of remote device. 834d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh * 835d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh * @return The user-friendly name of the specified remote device. 8369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 837d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh public synchronized String getRemoteName(String address) { 838d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 839005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly if (!BluetoothAdapter.checkBluetoothAddress(address)) { 840d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh return null; 841d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh } 84255929a958bf0e482c8e4d7df3dd75957f1e9d871Jaikumar Ganesh return getRemoteDeviceProperty(address, "Name"); 8439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 8469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Get the discoverability window for the device. A timeout of zero 8479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * means that the device is permanently discoverable (if the device is 8489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * in the discoverable mode). 8499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 8509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return The discoverability window of the device, in seconds. A negative 8519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * value indicates an error. 8529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 8539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public synchronized int getDiscoverableTimeout() { 8549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 855d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh String timeout = getProperty("DiscoverableTimeout"); 856d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh if (timeout != null) 857d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh return Integer.valueOf(timeout); 858d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh else 859d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh return -1; 8609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public synchronized int getScanMode() { 8639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 8648c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh if (!isEnabledInternal()) 865de893f550301a60274e87aa8168225e7a7a42184Nick Pelly return BluetoothAdapter.SCAN_MODE_NONE; 866d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh 867d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh boolean pairable = getProperty("Pairable").equals("true"); 868d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh boolean discoverable = getProperty("Discoverable").equals("true"); 869d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh return bluezStringToScanMode (pairable, discoverable); 8709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 872d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh public synchronized boolean startDiscovery() { 8739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 8749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Need BLUETOOTH_ADMIN permission"); 8758c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh if (!isEnabledInternal()) return false; 8768c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh 877d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh return startDiscoveryNative(); 8789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 880d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh public synchronized boolean cancelDiscovery() { 8819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 8829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Need BLUETOOTH_ADMIN permission"); 8838c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh if (!isEnabledInternal()) return false; 8848c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh 885d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh return stopDiscoveryNative(); 886d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh } 887d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh 888d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh public synchronized boolean isDiscovering() { 889d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 890d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh return mIsDiscovering; 891d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh } 892d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh 893d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh /* package */ void setIsDiscovering(boolean isDiscovering) { 894d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh mIsDiscovering = isDiscovering; 8959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public synchronized boolean createBond(String address) { 8989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 8999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Need BLUETOOTH_ADMIN permission"); 9008c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh if (!isEnabledInternal()) return false; 9018c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh 902005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly if (!BluetoothAdapter.checkBluetoothAddress(address)) { 9039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 9049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project address = address.toUpperCase(); 9069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9072092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh if (mBondState.getPendingOutgoingBonding() != null) { 9089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project log("Ignoring createBond(): another device is bonding"); 9099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // a different device is currently bonding, fail 9109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 9119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Check for bond state only if we are not performing auto 9149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // pairing exponential back-off attempts. 9159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!mBondState.isAutoPairingAttemptsInProgress(address) && 916005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly mBondState.getBondState(address) != BluetoothDevice.BOND_NONE) { 9179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project log("Ignoring createBond(): this device is already bonding or bonded"); 9189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 9199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 921d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh if (!createPairedDeviceNative(address, 60000 /* 1 minute */)) { 9229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 9239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9252092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh mBondState.setPendingOutgoingBonding(address); 9269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mBondState.setBondState(address, BluetoothDevice.BOND_BONDING); 9272092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh 9289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 9299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public synchronized boolean cancelBondProcess(String address) { 9329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 9339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Need BLUETOOTH_ADMIN permission"); 9348c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh if (!isEnabledInternal()) return false; 9358c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh 936005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly if (!BluetoothAdapter.checkBluetoothAddress(address)) { 9379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 9389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project address = address.toUpperCase(); 9409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mBondState.getBondState(address) != BluetoothDevice.BOND_BONDING) { 9419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 9429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 944005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly mBondState.setBondState(address, BluetoothDevice.BOND_NONE, 9459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project BluetoothDevice.UNBOND_REASON_AUTH_CANCELED); 946d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh cancelDeviceCreationNative(address); 9479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 9489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public synchronized boolean removeBond(String address) { 9519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 9529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Need BLUETOOTH_ADMIN permission"); 9538c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh if (!isEnabledInternal()) return false; 9548c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh 955005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly if (!BluetoothAdapter.checkBluetoothAddress(address)) { 9569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 9579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 958d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh return removeDeviceNative(getObjectPathFromAddress(address)); 9599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public synchronized String[] listBonds() { 9629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 9639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mBondState.listInState(BluetoothDevice.BOND_BONDED); 9649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public synchronized int getBondState(String address) { 9679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 968005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly if (!BluetoothAdapter.checkBluetoothAddress(address)) { 969b24e11baac589fe16426f2d243b460ab84991c7bNick Pelly return BluetoothDevice.ERROR; 9709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mBondState.getBondState(address.toUpperCase()); 9729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9749488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh /*package*/ boolean isRemoteDeviceInCache(String address) { 975bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly return (mDeviceProperties.get(address) != null); 9769488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh } 9779488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh 9789488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh /*package*/ String[] getRemoteDeviceProperties(String address) { 9798c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh if (!isEnabledInternal()) return null; 9808c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh 9819488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh String objectPath = getObjectPathFromAddress(address); 9829488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh return (String [])getDevicePropertiesNative(objectPath); 9839488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh } 9849488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh 985d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh /*package*/ synchronized String getRemoteDeviceProperty(String address, String property) { 986bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly Map<String, String> properties = mDeviceProperties.get(address); 987d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh if (properties != null) { 988d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh return properties.get(property); 989d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh } else { 990d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh // Query for remote device properties, again. 991d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh // We will need to reload the cache when we switch Bluetooth on / off 992d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh // or if we crash. 99310eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh if (updateRemoteDevicePropertiesCache(address)) 994d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh return getRemoteDeviceProperty(address, property); 9959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 996d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh Log.e(TAG, "getRemoteDeviceProperty: " + property + "not present:" + address); 997d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh return null; 9989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 100010eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh /* package */ synchronized boolean updateRemoteDevicePropertiesCache(String address) { 100110eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh String[] propValues = getRemoteDeviceProperties(address); 100210eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh if (propValues != null) { 100310eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh addRemoteDeviceProperties(address, propValues); 100410eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh return true; 100510eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh } 100610eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh return false; 100710eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh } 100810eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh 1009d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh /* package */ synchronized void addRemoteDeviceProperties(String address, String[] properties) { 1010395d1023660c5caedf7888def17f8ad826f51bf8Jaikumar Ganesh /* 1011395d1023660c5caedf7888def17f8ad826f51bf8Jaikumar Ganesh * We get a DeviceFound signal every time RSSI changes or name changes. 1012395d1023660c5caedf7888def17f8ad826f51bf8Jaikumar Ganesh * Don't create a new Map object every time */ 1013bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly Map<String, String> propertyValues = mDeviceProperties.get(address); 1014efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh if (propertyValues == null) { 1015395d1023660c5caedf7888def17f8ad826f51bf8Jaikumar Ganesh propertyValues = new HashMap<String, String>(); 1016395d1023660c5caedf7888def17f8ad826f51bf8Jaikumar Ganesh } 1017395d1023660c5caedf7888def17f8ad826f51bf8Jaikumar Ganesh 10188bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh for (int i = 0; i < properties.length; i++) { 10198bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh String name = properties[i]; 1020efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh String newValue = null; 10218bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh int len; 10228bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh if (name == null) { 10238bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh Log.e(TAG, "Error: Remote Device Property at index" + i + "is null"); 10248bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh continue; 10258bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh } 10268bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh if (name.equals("UUIDs") || name.equals("Nodes")) { 1027efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh StringBuilder str = new StringBuilder(); 10288bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh len = Integer.valueOf(properties[++i]); 10298bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh for (int j = 0; j < len; j++) { 1030efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh str.append(properties[++i]); 1031efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh str.append(","); 1032efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh } 1033efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh if (len > 0) { 1034efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh newValue = str.toString(); 10358bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh } 1036d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh } else { 10378bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh newValue = properties[++i]; 1038d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh } 1039efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh 10408bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh propertyValues.put(name, newValue); 10419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1042bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly mDeviceProperties.put(address, propertyValues); 104310eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh 104410eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh // We have added a new remote device or updated its properties. 104510eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh // Also update the serviceChannel cache. 104610eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh updateDeviceServiceChannelCache(address); 10479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1049d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh /* package */ void removeRemoteDeviceProperties(String address) { 1050bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly mDeviceProperties.remove(address); 10519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1053d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh /* package */ synchronized void setRemoteDeviceProperty(String address, String name, 1054d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh String value) { 1055bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly Map <String, String> propVal = mDeviceProperties.get(address); 1056d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh if (propVal != null) { 1057d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh propVal.put(name, value); 1058bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly mDeviceProperties.put(address, propVal); 1059d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh } else { 1060d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh Log.e(TAG, "setRemoteDeviceProperty for a device not in cache:" + address); 10619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1065efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue * Sets the remote device trust state. 1066efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue * 1067efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue * @return boolean to indicate operation success or fail 1068efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue */ 1069efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue public synchronized boolean setTrust(String address, boolean value) { 1070005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly if (!BluetoothAdapter.checkBluetoothAddress(address)) { 1071e6ee3be1c254404dad842298f6f56c11cc6c7ac8Nick Pelly mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 1072e6ee3be1c254404dad842298f6f56c11cc6c7ac8Nick Pelly "Need BLUETOOTH_ADMIN permission"); 1073efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue return false; 1074efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue } 1075efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue 10768c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh if (!isEnabledInternal()) return false; 10778c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh 1078efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue return setDevicePropertyBooleanNative(getObjectPathFromAddress(address), "Trusted", 1079efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue value ? 1 : 0); 1080efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue } 1081efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue 1082efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue /** 1083efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue * Gets the remote device trust state as boolean. 1084efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue * Note: this value may be 1085efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue * retrieved from cache if we retrieved the data before * 1086efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue * 1087efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue * @return boolean to indicate trust or untrust state 1088efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue */ 1089efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue public synchronized boolean getTrustState(String address) { 1090005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly if (!BluetoothAdapter.checkBluetoothAddress(address)) { 1091efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1092efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue return false; 1093efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue } 1094efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue 1095efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue String val = getRemoteDeviceProperty(address, "Trusted"); 1096efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue if (val == null) { 1097efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue return false; 1098efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue } else { 1099efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue return val.equals("true") ? true : false; 1100efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue } 1101efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue } 1102efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue 1103efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue /** 1104d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh * Gets the remote major, minor classes encoded as a 32-bit 11059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * integer. 11069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 11079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Note: this value is retrieved from cache, because we get it during 11089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * remote-device discovery. 11099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 11109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return 32-bit integer encoding the remote major, minor, and service 11119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * classes. 11129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 11139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public synchronized int getRemoteClass(String address) { 1114005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly if (!BluetoothAdapter.checkBluetoothAddress(address)) { 1115ea600ccfb7568f60377c4abc85f56c80af7fdbfcNick Pelly mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1116ea600ccfb7568f60377c4abc85f56c80af7fdbfcNick Pelly return BluetoothClass.ERROR; 11179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1118d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh String val = getRemoteDeviceProperty(address, "Class"); 1119d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh if (val == null) 1120d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh return BluetoothClass.ERROR; 1121d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh else { 1122d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh return Integer.valueOf(val); 1123d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh } 11249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1125d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh 11269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1128dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh * Gets the UUIDs supported by the remote device 11299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 1130dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh * @return array of 128bit ParcelUuids 11319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1132dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh public synchronized ParcelUuid[] getRemoteUuids(String address) { 11339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1134005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly if (!BluetoothAdapter.checkBluetoothAddress(address)) { 11359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return null; 11369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11371caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh return getUuidFromCache(address); 11381caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh } 11391caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh 11401caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh private ParcelUuid[] getUuidFromCache(String address) { 1141d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh String value = getRemoteDeviceProperty(address, "UUIDs"); 1142dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh if (value == null) return null; 1143dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh 1144dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh String[] uuidStrings = null; 1145d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh // The UUIDs are stored as a "," separated string. 1146dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh uuidStrings = value.split(","); 1147dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh ParcelUuid[] uuids = new ParcelUuid[uuidStrings.length]; 1148dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh 1149dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh for (int i = 0; i < uuidStrings.length; i++) { 1150dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh uuids[i] = ParcelUuid.fromString(uuidStrings[i]); 1151dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh } 1152d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh return uuids; 11539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 115516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly /** 115616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly * Connect and fetch new UUID's using SDP. 115716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly * The UUID's found are broadcast as intents. 115816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly * Optionally takes a uuid and callback to fetch the RFCOMM channel for the 115916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly * a given uuid. 116016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly * TODO: Don't wait UUID_INTENT_DELAY to broadcast UUID intents on success 116116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly * TODO: Don't wait UUID_INTENT_DELAY to handle the failure case for 116216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly * callback and broadcast intents. 116316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly */ 116416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly public synchronized boolean fetchRemoteUuids(String address, ParcelUuid uuid, 116516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly IBluetoothCallback callback) { 11661caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 11678c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh if (!isEnabledInternal()) return false; 11688c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh 11691caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh if (!BluetoothAdapter.checkBluetoothAddress(address)) { 11701caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh return false; 11711caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh } 11721caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh 117316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly RemoteService service = new RemoteService(address, uuid); 117416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly if (uuid != null && mUuidCallbackTracker.get(service) != null) { 117516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly // An SDP query for this address & uuid is already in progress 117616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly // Do not add this callback for the uuid 117716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly return false; 117816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } 117916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly 11801caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh if (mUuidIntentTracker.contains(address)) { 11811caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh // An SDP query for this address is already in progress 118216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly // Add this uuid onto the in-progress SDP query 118316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly if (uuid != null) { 118416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly mUuidCallbackTracker.put(new RemoteService(address, uuid), callback); 118516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } 11861caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh return true; 11871caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh } 11881caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh 11891caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh boolean ret; 11901caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh if (getBondState(address) == BluetoothDevice.BOND_BONDED) { 11911caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh String path = getObjectPathFromAddress(address); 11921caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh if (path == null) return false; 11931caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh 11941caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh // Use an empty string for the UUID pattern 11951caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh ret = discoverServicesNative(path, ""); 11961caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh } else { 11971caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh ret = createDeviceNative(address); 11981caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh } 11991caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh 12001caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh mUuidIntentTracker.add(address); 120116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly if (uuid != null) { 120216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly mUuidCallbackTracker.put(new RemoteService(address, uuid), callback); 120316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } 12041caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh 12051caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh Message message = mHandler.obtainMessage(MESSAGE_UUID_INTENT); 12061caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh message.obj = address; 12071caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh mHandler.sendMessageDelayed(message, UUID_INTENT_DELAY); 12081caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh return ret; 12091caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh } 12101caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh 12119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1212d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh * Gets the rfcomm channel associated with the UUID. 121316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly * Pulls records from the cache only. 12149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 1215d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh * @param address Address of the remote device 1216dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh * @param uuid ParcelUuid of the service attribute 12179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 1218d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh * @return rfcomm channel associated with the service attribute 121910eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh * -1 on error 12209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1221dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh public int getRemoteServiceChannel(String address, ParcelUuid uuid) { 12229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 12238c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh if (!isEnabledInternal()) return -1; 12248c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh 1225005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly if (!BluetoothAdapter.checkBluetoothAddress(address)) { 1226b24e11baac589fe16426f2d243b460ab84991c7bNick Pelly return BluetoothDevice.ERROR; 12279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 122810eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh // Check if we are recovering from a crash. 122910eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh if (mDeviceProperties.isEmpty()) { 123010eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh if (!updateRemoteDevicePropertiesCache(address)) 123110eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh return -1; 123210eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh } 123310eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh 123410eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh Map<ParcelUuid, Integer> value = mDeviceServiceChannelCache.get(address); 123510eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh if (value != null && value.containsKey(uuid)) 123610eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh return value.get(uuid); 123710eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh return -1; 12389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public synchronized boolean setPin(String address, byte[] pin) { 12419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 12429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Need BLUETOOTH_ADMIN permission"); 12438c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh if (!isEnabledInternal()) return false; 12448c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh 12459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (pin == null || pin.length <= 0 || pin.length > 16 || 1246005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly !BluetoothAdapter.checkBluetoothAddress(address)) { 12479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 12489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project address = address.toUpperCase(); 12509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Integer data = mEventLoop.getPasskeyAgentRequestData().remove(address); 12519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (data == null) { 12529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.w(TAG, "setPin(" + address + ") called but no native data available, " + 12539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "ignoring. Maybe the PasskeyAgent Request was cancelled by the remote device" + 12549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project " or by bluez.\n"); 12559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 12569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // bluez API wants pin as a string 12589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String pinString; 12599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 12609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project pinString = new String(pin, "UTF8"); 12619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (UnsupportedEncodingException uee) { 12629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.e(TAG, "UTF8 not supported?!?"); 12639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 12649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return setPinNative(address, pinString, data.intValue()); 12669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1268b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh public synchronized boolean setPasskey(String address, int passkey) { 1269b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 1270b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh "Need BLUETOOTH_ADMIN permission"); 12718c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh if (!isEnabledInternal()) return false; 12728c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh 1273005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly if (passkey < 0 || passkey > 999999 || !BluetoothAdapter.checkBluetoothAddress(address)) { 1274b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh return false; 1275b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh } 1276b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh address = address.toUpperCase(); 1277b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh Integer data = mEventLoop.getPasskeyAgentRequestData().remove(address); 1278b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh if (data == null) { 1279b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh Log.w(TAG, "setPasskey(" + address + ") called but no native data available, " + 1280b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh "ignoring. Maybe the PasskeyAgent Request was cancelled by the remote device" + 1281b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh " or by bluez.\n"); 1282b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh return false; 1283b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh } 1284b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh return setPasskeyNative(address, passkey, data.intValue()); 1285b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh } 1286b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh 1287b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh public synchronized boolean setPairingConfirmation(String address, boolean confirm) { 1288b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 1289b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh "Need BLUETOOTH_ADMIN permission"); 12908c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh if (!isEnabledInternal()) return false; 12918c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh 1292b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh address = address.toUpperCase(); 1293b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh Integer data = mEventLoop.getPasskeyAgentRequestData().remove(address); 1294b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh if (data == null) { 1295b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh Log.w(TAG, "setPasskey(" + address + ") called but no native data available, " + 1296b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh "ignoring. Maybe the PasskeyAgent Request was cancelled by the remote device" + 1297b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh " or by bluez.\n"); 1298b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh return false; 1299b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh } 1300b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh return setPairingConfirmationNative(address, confirm, data.intValue()); 1301b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh } 1302b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh 1303b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh public synchronized boolean cancelPairingUserInput(String address) { 13049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 13059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Need BLUETOOTH_ADMIN permission"); 13068c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh if (!isEnabledInternal()) return false; 13078c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh 1308005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly if (!BluetoothAdapter.checkBluetoothAddress(address)) { 13099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 13109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1311005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly mBondState.setBondState(address, BluetoothDevice.BOND_NONE, 1312397d8f4f4829a45f4fe7a672cc395466bbc0f442Jaikumar Ganesh BluetoothDevice.UNBOND_REASON_AUTH_CANCELED); 13139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project address = address.toUpperCase(); 13149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Integer data = mEventLoop.getPasskeyAgentRequestData().remove(address); 13159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (data == null) { 1316b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh Log.w(TAG, "cancelUserInputNative(" + address + ") called but no native data " + 1317b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh "available, ignoring. Maybe the PasskeyAgent Request was already cancelled " + 1318b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh "by the remote or by bluez.\n"); 13199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 13209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1321b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh return cancelPairingUserInputNative(address, data.intValue()); 13229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13248c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh /*package*/ void updateDeviceServiceChannelCache(String address) { 132510eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh ParcelUuid[] deviceUuids = getRemoteUuids(address); 132610eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh // We are storing the rfcomm channel numbers only for the uuids 132710eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh // we are interested in. 132810eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh int channel; 132916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly if (DBG) log("updateDeviceServiceChannelCache(" + address + ")"); 133016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly 133116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly ArrayList<ParcelUuid> applicationUuids = new ArrayList(); 133216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly 133316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly synchronized (this) { 133416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly for (RemoteService service : mUuidCallbackTracker.keySet()) { 133516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly if (service.address.equals(address)) { 133616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly applicationUuids.add(service.uuid); 133716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } 133816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } 133916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } 134010eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh 134110eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh Map <ParcelUuid, Integer> value = new HashMap<ParcelUuid, Integer>(); 134216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly 134316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly // Retrieve RFCOMM channel for default uuids 134416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly for (ParcelUuid uuid : RFCOMM_UUIDS) { 134510eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh if (BluetoothUuid.isUuidPresent(deviceUuids, uuid)) { 134616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly channel = getDeviceServiceChannelNative(getObjectPathFromAddress(address), 134716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly uuid.toString(), 0x0004); 134816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly if (DBG) log("\tuuid(system): " + uuid + " " + channel); 134910eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh value.put(uuid, channel); 135010eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh } 135110eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh } 135216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly // Retrieve RFCOMM channel for application requested uuids 135316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly for (ParcelUuid uuid : applicationUuids) { 135416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly if (BluetoothUuid.isUuidPresent(deviceUuids, uuid)) { 135516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly channel = getDeviceServiceChannelNative(getObjectPathFromAddress(address), 135616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly uuid.toString(), 0x0004); 135716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly if (DBG) log("\tuuid(application): " + uuid + " " + channel); 135816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly value.put(uuid, channel); 135916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } 136016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } 136116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly 136216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly synchronized (this) { 136316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly // Make application callbacks 136416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly for (Iterator<RemoteService> iter = mUuidCallbackTracker.keySet().iterator(); 136516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly iter.hasNext();) { 136616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly RemoteService service = iter.next(); 136716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly if (service.address.equals(address)) { 136816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly channel = -1; 136916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly if (value.get(service.uuid) != null) { 137016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly channel = value.get(service.uuid); 137116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } 137216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly if (channel != -1) { 137316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly if (DBG) log("Making callback for " + service.uuid + " with result " + 137416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly channel); 137516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly IBluetoothCallback callback = mUuidCallbackTracker.get(service); 137616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly if (callback != null) { 137716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly try { 137816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly callback.onRfcommChannelFound(channel); 137916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } catch (RemoteException e) {Log.e(TAG, "", e);} 138016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } 138116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly 138216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly iter.remove(); 138316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } 138416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } 138516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } 138616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly 138716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly // Update cache 138816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly mDeviceServiceChannelCache.put(address, value); 138916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } 139010eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh } 139110eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh 139224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly /** 139324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly * b is a handle to a Binder instance, so that this service can be notified 139424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly * for Applications that terminate unexpectedly, to clean there service 139524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly * records 139624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly */ 139724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly public synchronized int addRfcommServiceRecord(String serviceName, ParcelUuid uuid, 139824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly int channel, IBinder b) { 13998c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 14008c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh if (!isEnabledInternal()) return -1; 14018c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh 140224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly if (serviceName == null || uuid == null || channel < 1 || 140324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly channel > BluetoothSocket.MAX_RFCOMM_CHANNEL) { 140424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly return -1; 140524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly } 140624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly if (BluetoothUuid.isUuidPresent(BluetoothUuid.RESERVED_UUIDS, uuid)) { 140724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly Log.w(TAG, "Attempted to register a reserved UUID: " + uuid); 140824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly return -1; 140924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly } 141024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly int handle = addRfcommServiceRecordNative(serviceName, 141124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly uuid.getUuid().getMostSignificantBits(), uuid.getUuid().getLeastSignificantBits(), 141224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly (short)channel); 141324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly if (DBG) log("new handle " + Integer.toHexString(handle)); 141424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly if (handle == -1) { 141524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly return -1; 141624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly } 141724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly 141824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly int pid = Binder.getCallingPid(); 141924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly mServiceRecordToPid.put(new Integer(handle), new Integer(pid)); 142024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly try { 142124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly b.linkToDeath(new Reaper(handle, pid), 0); 142224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly } catch (RemoteException e) {} 142324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly return handle; 142424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly } 142524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly 142624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly public void removeServiceRecord(int handle) { 142724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, 142824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly "Need BLUETOOTH permission"); 142924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly checkAndRemoveRecord(handle, Binder.getCallingPid()); 143024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly } 143124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly 143224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly private synchronized void checkAndRemoveRecord(int handle, int pid) { 143324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly Integer handleInt = new Integer(handle); 143424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly Integer owner = mServiceRecordToPid.get(handleInt); 143524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly if (owner != null && pid == owner.intValue()) { 143624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly if (DBG) log("Removing service record " + Integer.toHexString(handle) + " for pid " + 143724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly pid); 143824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly mServiceRecordToPid.remove(handleInt); 143924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly removeServiceRecordNative(handle); 144024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly } 144124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly } 144224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly 144324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly private class Reaper implements IBinder.DeathRecipient { 144424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly int pid; 144524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly int handle; 144624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly Reaper(int handle, int pid) { 144724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly this.pid = pid; 144824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly this.handle = handle; 144924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly } 145024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly public void binderDied() { 145124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly synchronized (BluetoothService.this) { 145224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly if (DBG) log("Tracked app " + pid + " died"); 145324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly checkAndRemoveRecord(handle, pid); 145424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly } 145524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly } 145624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly } 145724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly 14589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private final BroadcastReceiver mReceiver = new BroadcastReceiver() { 14599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 14609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void onReceive(Context context, Intent intent) { 14619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String action = intent.getAction(); 14629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (action.equals(Intent.ACTION_AIRPLANE_MODE_CHANGED)) { 14639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ContentResolver resolver = context.getContentResolver(); 14649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Query the airplane mode from Settings.System just to make sure that 14659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // some random app is not sending this intent and disabling bluetooth 14669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean enabled = !isAirplaneModeOn(); 14679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // If bluetooth is currently expected to be on, then enable or disable bluetooth 14689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (Settings.Secure.getInt(resolver, Settings.Secure.BLUETOOTH_ON, 0) > 0) { 14699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (enabled) { 1470105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project enable(false); 14719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 14729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project disable(false); 14739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project }; 14789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void registerForAirplaneMode() { 14809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String airplaneModeRadios = Settings.System.getString(mContext.getContentResolver(), 14819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Settings.System.AIRPLANE_MODE_RADIOS); 14829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mIsAirplaneSensitive = airplaneModeRadios == null 14839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ? true : airplaneModeRadios.contains(Settings.System.RADIO_BLUETOOTH); 14849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mIsAirplaneSensitive) { 14859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mIntentFilter = new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED); 14869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mContext.registerReceiver(mReceiver, mIntentFilter); 14879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* Returns true if airplane mode is currently on */ 14919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private final boolean isAirplaneModeOn() { 14929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return Settings.System.getInt(mContext.getContentResolver(), 14939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Settings.System.AIRPLANE_MODE_ON, 0) == 1; 14949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14961caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh /* Broadcast the Uuid intent */ 14971caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh /*package*/ synchronized void sendUuidIntent(String address) { 14986179965e85ec17b836084a4a3d7963d8a7a1e1ccJaikumar Ganesh ParcelUuid[] uuid = getUuidFromCache(address); 14996179965e85ec17b836084a4a3d7963d8a7a1e1ccJaikumar Ganesh Intent intent = new Intent(BluetoothDevice.ACTION_UUID); 15002d3b98d868cda30535505b2a2fba47aa1c9c052bJaikumar Ganesh intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mAdapter.getRemoteDevice(address)); 15016179965e85ec17b836084a4a3d7963d8a7a1e1ccJaikumar Ganesh intent.putExtra(BluetoothDevice.EXTRA_UUID, uuid); 15026179965e85ec17b836084a4a3d7963d8a7a1e1ccJaikumar Ganesh mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM); 15031caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh 15046179965e85ec17b836084a4a3d7963d8a7a1e1ccJaikumar Ganesh if (mUuidIntentTracker.contains(address)) 15051caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh mUuidIntentTracker.remove(address); 150616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly 150716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } 150816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly 150916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly /*package*/ synchronized void makeServiceChannelCallbacks(String address) { 151016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly for (Iterator<RemoteService> iter = mUuidCallbackTracker.keySet().iterator(); 151116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly iter.hasNext();) { 151216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly RemoteService service = iter.next(); 151316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly if (service.address.equals(address)) { 151416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly if (DBG) log("Cleaning up failed UUID channel lookup: " + service.address + 151516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly " " + service.uuid); 151616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly IBluetoothCallback callback = mUuidCallbackTracker.get(service); 151716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly if (callback != null) { 151816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly try { 151916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly callback.onRfcommChannelFound(-1); 152016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } catch (RemoteException e) {Log.e(TAG, "", e);} 152116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } 152216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly 152316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly iter.remove(); 152416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } 152516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } 15261caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh } 15271caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh 15289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 15299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 1530105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project switch(mBluetoothState) { 1531de893f550301a60274e87aa8168225e7a7a42184Nick Pelly case BluetoothAdapter.STATE_OFF: 153224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly pw.println("Bluetooth OFF\n"); 1533105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project return; 1534de893f550301a60274e87aa8168225e7a7a42184Nick Pelly case BluetoothAdapter.STATE_TURNING_ON: 153524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly pw.println("Bluetooth TURNING ON\n"); 1536105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project return; 1537de893f550301a60274e87aa8168225e7a7a42184Nick Pelly case BluetoothAdapter.STATE_TURNING_OFF: 153824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly pw.println("Bluetooth TURNING OFF\n"); 1539105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project return; 1540de893f550301a60274e87aa8168225e7a7a42184Nick Pelly case BluetoothAdapter.STATE_ON: 154124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly pw.println("Bluetooth ON\n"); 1542105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project } 1543105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project 154424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly pw.println("mIsAirplaneSensitive = " + mIsAirplaneSensitive); 154524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly 154624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly pw.println("Local address = " + getAddress()); 154724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly pw.println("Local name = " + getName()); 154824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly pw.println("isDiscovering() = " + isDiscovering()); 1549105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project 1550105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project BluetoothHeadset headset = new BluetoothHeadset(mContext, null); 1551105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project 1552105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project pw.println("\n--Known devices--"); 1553bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly for (String address : mDeviceProperties.keySet()) { 15541eada0d3d655d6396bf862da954d254856a1bc03Nick Pelly int bondState = mBondState.getBondState(address); 1555105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project pw.printf("%s %10s (%d) %s\n", address, 15561eada0d3d655d6396bf862da954d254856a1bc03Nick Pelly toBondStateString(bondState), 1557105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project mBondState.getAttempt(address), 1558105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project getRemoteName(address)); 155924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly 156024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly Map<ParcelUuid, Integer> uuidChannels = mDeviceServiceChannelCache.get(address); 156124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly if (uuidChannels == null) { 156224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly pw.println("\tuuids = null"); 156324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly } else { 156424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly for (ParcelUuid uuid : uuidChannels.keySet()) { 156524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly Integer channel = uuidChannels.get(uuid); 156624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly if (channel == null) { 156724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly pw.println("\t" + uuid); 156824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly } else { 156924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly pw.println("\t" + uuid + " RFCOMM channel = " + channel); 15701eada0d3d655d6396bf862da954d254856a1bc03Nick Pelly } 15711eada0d3d655d6396bf862da954d254856a1bc03Nick Pelly } 15721eada0d3d655d6396bf862da954d254856a1bc03Nick Pelly } 157316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly for (RemoteService service : mUuidCallbackTracker.keySet()) { 157416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly if (service.address.equals(address)) { 157516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly pw.println("\tPENDING CALLBACK: " + service.uuid); 157616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } 157716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly } 1578105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project } 1579105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project 1580d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh String value = getProperty("Devices"); 15811eada0d3d655d6396bf862da954d254856a1bc03Nick Pelly String[] devicesObjectPath = null; 1582d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh if (value != null) { 1583d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh devicesObjectPath = value.split(","); 1584d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh } 1585105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project pw.println("\n--ACL connected devices--"); 158624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly if (devicesObjectPath != null) { 158724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly for (String device : devicesObjectPath) { 158824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly pw.println(getAddressFromObjectPath(device)); 158924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly } 1590105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project } 1591105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project 1592105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project // Rather not do this from here, but no-where else and I need this 1593105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project // dump 1594105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project pw.println("\n--Headset Service--"); 1595105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project switch (headset.getState()) { 1596105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project case BluetoothHeadset.STATE_DISCONNECTED: 1597105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project pw.println("getState() = STATE_DISCONNECTED"); 1598105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project break; 1599105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project case BluetoothHeadset.STATE_CONNECTING: 1600105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project pw.println("getState() = STATE_CONNECTING"); 1601105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project break; 1602105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project case BluetoothHeadset.STATE_CONNECTED: 1603105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project pw.println("getState() = STATE_CONNECTED"); 1604105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project break; 1605105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project case BluetoothHeadset.STATE_ERROR: 1606105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project pw.println("getState() = STATE_ERROR"); 1607105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project break; 1608105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project } 16096c901db72dbaf57d8fdf26adae6721de14ecae22Nick Pelly 161024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly pw.println("\ngetCurrentHeadset() = " + headset.getCurrentHeadset()); 161124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly pw.println("getBatteryUsageHint() = " + headset.getBatteryUsageHint()); 1612105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project headset.close(); 161324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly pw.println("\n--Application Service Records--"); 161424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly for (Integer handle : mServiceRecordToPid.keySet()) { 161524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly Integer pid = mServiceRecordToPid.get(handle); 161624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly pw.println("\tpid " + pid + " handle " + Integer.toHexString(handle)); 161724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly } 16189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1620d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh /* package */ static int bluezStringToScanMode(boolean pairable, boolean discoverable) { 1621d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh if (pairable && discoverable) 1622bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly return BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE; 1623d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh else if (pairable && !discoverable) 1624bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly return BluetoothAdapter.SCAN_MODE_CONNECTABLE; 1625d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh else 1626bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly return BluetoothAdapter.SCAN_MODE_NONE; 16279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 16299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* package */ static String scanModeToBluezString(int mode) { 16309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project switch (mode) { 1631bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly case BluetoothAdapter.SCAN_MODE_NONE: 16329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return "off"; 1633bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly case BluetoothAdapter.SCAN_MODE_CONNECTABLE: 16349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return "connectable"; 1635bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly case BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE: 16369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return "discoverable"; 16379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return null; 16399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1641d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh /*package*/ String getAddressFromObjectPath(String objectPath) { 1642d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh String adapterObjectPath = getProperty("ObjectPath"); 1643d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh if (adapterObjectPath == null || objectPath == null) { 1644d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh Log.e(TAG, "getAddressFromObjectPath: AdpaterObjectPath:" + adapterObjectPath + 1645d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh " or deviceObjectPath:" + objectPath + " is null"); 1646d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh return null; 1647d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh } 1648d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh if (!objectPath.startsWith(adapterObjectPath)) { 1649d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh Log.e(TAG, "getAddressFromObjectPath: AdpaterObjectPath:" + adapterObjectPath + 1650d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh " is not a prefix of deviceObjectPath:" + objectPath + 1651d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh "bluetoothd crashed ?"); 1652d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh return null; 1653d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh } 1654d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh String address = objectPath.substring(adapterObjectPath.length()); 1655d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh if (address != null) return address.replace('_', ':'); 1656d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh 1657d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh Log.e(TAG, "getAddressFromObjectPath: Address being returned is null"); 1658d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh return null; 1659d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh } 1660d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh 1661d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh /*package*/ String getObjectPathFromAddress(String address) { 1662d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh String path = getProperty("ObjectPath"); 1663d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh if (path == null) { 1664d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh Log.e(TAG, "Error: Object Path is null"); 1665d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh return null; 1666d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh } 1667d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh path = path + address.replace(":", "_"); 1668d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh return path; 1669d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh } 1670d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh 16719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static void log(String msg) { 16729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.d(TAG, msg); 16739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1674d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh 1675d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh private native static void classInitNative(); 1676d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh private native void initializeNativeDataNative(); 1677d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh private native boolean setupNativeDataNative(); 1678d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh private native boolean tearDownNativeDataNative(); 1679d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh private native void cleanupNativeDataNative(); 1680d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh private native String getAdapterPathNative(); 1681d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh 1682d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh private native int isEnabledNative(); 1683d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh private native int enableNative(); 1684d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh private native int disableNative(); 1685d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh 1686d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh private native Object[] getAdapterPropertiesNative(); 1687d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh private native Object[] getDevicePropertiesNative(String objectPath); 1688d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh private native boolean setAdapterPropertyStringNative(String key, String value); 1689d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh private native boolean setAdapterPropertyIntegerNative(String key, int value); 1690d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh private native boolean setAdapterPropertyBooleanNative(String key, int value); 1691d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh 1692d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh private native boolean startDiscoveryNative(); 1693d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh private native boolean stopDiscoveryNative(); 1694d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh 1695d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh private native boolean createPairedDeviceNative(String address, int timeout_ms); 1696d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh private native boolean cancelDeviceCreationNative(String address); 1697d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh private native boolean removeDeviceNative(String objectPath); 1698d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh private native int getDeviceServiceChannelNative(String objectPath, String uuid, 1699d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh int attributeId); 1700d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh 1701b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh private native boolean cancelPairingUserInputNative(String address, int nativeData); 1702d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh private native boolean setPinNative(String address, String pin, int nativeData); 1703b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh private native boolean setPasskeyNative(String address, int passkey, int nativeData); 1704b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh private native boolean setPairingConfirmationNative(String address, boolean confirm, 1705b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh int nativeData); 170624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly private native boolean setDevicePropertyBooleanNative(String objectPath, String key, 170724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly int value); 17081caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh private native boolean createDeviceNative(String address); 170916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly /*package*/ native boolean discoverServicesNative(String objectPath, String pattern); 171010eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh 171124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly private native int addRfcommServiceRecordNative(String name, long uuidMsb, long uuidLsb, 171224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly short channel); 171324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly private native boolean removeServiceRecordNative(int handle); 17149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 1715