A2dpStateMachine.java revision 75e9fd59f4d4011ba7155732a41b06f0df40bada
1/* 2 * Copyright (C) 2012 Google Inc. 3 */ 4 5/** 6 * Bluetooth A2dp StateMachine 7 * (Disconnected) 8 * | ^ 9 * CONNECT | | DISCONNECTED 10 * V | 11 * (Pending) 12 * | ^ 13 * CONNECTED | | CONNECT 14 * V | 15 * (Connected) 16 */ 17package com.android.bluetooth.a2dp; 18 19import android.bluetooth.BluetoothA2dp; 20import android.bluetooth.BluetoothAdapter; 21import android.bluetooth.BluetoothDevice; 22import android.bluetooth.BluetoothProfile; 23import android.bluetooth.BluetoothUuid; 24import android.bluetooth.IBluetooth; 25import android.content.Context; 26import android.content.Intent; 27import android.os.Message; 28import android.os.RemoteException; 29import android.os.ServiceManager; 30import android.os.ParcelUuid; 31import android.util.Log; 32import com.android.bluetooth.Utils; 33import com.android.bluetooth.btservice.AdapterService; 34import com.android.bluetooth.btservice.ProfileService; 35import com.android.internal.util.IState; 36import com.android.internal.util.State; 37import com.android.internal.util.StateMachine; 38import java.util.ArrayList; 39import java.util.List; 40import java.util.Set; 41 42final class A2dpStateMachine extends StateMachine { 43 private static final String TAG = "A2dpStateMachine"; 44 private static final boolean DBG = true; 45 46 static final int CONNECT = 1; 47 static final int DISCONNECT = 2; 48 private static final int STACK_EVENT = 101; 49 private static final int CONNECT_TIMEOUT = 201; 50 51 private Disconnected mDisconnected; 52 private Pending mPending; 53 private Connected mConnected; 54 55 private A2dpService mService; 56 private Context mContext; 57 private BluetoothAdapter mAdapter; 58 private static final ParcelUuid[] A2DP_UUIDS = { 59 BluetoothUuid.AudioSink 60 }; 61 62 // mCurrentDevice is the device connected before the state changes 63 // mTargetDevice is the device to be connected 64 // mIncomingDevice is the device connecting to us, valid only in Pending state 65 // when mIncomingDevice is not null, both mCurrentDevice 66 // and mTargetDevice are null 67 // when either mCurrentDevice or mTargetDevice is not null, 68 // mIncomingDevice is null 69 // Stable states 70 // No connection, Disconnected state 71 // both mCurrentDevice and mTargetDevice are null 72 // Connected, Connected state 73 // mCurrentDevice is not null, mTargetDevice is null 74 // Interim states 75 // Connecting to a device, Pending 76 // mCurrentDevice is null, mTargetDevice is not null 77 // Disconnecting device, Connecting to new device 78 // Pending 79 // Both mCurrentDevice and mTargetDevice are not null 80 // Disconnecting device Pending 81 // mCurrentDevice is not null, mTargetDevice is null 82 // Incoming connections Pending 83 // Both mCurrentDevice and mTargetDevice are null 84 private BluetoothDevice mCurrentDevice = null; 85 private BluetoothDevice mTargetDevice = null; 86 private BluetoothDevice mIncomingDevice = null; 87 private BluetoothDevice mPlayingA2dpDevice = null; 88 89 static { 90 classInitNative(); 91 } 92 93 A2dpStateMachine(A2dpService svc, Context context) { 94 super(TAG); 95 mService = svc; 96 mContext = context; 97 mAdapter = BluetoothAdapter.getDefaultAdapter(); 98 99 initNative(); 100 101 mDisconnected = new Disconnected(); 102 mPending = new Pending(); 103 mConnected = new Connected(); 104 105 addState(mDisconnected); 106 addState(mPending); 107 addState(mConnected); 108 109 setInitialState(mDisconnected); 110 } 111 112 public void cleanup() { 113 cleanupNative(); 114 if(mService != null) 115 mService = null; 116 if (mContext != null) 117 mContext = null; 118 if(mAdapter != null) 119 mAdapter = null; 120 } 121 122 private class Disconnected extends State { 123 @Override 124 public void enter() { 125 log("Enter Disconnected: " + getCurrentMessage().what); 126 } 127 128 @Override 129 public boolean processMessage(Message message) { 130 log("Disconnected process message: " + message.what); 131 if (DBG) { 132 if (mCurrentDevice != null || mTargetDevice != null || mIncomingDevice != null) { 133 log("ERROR: current, target, or mIncomingDevice not null in Disconnected"); 134 return NOT_HANDLED; 135 } 136 } 137 138 boolean retValue = HANDLED; 139 switch(message.what) { 140 case CONNECT: 141 BluetoothDevice device = (BluetoothDevice) message.obj; 142 broadcastConnectionState(device, BluetoothProfile.STATE_CONNECTING, 143 BluetoothProfile.STATE_DISCONNECTED); 144 145 if (!connectA2dpNative(getByteAddress(device)) ) { 146 broadcastConnectionState(device, BluetoothProfile.STATE_DISCONNECTED, 147 BluetoothProfile.STATE_CONNECTING); 148 break; 149 } 150 151 synchronized (A2dpStateMachine.this) { 152 mTargetDevice = device; 153 transitionTo(mPending); 154 } 155 // TODO(BT) remove CONNECT_TIMEOUT when the stack 156 // sends back events consistently 157 sendMessageDelayed(CONNECT_TIMEOUT, 30000); 158 break; 159 case DISCONNECT: 160 // ignore 161 break; 162 case STACK_EVENT: 163 StackEvent event = (StackEvent) message.obj; 164 switch (event.type) { 165 case EVENT_TYPE_CONNECTION_STATE_CHANGED: 166 processConnectionEvent(event.valueInt, event.device); 167 break; 168 default: 169 Log.e(TAG, "Unexpected stack event: " + event.type); 170 break; 171 } 172 break; 173 default: 174 return NOT_HANDLED; 175 } 176 return retValue; 177 } 178 179 @Override 180 public void exit() { 181 log("Exit Disconnected: " + getCurrentMessage().what); 182 } 183 184 // in Disconnected state 185 private void processConnectionEvent(int state, BluetoothDevice device) { 186 switch (state) { 187 case CONNECTION_STATE_DISCONNECTED: 188 Log.w(TAG, "Ignore HF DISCONNECTED event, device: " + device); 189 break; 190 case CONNECTION_STATE_CONNECTING: 191 // check priority and accept or reject the connection 192 // Since the state changes to Connecting or directly Connected in some cases.Have the check both in 193 // CONNECTION_STATE_CONNECTING and CONNECTION_STATE_CONNECTED. 194 if (BluetoothProfile.PRIORITY_OFF < mService.getPriority(device)) { 195 Log.i(TAG,"Incoming A2DP accepted"); 196 broadcastConnectionState(device, BluetoothProfile.STATE_CONNECTING, 197 BluetoothProfile.STATE_DISCONNECTED); 198 synchronized (A2dpStateMachine.this) { 199 mIncomingDevice = device; 200 transitionTo(mPending); 201 } 202 } else { 203 //reject the connection and stay in Disconnected state itself 204 Log.i(TAG,"Incoming A2DP rejected"); 205 disconnectA2dpNative(getByteAddress(device)); 206 } 207 break; 208 case CONNECTION_STATE_CONNECTED: 209 Log.w(TAG, "A2DP Connected from Disconnected state"); 210 if (BluetoothProfile.PRIORITY_OFF < mService.getPriority(device)) { 211 Log.i(TAG,"Incoming A2DP accepted"); 212 broadcastConnectionState(device, BluetoothProfile.STATE_CONNECTED, 213 BluetoothProfile.STATE_DISCONNECTED); 214 synchronized (A2dpStateMachine.this) { 215 mCurrentDevice = device; 216 transitionTo(mConnected); 217 } 218 } else { 219 //reject the connection and stay in Disconnected state itself 220 Log.i(TAG,"Incoming A2DP rejected"); 221 disconnectA2dpNative(getByteAddress(device)); 222 } 223 break; 224 case CONNECTION_STATE_DISCONNECTING: 225 Log.w(TAG, "Ignore HF DISCONNECTING event, device: " + device); 226 break; 227 default: 228 Log.e(TAG, "Incorrect state: " + state); 229 break; 230 } 231 } 232 } 233 234 private class Pending extends State { 235 @Override 236 public void enter() { 237 log("Enter Pending: " + getCurrentMessage().what); 238 } 239 240 @Override 241 public boolean processMessage(Message message) { 242 log("Pending process message: " + message.what); 243 244 boolean retValue = HANDLED; 245 switch(message.what) { 246 case CONNECT: 247 deferMessage(message); 248 break; 249 case CONNECT_TIMEOUT: 250 onConnectionStateChanged(CONNECTION_STATE_DISCONNECTED, 251 getByteAddress(mTargetDevice)); 252 break; 253 case DISCONNECT: 254 BluetoothDevice device = (BluetoothDevice) message.obj; 255 if (mCurrentDevice != null && mTargetDevice != null && 256 mTargetDevice.equals(device) ) { 257 // cancel connection to the mTargetDevice 258 broadcastConnectionState(device, BluetoothProfile.STATE_DISCONNECTED, 259 BluetoothProfile.STATE_CONNECTING); 260 synchronized (A2dpStateMachine.this) { 261 mTargetDevice = null; 262 } 263 } else { 264 deferMessage(message); 265 } 266 break; 267 case STACK_EVENT: 268 StackEvent event = (StackEvent) message.obj; 269 switch (event.type) { 270 case EVENT_TYPE_CONNECTION_STATE_CHANGED: 271 removeMessages(CONNECT_TIMEOUT); 272 processConnectionEvent(event.valueInt, event.device); 273 break; 274 default: 275 Log.e(TAG, "Unexpected stack event: " + event.type); 276 break; 277 } 278 break; 279 default: 280 return NOT_HANDLED; 281 } 282 return retValue; 283 } 284 285 // in Pending state 286 private void processConnectionEvent(int state, BluetoothDevice device) { 287 switch (state) { 288 case CONNECTION_STATE_DISCONNECTED: 289 if ((mCurrentDevice != null) && mCurrentDevice.equals(device)) { 290 broadcastConnectionState(mCurrentDevice, 291 BluetoothProfile.STATE_DISCONNECTED, 292 BluetoothProfile.STATE_DISCONNECTING); 293 synchronized (A2dpStateMachine.this) { 294 mCurrentDevice = null; 295 } 296 297 if (mTargetDevice != null) { 298 if (!connectA2dpNative(getByteAddress(mTargetDevice))) { 299 broadcastConnectionState(mTargetDevice, 300 BluetoothProfile.STATE_DISCONNECTED, 301 BluetoothProfile.STATE_CONNECTING); 302 synchronized (A2dpStateMachine.this) { 303 mTargetDevice = null; 304 transitionTo(mDisconnected); 305 } 306 } 307 } else { 308 synchronized (A2dpStateMachine.this) { 309 mIncomingDevice = null; 310 transitionTo(mDisconnected); 311 } 312 } 313 } else if (mTargetDevice != null && mTargetDevice.equals(device)) { 314 // outgoing connection failed 315 broadcastConnectionState(mTargetDevice, BluetoothProfile.STATE_DISCONNECTED, 316 BluetoothProfile.STATE_CONNECTING); 317 synchronized (A2dpStateMachine.this) { 318 mTargetDevice = null; 319 transitionTo(mDisconnected); 320 } 321 } else if (mIncomingDevice != null && mIncomingDevice.equals(device)) { 322 broadcastConnectionState(mIncomingDevice, 323 BluetoothProfile.STATE_DISCONNECTED, 324 BluetoothProfile.STATE_CONNECTING); 325 synchronized (A2dpStateMachine.this) { 326 mIncomingDevice = null; 327 transitionTo(mDisconnected); 328 } 329 } else { 330 Log.e(TAG, "Unknown device Disconnected: " + device); 331 } 332 break; 333 case CONNECTION_STATE_CONNECTED: 334 if ((mCurrentDevice != null) && mCurrentDevice.equals(device)) { 335 // disconnection failed 336 broadcastConnectionState(mCurrentDevice, BluetoothProfile.STATE_CONNECTED, 337 BluetoothProfile.STATE_DISCONNECTING); 338 if (mTargetDevice != null) { 339 broadcastConnectionState(mTargetDevice, BluetoothProfile.STATE_DISCONNECTED, 340 BluetoothProfile.STATE_CONNECTING); 341 } 342 synchronized (A2dpStateMachine.this) { 343 mTargetDevice = null; 344 transitionTo(mConnected); 345 } 346 } else if (mTargetDevice != null && mTargetDevice.equals(device)) { 347 broadcastConnectionState(mTargetDevice, BluetoothProfile.STATE_CONNECTED, 348 BluetoothProfile.STATE_CONNECTING); 349 synchronized (A2dpStateMachine.this) { 350 mCurrentDevice = mTargetDevice; 351 mTargetDevice = null; 352 transitionTo(mConnected); 353 } 354 } else if (mIncomingDevice != null && mIncomingDevice.equals(device)) { 355 broadcastConnectionState(mIncomingDevice, BluetoothProfile.STATE_CONNECTED, 356 BluetoothProfile.STATE_CONNECTING); 357 synchronized (A2dpStateMachine.this) { 358 mCurrentDevice = mIncomingDevice; 359 mIncomingDevice = null; 360 transitionTo(mConnected); 361 } 362 } else { 363 Log.e(TAG, "Unknown device Connected: " + device); 364 // something is wrong here, but sync our state with stack 365 broadcastConnectionState(device, BluetoothProfile.STATE_CONNECTED, 366 BluetoothProfile.STATE_DISCONNECTED); 367 synchronized (A2dpStateMachine.this) { 368 mCurrentDevice = device; 369 mTargetDevice = null; 370 mIncomingDevice = null; 371 transitionTo(mConnected); 372 } 373 } 374 break; 375 case CONNECTION_STATE_CONNECTING: 376 if ((mCurrentDevice != null) && mCurrentDevice.equals(device)) { 377 log("current device tries to connect back"); 378 // TODO(BT) ignore or reject 379 } else if (mTargetDevice != null && mTargetDevice.equals(device)) { 380 // The stack is connecting to target device or 381 // there is an incoming connection from the target device at the same time 382 // we already broadcasted the intent, doing nothing here 383 if (DBG) { 384 log("Stack and target device are connecting"); 385 } 386 } 387 else if (mIncomingDevice != null && mIncomingDevice.equals(device)) { 388 Log.e(TAG, "Another connecting event on the incoming device"); 389 } else { 390 // We get an incoming connecting request while Pending 391 // TODO(BT) is stack handing this case? let's ignore it for now 392 log("Incoming connection while pending, ignore"); 393 } 394 break; 395 case CONNECTION_STATE_DISCONNECTING: 396 if ((mCurrentDevice != null) && mCurrentDevice.equals(device)) { 397 // we already broadcasted the intent, doing nothing here 398 if (DBG) { 399 log("stack is disconnecting mCurrentDevice"); 400 } 401 } else if (mTargetDevice != null && mTargetDevice.equals(device)) { 402 Log.e(TAG, "TargetDevice is getting disconnected"); 403 } else if (mIncomingDevice != null && mIncomingDevice.equals(device)) { 404 Log.e(TAG, "IncomingDevice is getting disconnected"); 405 } else { 406 Log.e(TAG, "Disconnecting unknow device: " + device); 407 } 408 break; 409 default: 410 Log.e(TAG, "Incorrect state: " + state); 411 break; 412 } 413 } 414 415 } 416 417 private class Connected extends State { 418 @Override 419 public void enter() { 420 log("Enter Connected: " + getCurrentMessage().what); 421 // Upon connected, the audio starts out as stopped 422 broadcastAudioState(mCurrentDevice, BluetoothA2dp.STATE_NOT_PLAYING, 423 BluetoothA2dp.STATE_PLAYING); 424 } 425 426 @Override 427 public boolean processMessage(Message message) { 428 log("Connected process message: " + message.what); 429 if (DBG) { 430 if (mCurrentDevice == null) { 431 log("ERROR: mCurrentDevice is null in Connected"); 432 return NOT_HANDLED; 433 } 434 } 435 436 boolean retValue = HANDLED; 437 switch(message.what) { 438 case CONNECT: 439 { 440 BluetoothDevice device = (BluetoothDevice) message.obj; 441 if (mCurrentDevice.equals(device)) { 442 break; 443 } 444 445 broadcastConnectionState(device, BluetoothProfile.STATE_CONNECTING, 446 BluetoothProfile.STATE_DISCONNECTED); 447 if (!disconnectA2dpNative(getByteAddress(mCurrentDevice))) { 448 broadcastConnectionState(device, BluetoothProfile.STATE_DISCONNECTED, 449 BluetoothProfile.STATE_CONNECTING); 450 break; 451 } 452 453 synchronized (A2dpStateMachine.this) { 454 mTargetDevice = device; 455 transitionTo(mPending); 456 } 457 } 458 break; 459 case DISCONNECT: 460 { 461 BluetoothDevice device = (BluetoothDevice) message.obj; 462 if (!mCurrentDevice.equals(device)) { 463 break; 464 } 465 broadcastConnectionState(device, BluetoothProfile.STATE_DISCONNECTING, 466 BluetoothProfile.STATE_CONNECTED); 467 if (!disconnectA2dpNative(getByteAddress(device))) { 468 broadcastConnectionState(device, BluetoothProfile.STATE_CONNECTED, 469 BluetoothProfile.STATE_DISCONNECTED); 470 break; 471 } 472 transitionTo(mPending); 473 } 474 break; 475 case STACK_EVENT: 476 StackEvent event = (StackEvent) message.obj; 477 switch (event.type) { 478 case EVENT_TYPE_CONNECTION_STATE_CHANGED: 479 processConnectionEvent(event.valueInt, event.device); 480 break; 481 case EVENT_TYPE_AUDIO_STATE_CHANGED: 482 processAudioStateEvent(event.valueInt, event.device); 483 break; 484 default: 485 Log.e(TAG, "Unexpected stack event: " + event.type); 486 break; 487 } 488 break; 489 default: 490 return NOT_HANDLED; 491 } 492 return retValue; 493 } 494 495 // in Connected state 496 private void processConnectionEvent(int state, BluetoothDevice device) { 497 switch (state) { 498 case CONNECTION_STATE_DISCONNECTED: 499 if (mCurrentDevice.equals(device)) { 500 broadcastConnectionState(mCurrentDevice, BluetoothProfile.STATE_DISCONNECTED, 501 BluetoothProfile.STATE_CONNECTED); 502 synchronized (A2dpStateMachine.this) { 503 mCurrentDevice = null; 504 transitionTo(mDisconnected); 505 } 506 } else { 507 Log.e(TAG, "Disconnected from unknown device: " + device); 508 } 509 break; 510 default: 511 Log.e(TAG, "Connection State Device: " + device + " bad state: " + state); 512 break; 513 } 514 } 515 private void processAudioStateEvent(int state, BluetoothDevice device) { 516 if (!mCurrentDevice.equals(device)) { 517 Log.e(TAG, "Audio State Device:" + device + "is different from ConnectedDevice:" + 518 mCurrentDevice); 519 return; 520 } 521 switch (state) { 522 case AUDIO_STATE_STARTED: 523 if (mPlayingA2dpDevice == null) { 524 mPlayingA2dpDevice = device; 525 broadcastAudioState(device, BluetoothA2dp.STATE_PLAYING, 526 BluetoothA2dp.STATE_NOT_PLAYING); 527 } 528 break; 529 case AUDIO_STATE_STOPPED: 530 if(mPlayingA2dpDevice != null) { 531 mPlayingA2dpDevice = null; 532 broadcastAudioState(device, BluetoothA2dp.STATE_NOT_PLAYING, 533 BluetoothA2dp.STATE_PLAYING); 534 } 535 break; 536 default: 537 Log.e(TAG, "Audio State Device: " + device + " bad state: " + state); 538 break; 539 } 540 } 541 } 542 543 int getConnectionState(BluetoothDevice device) { 544 if (getCurrentState() == mDisconnected) { 545 return BluetoothProfile.STATE_DISCONNECTED; 546 } 547 548 synchronized (this) { 549 IState currentState = getCurrentState(); 550 if (currentState == mPending) { 551 if ((mTargetDevice != null) && mTargetDevice.equals(device)) { 552 return BluetoothProfile.STATE_CONNECTING; 553 } 554 if ((mCurrentDevice != null) && mCurrentDevice.equals(device)) { 555 return BluetoothProfile.STATE_DISCONNECTING; 556 } 557 if ((mIncomingDevice != null) && mIncomingDevice.equals(device)) { 558 return BluetoothProfile.STATE_CONNECTING; // incoming connection 559 } 560 return BluetoothProfile.STATE_DISCONNECTED; 561 } 562 563 if (currentState == mConnected) { 564 if (mCurrentDevice.equals(device)) { 565 return BluetoothProfile.STATE_CONNECTED; 566 } 567 return BluetoothProfile.STATE_DISCONNECTED; 568 } else { 569 Log.e(TAG, "Bad currentState: " + currentState); 570 return BluetoothProfile.STATE_DISCONNECTED; 571 } 572 } 573 } 574 575 List<BluetoothDevice> getConnectedDevices() { 576 List<BluetoothDevice> devices = new ArrayList<BluetoothDevice>(); 577 synchronized(this) { 578 if (getCurrentState() == mConnected) { 579 devices.add(mCurrentDevice); 580 } 581 } 582 return devices; 583 } 584 585 boolean isPlaying(BluetoothDevice device) { 586 synchronized(this) { 587 if (device.equals(mPlayingA2dpDevice)) { 588 return true; 589 } 590 } 591 return false; 592 } 593 594 synchronized List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) { 595 List<BluetoothDevice> deviceList = new ArrayList<BluetoothDevice>(); 596 Set<BluetoothDevice> bondedDevices = mAdapter.getBondedDevices(); 597 int connectionState; 598 599 for (BluetoothDevice device : bondedDevices) { 600 ParcelUuid[] featureUuids = device.getUuids(); 601 if (!BluetoothUuid.containsAnyUuid(featureUuids, A2DP_UUIDS)) { 602 continue; 603 } 604 connectionState = getConnectionState(device); 605 for(int i = 0; i < states.length; i++) { 606 if (connectionState == states[i]) { 607 deviceList.add(device); 608 } 609 } 610 } 611 return deviceList; 612 } 613 614 // This method does not check for error conditon (newState == prevState) 615 private void broadcastConnectionState(BluetoothDevice device, int newState, int prevState) { 616 Intent intent = new Intent(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED); 617 intent.putExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, prevState); 618 intent.putExtra(BluetoothProfile.EXTRA_STATE, newState); 619 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); 620 mContext.sendBroadcast(intent, ProfileService.BLUETOOTH_PERM); 621 if (DBG) log("Connection state " + device + ": " + prevState + "->" + newState); 622 mService.notifyProfileConnectionStateChanged(device, BluetoothProfile.A2DP, newState, prevState); 623 } 624 625 private void broadcastAudioState(BluetoothDevice device, int state, int prevState) { 626 Intent intent = new Intent(BluetoothA2dp.ACTION_PLAYING_STATE_CHANGED); 627 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); 628 intent.putExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, prevState); 629 intent.putExtra(BluetoothProfile.EXTRA_STATE, state); 630 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 631 mContext.sendBroadcast(intent, A2dpService.BLUETOOTH_PERM); 632 633 if (DBG) log("A2DP Playing state : device: " + device + " State:" + prevState + "->" + state); 634 } 635 636 private byte[] getByteAddress(BluetoothDevice device) { 637 return Utils.getBytesFromAddress(device.getAddress()); 638 } 639 640 private void onConnectionStateChanged(int state, byte[] address) { 641 StackEvent event = new StackEvent(EVENT_TYPE_CONNECTION_STATE_CHANGED); 642 event.valueInt = state; 643 event.device = getDevice(address); 644 sendMessage(STACK_EVENT, event); 645 } 646 647 private void onAudioStateChanged(int state, byte[] address) { 648 StackEvent event = new StackEvent(EVENT_TYPE_AUDIO_STATE_CHANGED); 649 event.valueInt = state; 650 event.device = getDevice(address); 651 sendMessage(STACK_EVENT, event); 652 } 653 private BluetoothDevice getDevice(byte[] address) { 654 return mAdapter.getRemoteDevice(Utils.getAddressStringFromByte(address)); 655 } 656 657 private void log(String msg) { 658 if (DBG) { 659 Log.d(TAG, msg); 660 } 661 } 662 663 private class StackEvent { 664 int type = EVENT_TYPE_NONE; 665 int valueInt = 0; 666 BluetoothDevice device = null; 667 668 private StackEvent(int type) { 669 this.type = type; 670 } 671 } 672 673 // Event types for STACK_EVENT message 674 final private static int EVENT_TYPE_NONE = 0; 675 final private static int EVENT_TYPE_CONNECTION_STATE_CHANGED = 1; 676 final private static int EVENT_TYPE_AUDIO_STATE_CHANGED = 2; 677 678 // Do not modify without updating the HAL bt_av.h files. 679 680 // match up with btav_connection_state_t enum of bt_av.h 681 final static int CONNECTION_STATE_DISCONNECTED = 0; 682 final static int CONNECTION_STATE_CONNECTING = 1; 683 final static int CONNECTION_STATE_CONNECTED = 2; 684 final static int CONNECTION_STATE_DISCONNECTING = 3; 685 686 // match up with btav_audio_state_t enum of bt_av.h 687 final static int AUDIO_STATE_REMOTE_SUSPEND = 0; 688 final static int AUDIO_STATE_STOPPED = 1; 689 final static int AUDIO_STATE_STARTED = 2; 690 691 private native static void classInitNative(); 692 private native void initNative(); 693 private native void cleanupNative(); 694 private native boolean connectA2dpNative(byte[] address); 695 private native boolean disconnectA2dpNative(byte[] address); 696} 697