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