HeadsetClientService.java revision 1ff2e6e9306272bd113c8633c9b52fb169eddcb3
1/* 2 * Copyright (c) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.bluetooth.hfpclient; 18 19import android.bluetooth.BluetoothDevice; 20import android.bluetooth.BluetoothProfile; 21import android.bluetooth.BluetoothHeadsetClient; 22import android.bluetooth.BluetoothHeadsetClientCall; 23import android.bluetooth.IBluetoothHeadsetClient; 24import android.content.BroadcastReceiver; 25import android.content.Context; 26import android.content.Intent; 27import android.content.IntentFilter; 28import android.media.AudioManager; 29import android.os.Bundle; 30import android.os.Message; 31import android.provider.Settings; 32import android.util.Log; 33 34import com.android.bluetooth.btservice.ProfileService; 35import com.android.bluetooth.hfpclient.connserv.HfpClientConnectionService; 36import com.android.bluetooth.Utils; 37 38import java.util.ArrayList; 39import java.util.List; 40import java.util.UUID; 41 42/** 43 * Provides Bluetooth Headset Client (HF Role) profile, as a service in the 44 * Bluetooth application. 45 * 46 * @hide 47 */ 48public class HeadsetClientService extends ProfileService { 49 private static final boolean DBG = false; 50 private static final String TAG = "HeadsetClientService"; 51 52 private HeadsetClientStateMachine mStateMachine; 53 private static HeadsetClientService sHeadsetClientService; 54 55 public static String HFP_CLIENT_STOP_TAG = "hfp_client_stop_tag"; 56 57 @Override 58 protected String getName() { 59 return TAG; 60 } 61 62 @Override 63 public IProfileServiceBinder initBinder() { 64 return new BluetoothHeadsetClientBinder(this); 65 } 66 67 @Override 68 protected boolean start() { 69 mStateMachine = HeadsetClientStateMachine.make(this); 70 IntentFilter filter = new IntentFilter(AudioManager.VOLUME_CHANGED_ACTION); 71 filter.addAction(BluetoothDevice.ACTION_CONNECTION_ACCESS_REPLY); 72 try { 73 registerReceiver(mBroadcastReceiver, filter); 74 } catch (Exception e) { 75 Log.w(TAG, "Unable to register broadcat receiver", e); 76 } 77 setHeadsetClientService(this); 78 79 // Start the HfpClientConnectionService to create connection with telecom when HFP 80 // connection is available. 81 Intent startIntent = new Intent(this, HfpClientConnectionService.class); 82 startService(startIntent); 83 84 return true; 85 } 86 87 @Override 88 protected boolean stop() { 89 try { 90 unregisterReceiver(mBroadcastReceiver); 91 } catch (Exception e) { 92 Log.w(TAG, "Unable to unregister broadcast receiver", e); 93 } 94 95 if (mStateMachine != null) { 96 mStateMachine.doQuit(); 97 } 98 99 // Stop the HfpClientConnectionService. 100 Intent stopIntent = new Intent(this, HfpClientConnectionService.class); 101 stopIntent.putExtra(HFP_CLIENT_STOP_TAG, true); 102 startService(stopIntent); 103 return true; 104 } 105 106 @Override 107 protected boolean cleanup() { 108 if (mStateMachine != null) { 109 mStateMachine.cleanup(); 110 } 111 clearHeadsetClientService(); 112 return true; 113 } 114 115 private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { 116 @Override 117 public void onReceive(Context context, Intent intent) { 118 String action = intent.getAction(); 119 120 // We handle the volume changes for Voice calls here since HFP audio volume control does 121 // not go through audio manager (audio mixer). We check if the voice call volume has 122 // changed and subsequently change the SCO volume see 123 // ({@link HeadsetClientStateMachine#SET_SPEAKER_VOLUME} in 124 // {@link HeadsetClientStateMachine} for details. 125 if (action.equals(AudioManager.VOLUME_CHANGED_ACTION)) { 126 Log.d(TAG, "Volume changed for stream: " + 127 intent.getExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE)); 128 int streamType = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, -1); 129 if (streamType == AudioManager.STREAM_VOICE_CALL) { 130 int streamValue = intent 131 .getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, -1); 132 int streamPrevValue = intent.getIntExtra( 133 AudioManager.EXTRA_PREV_VOLUME_STREAM_VALUE, -1); 134 135 if (streamValue != -1 && streamValue != streamPrevValue) { 136 mStateMachine.sendMessage(mStateMachine.obtainMessage( 137 HeadsetClientStateMachine.SET_SPEAKER_VOLUME, streamValue, 0)); 138 } 139 } 140 } 141 } 142 }; 143 144 /** 145 * Handlers for incoming service calls 146 */ 147 private static class BluetoothHeadsetClientBinder extends IBluetoothHeadsetClient.Stub 148 implements IProfileServiceBinder { 149 private HeadsetClientService mService; 150 151 public BluetoothHeadsetClientBinder(HeadsetClientService svc) { 152 mService = svc; 153 } 154 155 @Override 156 public boolean cleanup() { 157 mService = null; 158 return true; 159 } 160 161 private HeadsetClientService getService() { 162 if (!Utils.checkCaller()) { 163 Log.w(TAG, "HeadsetClient call not allowed for non-active user"); 164 return null; 165 } 166 167 if (mService != null && mService.isAvailable()) { 168 return mService; 169 } 170 return null; 171 } 172 173 @Override 174 public boolean connect(BluetoothDevice device) { 175 HeadsetClientService service = getService(); 176 if (service == null) { 177 return false; 178 } 179 return service.connect(device); 180 } 181 182 @Override 183 public boolean disconnect(BluetoothDevice device) { 184 HeadsetClientService service = getService(); 185 if (service == null) { 186 return false; 187 } 188 return service.disconnect(device); 189 } 190 191 @Override 192 public List<BluetoothDevice> getConnectedDevices() { 193 HeadsetClientService service = getService(); 194 if (service == null) { 195 return new ArrayList<BluetoothDevice>(0); 196 } 197 return service.getConnectedDevices(); 198 } 199 200 @Override 201 public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) { 202 HeadsetClientService service = getService(); 203 if (service == null) { 204 return new ArrayList<BluetoothDevice>(0); 205 } 206 return service.getDevicesMatchingConnectionStates(states); 207 } 208 209 @Override 210 public int getConnectionState(BluetoothDevice device) { 211 HeadsetClientService service = getService(); 212 if (service == null) { 213 return BluetoothProfile.STATE_DISCONNECTED; 214 } 215 return service.getConnectionState(device); 216 } 217 218 @Override 219 public boolean setPriority(BluetoothDevice device, int priority) { 220 HeadsetClientService service = getService(); 221 if (service == null) { 222 return false; 223 } 224 return service.setPriority(device, priority); 225 } 226 227 @Override 228 public int getPriority(BluetoothDevice device) { 229 HeadsetClientService service = getService(); 230 if (service == null) { 231 return BluetoothProfile.PRIORITY_UNDEFINED; 232 } 233 return service.getPriority(device); 234 } 235 236 @Override 237 public boolean startVoiceRecognition(BluetoothDevice device) { 238 HeadsetClientService service = getService(); 239 if (service == null) { 240 return false; 241 } 242 return service.startVoiceRecognition(device); 243 } 244 245 @Override 246 public boolean stopVoiceRecognition(BluetoothDevice device) { 247 HeadsetClientService service = getService(); 248 if (service == null) { 249 return false; 250 } 251 return service.stopVoiceRecognition(device); 252 } 253 254 @Override 255 public boolean acceptIncomingConnect(BluetoothDevice device) { 256 HeadsetClientService service = getService(); 257 if (service == null) { 258 return false; 259 } 260 return service.acceptIncomingConnect(device); 261 } 262 263 @Override 264 public boolean rejectIncomingConnect(BluetoothDevice device) { 265 HeadsetClientService service = getService(); 266 if (service == null) { 267 return false; 268 } 269 return service.rejectIncomingConnect(device); 270 } 271 272 @Override 273 public int getAudioState(BluetoothDevice device) { 274 HeadsetClientService service = getService(); 275 if (service == null) { 276 return BluetoothHeadsetClient.STATE_AUDIO_DISCONNECTED; 277 } 278 return service.getAudioState(device); 279 } 280 281 @Override 282 public void setAudioRouteAllowed(boolean allowed) { 283 HeadsetClientService service = getService(); 284 if (service != null) { 285 service.setAudioRouteAllowed(allowed); 286 } 287 } 288 289 @Override 290 public boolean getAudioRouteAllowed() { 291 HeadsetClientService service = getService(); 292 if (service != null) { 293 return service.getAudioRouteAllowed(); 294 } 295 296 return false; 297 } 298 299 @Override 300 public boolean connectAudio() { 301 HeadsetClientService service = getService(); 302 if (service == null) { 303 return false; 304 } 305 return service.connectAudio(); 306 } 307 308 @Override 309 public boolean disconnectAudio() { 310 HeadsetClientService service = getService(); 311 if (service == null) { 312 return false; 313 } 314 return service.disconnectAudio(); 315 } 316 317 @Override 318 public boolean acceptCall(BluetoothDevice device, int flag) { 319 HeadsetClientService service = getService(); 320 if (service == null) { 321 return false; 322 } 323 return service.acceptCall(device, flag); 324 } 325 326 @Override 327 public boolean rejectCall(BluetoothDevice device) { 328 HeadsetClientService service = getService(); 329 if (service == null) { 330 return false; 331 } 332 return service.rejectCall(device); 333 } 334 335 @Override 336 public boolean holdCall(BluetoothDevice device) { 337 HeadsetClientService service = getService(); 338 if (service == null) { 339 return false; 340 } 341 return service.holdCall(device); 342 } 343 344 @Override 345 public boolean terminateCall(BluetoothDevice device, BluetoothHeadsetClientCall call) { 346 HeadsetClientService service = getService(); 347 if (service == null) { 348 Log.w(TAG, "service is null"); 349 return false; 350 } 351 return service.terminateCall(device, call.getUUID()); 352 } 353 354 @Override 355 public boolean explicitCallTransfer(BluetoothDevice device) { 356 HeadsetClientService service = getService(); 357 if (service == null) { 358 return false; 359 } 360 return service.explicitCallTransfer(device); 361 } 362 363 @Override 364 public boolean enterPrivateMode(BluetoothDevice device, int index) { 365 HeadsetClientService service = getService(); 366 if (service == null) { 367 return false; 368 } 369 return service.enterPrivateMode(device, index); 370 } 371 372 @Override 373 public BluetoothHeadsetClientCall dial(BluetoothDevice device, String number) { 374 HeadsetClientService service = getService(); 375 if (service == null) { 376 return null; 377 } 378 return service.dial(device, number); 379 } 380 381 @Override 382 public List<BluetoothHeadsetClientCall> getCurrentCalls(BluetoothDevice device) { 383 HeadsetClientService service = getService(); 384 if (service == null) { 385 return null; 386 } 387 return service.getCurrentCalls(device); 388 } 389 390 @Override 391 public boolean sendDTMF(BluetoothDevice device, byte code) { 392 HeadsetClientService service = getService(); 393 if (service == null) { 394 return false; 395 } 396 return service.sendDTMF(device, code); 397 } 398 399 @Override 400 public boolean getLastVoiceTagNumber(BluetoothDevice device) { 401 HeadsetClientService service = getService(); 402 if (service == null) { 403 return false; 404 } 405 return service.getLastVoiceTagNumber(device); 406 } 407 408 @Override 409 public Bundle getCurrentAgEvents(BluetoothDevice device) { 410 HeadsetClientService service = getService(); 411 if (service == null) { 412 return null; 413 } 414 return service.getCurrentAgEvents(device); 415 } 416 417 @Override 418 public Bundle getCurrentAgFeatures(BluetoothDevice device) { 419 HeadsetClientService service = getService(); 420 if (service == null) { 421 return null; 422 } 423 return service.getCurrentAgFeatures(device); 424 } 425 }; 426 427 // API methods 428 public static synchronized HeadsetClientService getHeadsetClientService() { 429 if (sHeadsetClientService != null && sHeadsetClientService.isAvailable()) { 430 if (DBG) { 431 Log.d(TAG, "getHeadsetClientService(): returning " + sHeadsetClientService); 432 } 433 return sHeadsetClientService; 434 } 435 if (DBG) { 436 if (sHeadsetClientService == null) { 437 Log.d(TAG, "getHeadsetClientService(): service is NULL"); 438 } else if (!(sHeadsetClientService.isAvailable())) { 439 Log.d(TAG, "getHeadsetClientService(): service is not available"); 440 } 441 } 442 return null; 443 } 444 445 private static synchronized void setHeadsetClientService(HeadsetClientService instance) { 446 if (instance != null && instance.isAvailable()) { 447 if (DBG) { 448 Log.d(TAG, "setHeadsetClientService(): set to: " + sHeadsetClientService); 449 } 450 sHeadsetClientService = instance; 451 } else { 452 if (DBG) { 453 if (sHeadsetClientService == null) { 454 Log.d(TAG, "setHeadsetClientService(): service not available"); 455 } else if (!sHeadsetClientService.isAvailable()) { 456 Log.d(TAG, "setHeadsetClientService(): service is cleaning up"); 457 } 458 } 459 } 460 } 461 462 private static synchronized void clearHeadsetClientService() { 463 sHeadsetClientService = null; 464 } 465 466 public boolean connect(BluetoothDevice device) { 467 enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 468 "Need BLUETOOTH ADMIN permission"); 469 470 if (getPriority(device) == BluetoothProfile.PRIORITY_OFF) { 471 return false; 472 } 473 474 int connectionState = mStateMachine.getConnectionState(device); 475 if (connectionState == BluetoothProfile.STATE_CONNECTED || 476 connectionState == BluetoothProfile.STATE_CONNECTING) { 477 return false; 478 } 479 480 mStateMachine.sendMessage(HeadsetClientStateMachine.CONNECT, device); 481 return true; 482 } 483 484 boolean disconnect(BluetoothDevice device) { 485 enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 486 "Need BLUETOOTH ADMIN permission"); 487 int connectionState = mStateMachine.getConnectionState(device); 488 if (connectionState != BluetoothProfile.STATE_CONNECTED && 489 connectionState != BluetoothProfile.STATE_CONNECTING) { 490 return false; 491 } 492 493 mStateMachine.sendMessage(HeadsetClientStateMachine.DISCONNECT, device); 494 return true; 495 } 496 497 public List<BluetoothDevice> getConnectedDevices() { 498 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 499 return mStateMachine.getConnectedDevices(); 500 } 501 502 private List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) { 503 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 504 return mStateMachine.getDevicesMatchingConnectionStates(states); 505 } 506 507 int getConnectionState(BluetoothDevice device) { 508 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 509 return mStateMachine.getConnectionState(device); 510 } 511 512 // TODO Should new setting for HeadsetClient priority be created? 513 public boolean setPriority(BluetoothDevice device, int priority) { 514 enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 515 "Need BLUETOOTH_ADMIN permission"); 516 Settings.Global.putInt(getContentResolver(), 517 Settings.Global.getBluetoothHeadsetPriorityKey(device.getAddress()), 518 priority); 519 if (DBG) { 520 Log.d(TAG, "Saved priority " + device + " = " + priority); 521 } 522 return true; 523 } 524 525 public int getPriority(BluetoothDevice device) { 526 enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 527 "Need BLUETOOTH_ADMIN permission"); 528 int priority = Settings.Global.getInt(getContentResolver(), 529 Settings.Global.getBluetoothHeadsetPriorityKey(device.getAddress()), 530 BluetoothProfile.PRIORITY_UNDEFINED); 531 return priority; 532 } 533 534 boolean startVoiceRecognition(BluetoothDevice device) { 535 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 536 int connectionState = mStateMachine.getConnectionState(device); 537 if (connectionState != BluetoothProfile.STATE_CONNECTED && 538 connectionState != BluetoothProfile.STATE_CONNECTING) { 539 return false; 540 } 541 mStateMachine.sendMessage(HeadsetClientStateMachine.VOICE_RECOGNITION_START); 542 return true; 543 } 544 545 boolean stopVoiceRecognition(BluetoothDevice device) { 546 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 547 // It seem that we really need to check the AudioOn state. 548 // But since we allow startVoiceRecognition in STATE_CONNECTED and 549 // STATE_CONNECTING state, we do these 2 in this method 550 int connectionState = mStateMachine.getConnectionState(device); 551 if (connectionState != BluetoothProfile.STATE_CONNECTED && 552 connectionState != BluetoothProfile.STATE_CONNECTING) { 553 return false; 554 } 555 mStateMachine.sendMessage(HeadsetClientStateMachine.VOICE_RECOGNITION_STOP); 556 return true; 557 } 558 559 boolean acceptIncomingConnect(BluetoothDevice device) { 560 // TODO(BT) remove it if stack does access control 561 return false; 562 } 563 564 boolean rejectIncomingConnect(BluetoothDevice device) { 565 // TODO(BT) remove it if stack does access control 566 return false; 567 } 568 569 int getAudioState(BluetoothDevice device) { 570 return mStateMachine.getAudioState(device); 571 } 572 573 public void setAudioRouteAllowed(boolean allowed) { 574 mStateMachine.setAudioRouteAllowed(allowed); 575 } 576 577 public boolean getAudioRouteAllowed() { 578 return mStateMachine.getAudioRouteAllowed(); 579 } 580 581 boolean connectAudio() { 582 enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH_ADMIN permission"); 583 if (!mStateMachine.isConnected()) { 584 return false; 585 } 586 if (mStateMachine.isAudioOn()) { 587 return false; 588 } 589 mStateMachine.sendMessage(HeadsetClientStateMachine.CONNECT_AUDIO); 590 return true; 591 } 592 593 boolean disconnectAudio() { 594 enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH_ADMIN permission"); 595 if (!mStateMachine.isAudioOn()) { 596 return false; 597 } 598 mStateMachine.sendMessage(HeadsetClientStateMachine.DISCONNECT_AUDIO); 599 return true; 600 } 601 602 boolean holdCall(BluetoothDevice device) { 603 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 604 int connectionState = mStateMachine.getConnectionState(device); 605 if (connectionState != BluetoothProfile.STATE_CONNECTED && 606 connectionState != BluetoothProfile.STATE_CONNECTING) { 607 return false; 608 } 609 Message msg = mStateMachine.obtainMessage(HeadsetClientStateMachine.HOLD_CALL); 610 mStateMachine.sendMessage(msg); 611 return true; 612 } 613 614 boolean acceptCall(BluetoothDevice device, int flag) { 615 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 616 int connectionState = mStateMachine.getConnectionState(device); 617 if (connectionState != BluetoothProfile.STATE_CONNECTED && 618 connectionState != BluetoothProfile.STATE_CONNECTING) { 619 return false; 620 } 621 Message msg = mStateMachine.obtainMessage(HeadsetClientStateMachine.ACCEPT_CALL); 622 msg.arg1 = flag; 623 mStateMachine.sendMessage(msg); 624 return true; 625 } 626 627 boolean rejectCall(BluetoothDevice device) { 628 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 629 int connectionState = mStateMachine.getConnectionState(device); 630 if (connectionState != BluetoothProfile.STATE_CONNECTED && 631 connectionState != BluetoothProfile.STATE_CONNECTING) { 632 return false; 633 } 634 635 Message msg = mStateMachine.obtainMessage(HeadsetClientStateMachine.REJECT_CALL); 636 mStateMachine.sendMessage(msg); 637 return true; 638 } 639 640 boolean terminateCall(BluetoothDevice device, UUID uuid) { 641 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 642 int connectionState = mStateMachine.getConnectionState(device); 643 if (connectionState != BluetoothProfile.STATE_CONNECTED && 644 connectionState != BluetoothProfile.STATE_CONNECTING) { 645 return false; 646 } 647 648 Message msg = mStateMachine.obtainMessage(HeadsetClientStateMachine.TERMINATE_CALL); 649 msg.obj = uuid; 650 mStateMachine.sendMessage(msg); 651 return true; 652 } 653 654 boolean enterPrivateMode(BluetoothDevice device, int index) { 655 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 656 int connectionState = mStateMachine.getConnectionState(device); 657 if (connectionState != BluetoothProfile.STATE_CONNECTED && 658 connectionState != BluetoothProfile.STATE_CONNECTING) { 659 return false; 660 } 661 662 Message msg = mStateMachine.obtainMessage(HeadsetClientStateMachine.ENTER_PRIVATE_MODE); 663 msg.arg1 = index; 664 mStateMachine.sendMessage(msg); 665 return true; 666 } 667 668 BluetoothHeadsetClientCall dial(BluetoothDevice device, String number) { 669 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 670 int connectionState = mStateMachine.getConnectionState(device); 671 if (connectionState != BluetoothProfile.STATE_CONNECTED && 672 connectionState != BluetoothProfile.STATE_CONNECTING) { 673 return null; 674 } 675 676 BluetoothHeadsetClientCall call = new BluetoothHeadsetClientCall( 677 device, HeadsetClientStateMachine.HF_ORIGINATED_CALL_ID, 678 BluetoothHeadsetClientCall.CALL_STATE_DIALING, number, false /* multiparty */, 679 true /* outgoing */); 680 Message msg = mStateMachine.obtainMessage(HeadsetClientStateMachine.DIAL_NUMBER); 681 msg.obj = call; 682 mStateMachine.sendMessage(msg); 683 return call; 684 } 685 686 public boolean sendDTMF(BluetoothDevice device, byte code) { 687 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 688 int connectionState = mStateMachine.getConnectionState(device); 689 if (connectionState != BluetoothProfile.STATE_CONNECTED && 690 connectionState != BluetoothProfile.STATE_CONNECTING) { 691 return false; 692 } 693 Message msg = mStateMachine.obtainMessage(HeadsetClientStateMachine.SEND_DTMF); 694 msg.arg1 = code; 695 mStateMachine.sendMessage(msg); 696 return true; 697 } 698 699 public boolean getLastVoiceTagNumber(BluetoothDevice device) { 700 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 701 int connectionState = mStateMachine.getConnectionState(device); 702 if (connectionState != BluetoothProfile.STATE_CONNECTED && 703 connectionState != BluetoothProfile.STATE_CONNECTING) { 704 return false; 705 } 706 Message msg = mStateMachine.obtainMessage(HeadsetClientStateMachine.LAST_VTAG_NUMBER); 707 mStateMachine.sendMessage(msg); 708 return true; 709 } 710 711 public List<BluetoothHeadsetClientCall> getCurrentCalls(BluetoothDevice device) { 712 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 713 int connectionState = mStateMachine.getConnectionState(device); 714 if (connectionState != BluetoothProfile.STATE_CONNECTED) { 715 return null; 716 } 717 return mStateMachine.getCurrentCalls(); 718 } 719 720 public boolean explicitCallTransfer(BluetoothDevice device) { 721 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 722 int connectionState = mStateMachine.getConnectionState(device); 723 if (connectionState != BluetoothProfile.STATE_CONNECTED && 724 connectionState != BluetoothProfile.STATE_CONNECTING) { 725 return false; 726 } 727 Message msg = mStateMachine 728 .obtainMessage(HeadsetClientStateMachine.EXPLICIT_CALL_TRANSFER); 729 mStateMachine.sendMessage(msg); 730 return true; 731 } 732 733 public Bundle getCurrentAgEvents(BluetoothDevice device) { 734 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 735 int connectionState = mStateMachine.getConnectionState(device); 736 if (connectionState != BluetoothProfile.STATE_CONNECTED) { 737 return null; 738 } 739 return mStateMachine.getCurrentAgEvents(); 740 } 741 742 public Bundle getCurrentAgFeatures(BluetoothDevice device) { 743 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 744 int connectionState = mStateMachine.getConnectionState(device); 745 if (connectionState != BluetoothProfile.STATE_CONNECTED) { 746 return null; 747 } 748 return mStateMachine.getCurrentAgFeatures(); 749 } 750 751 @Override 752 public void dump(StringBuilder sb) { 753 super.dump(sb); 754 if (mStateMachine != null) { 755 mStateMachine.dump(sb); 756 } 757 } 758} 759