AdapterService.java revision 676cb1bdd1c14c7af56562bab51f168e7f8f6d62
1/* 2 * Copyright (C) 2012 Google Inc. 3 */ 4 5/** 6 * @hide 7 */ 8 9package com.android.bluetooth.btservice; 10 11import android.app.Application; 12import android.app.Service; 13import android.bluetooth.BluetoothAdapter; 14import android.bluetooth.BluetoothDevice; 15import android.bluetooth.BluetoothProfile; 16import android.bluetooth.IBluetooth; 17import android.content.BroadcastReceiver; 18import android.content.ContentResolver; 19import android.content.Context; 20import android.content.Intent; 21import android.content.IntentFilter; 22import android.os.Binder; 23import android.os.IBinder; 24import android.os.Message; 25import android.os.ParcelUuid; 26import android.os.RemoteException; 27import android.os.ServiceManager; 28import android.provider.Settings; 29import android.util.Log; 30import android.util.Pair; 31 32import com.android.bluetooth.a2dp.A2dpService; 33import com.android.bluetooth.hid.HidService; 34import com.android.bluetooth.hfp.HeadsetService; 35import com.android.bluetooth.hdp.HealthService; 36import com.android.bluetooth.Utils; 37import com.android.bluetooth.btservice.RemoteDevices.DeviceProperties; 38 39import java.util.HashMap; 40import java.util.Set; 41 42public class AdapterService extends Application { 43 private static final String TAG = "BluetoothAdapterService"; 44 private static final boolean DBG = true; 45 46 static final String BLUETOOTH_ADMIN_PERM = 47 android.Manifest.permission.BLUETOOTH_ADMIN; 48 static final String BLUETOOTH_PERM = android.Manifest.permission.BLUETOOTH; 49 50 private AdapterProperties mAdapterProperties; 51 private int mAdapterState; 52 private Context mContext; 53 private boolean mIsAirplaneSensitive; 54 private boolean mIsAirplaneToggleable; 55 private static AdapterService sAdapterService; 56 57 private BluetoothAdapter mAdapter; 58 private AdapterState mAdapterStateMachine; 59 private BondStateMachine mBondStateMachine; 60 private JniCallbacks mJniCallbacks; 61 62 63 private RemoteDevices mRemoteDevices; 64 static { 65 System.loadLibrary("bluetooth_jni"); 66 classInitNative(); 67 } 68 69 @Override 70 public void onCreate() { 71 super.onCreate(); 72 ServiceManager.addService(Context.BLUETOOTH_SERVICE, mBinder); 73 74 mAdapter = BluetoothAdapter.getDefaultAdapter(); 75 mContext = this; 76 sAdapterService = this; 77 78 IntentFilter filter = new IntentFilter(); 79 filter.addAction(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED); 80 registerForAirplaneMode(filter); 81 registerReceiver(mReceiver, filter); 82 83 mRemoteDevices = RemoteDevices.getInstance(this, mContext); 84 mAdapterProperties = AdapterProperties.getInstance(this, mContext); 85 mAdapterStateMachine = new AdapterState(this, mContext, mAdapterProperties); 86 mBondStateMachine = new BondStateMachine(this, mContext, mAdapterProperties); 87 mJniCallbacks = JniCallbacks.getInstance(mRemoteDevices, mAdapterProperties, 88 mAdapterStateMachine, mBondStateMachine); 89 90 91 initNative(); 92 mAdapterStateMachine.start(); 93 mBondStateMachine.start(); 94 //TODO(BT): Remove this when BT is no longer a persitent process. 95 int bluetoothOn = Settings.Secure.getInt(mContext.getContentResolver(), 96 Settings.Secure.BLUETOOTH_ON, 0); 97 if (!isAirplaneModeOn() && bluetoothOn != 0) mAdapter.enable(); 98 startService(new Intent(this, HeadsetService.class)); 99 startService(new Intent(this, A2dpService.class)); 100 startService(new Intent(this, HidService.class)); 101 startService(new Intent(this, HealthService.class)); 102 } 103 104 @Override 105 protected void finalize() throws Throwable { 106 mContext.unregisterReceiver(mReceiver); 107 try { 108 cleanupNative(); 109 } finally { 110 super.finalize(); 111 } 112 } 113 114 private final BroadcastReceiver mReceiver = new BroadcastReceiver() { 115 @Override 116 public void onReceive(Context context, Intent intent) { 117 if (intent == null) return; 118 119 String action = intent.getAction(); 120 if (action.equals(Intent.ACTION_AIRPLANE_MODE_CHANGED)) { 121 ContentResolver resolver = context.getContentResolver(); 122 // Query the airplane mode from Settings.System just to make sure that 123 // some random app is not sending this intent and disabling bluetooth 124 if (isAirplaneModeOn()) { 125 mAdapterStateMachine.sendMessage(AdapterState.AIRPLANE_MODE_ON); 126 } else { 127 mAdapterStateMachine.sendMessage(AdapterState.AIRPLANE_MODE_OFF); 128 } 129 } 130 } 131 }; 132 133 134 135 private void registerForAirplaneMode(IntentFilter filter) { 136 final ContentResolver resolver = mContext.getContentResolver(); 137 final String airplaneModeRadios = Settings.System.getString(resolver, 138 Settings.System.AIRPLANE_MODE_RADIOS); 139 final String toggleableRadios = Settings.System.getString(resolver, 140 Settings.System.AIRPLANE_MODE_TOGGLEABLE_RADIOS); 141 142 mIsAirplaneSensitive = airplaneModeRadios == null ? true : 143 airplaneModeRadios.contains(Settings.System.RADIO_BLUETOOTH); 144 mIsAirplaneToggleable = toggleableRadios == null ? false : 145 toggleableRadios.contains(Settings.System.RADIO_BLUETOOTH); 146 147 if (mIsAirplaneSensitive) { 148 filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED); 149 } 150 } 151 152 /* Returns true if airplane mode is currently on */ 153 private final boolean isAirplaneModeOn() { 154 return Settings.System.getInt(mContext.getContentResolver(), 155 Settings.System.AIRPLANE_MODE_ON, 0) == 1; 156 } 157 158 /** 159 * Handlers for incoming service calls 160 */ 161 private final IBluetooth.Stub mBinder = new IBluetooth.Stub() { 162 public boolean isEnabled() { 163 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 164 return mAdapterProperties.getState() == BluetoothAdapter.STATE_ON; 165 } 166 167 public int getState() { 168 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 169 return mAdapterProperties.getState(); 170 } 171 172 public boolean enable() { 173 enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 174 "Need BLUETOOTH ADMIN permission"); 175 // Persist the setting 176 Message m = 177 mAdapterStateMachine.obtainMessage(AdapterState.USER_TURN_ON); 178 m.arg1 = 1; 179 mAdapterStateMachine.sendMessage(m); 180 return true; 181 } 182 183 public boolean disable(boolean persist) { 184 enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 185 "Need BLUETOOTH ADMIN permission"); 186 int val = (persist ? 1 : 0); 187 Message m = 188 mAdapterStateMachine.obtainMessage(AdapterState.USER_TURN_OFF); 189 m.arg1 = val; 190 mAdapterStateMachine.sendMessage(m); 191 return true; 192 } 193 194 public String getAddress() { 195 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 196 String addrString = null; 197 byte[] address = mAdapterProperties.getAddress(); 198 return Utils.getAddressStringFromByte(address); 199 } 200 201 public ParcelUuid[] getUuids() { 202 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 203 return mAdapterProperties.getUuids(); 204 } 205 206 public String getName() { 207 enforceCallingOrSelfPermission(BLUETOOTH_PERM, 208 "Need BLUETOOTH permission"); 209 return mAdapterProperties.getName(); 210 } 211 212 public boolean setName(String name) { 213 enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 214 "Need BLUETOOTH ADMIN permission"); 215 return mAdapterProperties.setName(name); 216 } 217 218 public int getScanMode() { 219 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 220 return mAdapterProperties.getScanMode(); 221 } 222 223 public boolean setScanMode(int mode, int duration) { 224 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 225 setDiscoverableTimeout(duration); 226 227 int newMode = convertScanModeToHal(mode); 228 return mAdapterProperties.setScanMode(newMode); 229 } 230 231 public int getDiscoverableTimeout() { 232 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 233 return mAdapterProperties.getDiscoverableTimeout(); 234 } 235 236 public boolean setDiscoverableTimeout(int timeout) { 237 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 238 return mAdapterProperties.setDiscoverableTimeout(timeout); 239 } 240 241 public boolean startDiscovery() { 242 enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 243 "Need BLUETOOTH ADMIN permission"); 244 return startDiscoveryNative(); 245 } 246 247 public boolean cancelDiscovery() { 248 enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 249 "Need BLUETOOTH ADMIN permission"); 250 return cancelDiscoveryNative(); 251 } 252 253 public boolean isDiscovering() { 254 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 255 return mAdapterProperties.isDiscovering(); 256 } 257 258 public BluetoothDevice[] getBondedDevices() { 259 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 260 debugLog("Get Bonded Devices being called"); 261 return mAdapterProperties.getBondedDevices(); 262 } 263 264 public int getAdapterConnectionState() { 265 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 266 return mAdapterProperties.getConnectionState(); 267 } 268 269 public int getProfileConnectionState(int profile) { 270 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 271 return mAdapterProperties.getProfileConnectionState(profile); 272 } 273 274 public boolean createBond(BluetoothDevice device) { 275 enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 276 "Need BLUETOOTH ADMIN permission"); 277 DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device); 278 if (deviceProp != null && deviceProp.getBondState() != BluetoothDevice.BOND_NONE) { 279 return false; 280 } 281 282 Message msg = mBondStateMachine.obtainMessage(BondStateMachine.CREATE_BOND); 283 msg.obj = device; 284 mBondStateMachine.sendMessage(msg); 285 return true; 286 } 287 288 public boolean cancelBondProcess(BluetoothDevice device) { 289 enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH ADMIN permission"); 290 byte[] addr = Utils.getBytesFromAddress(device.getAddress()); 291 return cancelBondNative(addr); 292 } 293 294 public boolean removeBond(BluetoothDevice device) { 295 enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 296 "Need BLUETOOTH ADMIN permission"); 297 DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device); 298 if (deviceProp == null || deviceProp.getBondState() != BluetoothDevice.BOND_BONDED) { 299 return false; 300 } 301 Message msg = mBondStateMachine.obtainMessage(BondStateMachine.REMOVE_BOND); 302 msg.obj = device; 303 mBondStateMachine.sendMessage(msg); 304 return true; 305 } 306 307 public int getBondState(BluetoothDevice device) { 308 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 309 DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device); 310 if (deviceProp == null) { 311 return BluetoothDevice.BOND_NONE; 312 } 313 return deviceProp.getBondState(); 314 } 315 316 public String getRemoteName(BluetoothDevice device) { 317 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 318 DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device); 319 if (deviceProp == null) return null; 320 return deviceProp.getName(); 321 } 322 323 public String getRemoteAlias(BluetoothDevice device) { 324 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 325 DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device); 326 if (deviceProp == null) return null; 327 return deviceProp.getAlias(); 328 } 329 330 public boolean setRemoteAlias(BluetoothDevice device, String name) { 331 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 332 DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device); 333 if (deviceProp == null) return false; 334 deviceProp.setAlias(name); 335 return true; 336 } 337 338 public int getRemoteClass(BluetoothDevice device) { 339 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 340 DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device); 341 if (deviceProp == null) return 0; 342 343 return deviceProp.getBluetoothClass(); 344 } 345 346 public ParcelUuid[] getRemoteUuids(BluetoothDevice device) { 347 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 348 DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device); 349 if (deviceProp == null) return null; 350 return deviceProp.getUuids(); 351 } 352 353 public boolean fetchRemoteUuids(BluetoothDevice device) { 354 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 355 mRemoteDevices.performSdp(device); 356 return true; 357 } 358 359 public boolean setPin(BluetoothDevice device, boolean accept, int len, byte[] pinCode) { 360 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 361 DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device); 362 if (deviceProp == null || deviceProp.getBondState() != BluetoothDevice.BOND_BONDING) { 363 return false; 364 } 365 366 byte[] addr = Utils.getBytesFromAddress(device.getAddress()); 367 return pinReplyNative(addr, accept, len, pinCode); 368 } 369 370 public boolean setPasskey(BluetoothDevice device, boolean accept, int len, byte[] passkey) { 371 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 372 DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device); 373 if (deviceProp == null || deviceProp.getBondState() != BluetoothDevice.BOND_BONDING) { 374 return false; 375 } 376 377 byte[] addr = Utils.getBytesFromAddress(device.getAddress()); 378 return sspReplyNative(addr, AbstractionLayer.BT_SSP_VARIANT_PASSKEY_ENTRY, accept, 379 Utils.byteArrayToInt(passkey)); 380 } 381 382 public boolean setPairingConfirmation(BluetoothDevice device, boolean accept) { 383 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 384 DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device); 385 if (deviceProp == null || deviceProp.getBondState() != BluetoothDevice.BOND_BONDING) { 386 return false; 387 } 388 389 byte[] addr = Utils.getBytesFromAddress(device.getAddress()); 390 return sspReplyNative(addr, AbstractionLayer.BT_SSP_VARIANT_PASSKEY_CONFIRMATION, 391 accept, 0); 392 } 393 394 public void sendConnectionStateChange(BluetoothDevice 395 device, int profile, int state, int prevState) { 396 // Since this is a binder call check if Bluetooth is on still 397 if (getState() == BluetoothAdapter.STATE_OFF) return; 398 399 mAdapterProperties.sendConnectionStateChange(device, profile, state, prevState); 400 401 } 402 403 }; 404 405 private int convertScanModeToHal(int mode) { 406 switch (mode) { 407 case BluetoothAdapter.SCAN_MODE_NONE: 408 return AbstractionLayer.BT_SCAN_MODE_NONE; 409 case BluetoothAdapter.SCAN_MODE_CONNECTABLE: 410 return AbstractionLayer.BT_SCAN_MODE_CONNECTABLE; 411 case BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE: 412 return AbstractionLayer.BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE; 413 } 414 errorLog("Incorrect scan mode in convertScanModeToHal"); 415 return -1; 416 } 417 418 int convertScanModeFromHal(int mode) { 419 switch (mode) { 420 case AbstractionLayer.BT_SCAN_MODE_NONE: 421 return BluetoothAdapter.SCAN_MODE_NONE; 422 case AbstractionLayer.BT_SCAN_MODE_CONNECTABLE: 423 return BluetoothAdapter.SCAN_MODE_CONNECTABLE; 424 case AbstractionLayer.BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE: 425 return BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE; 426 } 427 errorLog("Incorrect scan mode in convertScanModeFromHal"); 428 return -1; 429 } 430 431 private static void debugLog(String msg) { 432 Log.d(TAG, msg); 433 } 434 435 private static void errorLog(String msg) { 436 Log.e(TAG, msg); 437 } 438 439 void persistBluetoothSetting(boolean setOn) { 440 long origCallerIdentityToken = Binder.clearCallingIdentity(); 441 Settings.Secure.putInt(mContext.getContentResolver(), 442 Settings.Secure.BLUETOOTH_ON, 443 setOn ? 1 : 0); 444 Binder.restoreCallingIdentity(origCallerIdentityToken); 445 } 446 447 private boolean getBluetoothPersistedSetting() { 448 ContentResolver contentResolver = mContext.getContentResolver(); 449 return (Settings.Secure.getInt(contentResolver, 450 Settings.Secure.BLUETOOTH_ON, 0) > 0); 451 } 452 453 private native static void classInitNative(); 454 private native boolean initNative(); 455 private native void cleanupNative(); 456 /*package*/ native boolean enableNative(); 457 /*package*/ native boolean disableNative(); 458 /*package*/ native boolean setAdapterPropertyNative(int type, byte[] val); 459 /*package*/ native boolean getAdapterPropertiesNative(); 460 /*package*/ native boolean getAdapterPropertyNative(int type); 461 /*package*/ native boolean setAdapterPropertyNative(int type); 462 /*package*/ native boolean 463 setDevicePropertyNative(byte[] address, int type, byte[] val); 464 /*package*/ native boolean getDevicePropertyNative(byte[] address, int type); 465 466 /*package*/ native boolean createBondNative(byte[] address); 467 /*package*/ native boolean removeBondNative(byte[] address); 468 /*package*/ native boolean cancelBondNative(byte[] address); 469 470 private native boolean startDiscoveryNative(); 471 private native boolean cancelDiscoveryNative(); 472 473 private native boolean pinReplyNative(byte[] address, boolean accept, int len, byte[] pin); 474 private native boolean sspReplyNative(byte[] address, int type, boolean 475 accept, int passkey); 476} 477