HeadsetClientService.java revision 05462fe44531f887fe91ac173ec645e91b236025
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 return false; 349 } 350 return service.terminateCall(device, call.getUUID()); 351 } 352 353 @Override 354 public boolean explicitCallTransfer(BluetoothDevice device) { 355 HeadsetClientService service = getService(); 356 if (service == null) { 357 return false; 358 } 359 return service.explicitCallTransfer(device); 360 } 361 362 @Override 363 public boolean enterPrivateMode(BluetoothDevice device, int index) { 364 HeadsetClientService service = getService(); 365 if (service == null) { 366 return false; 367 } 368 return service.enterPrivateMode(device, index); 369 } 370 371 @Override 372 public BluetoothHeadsetClientCall dial(BluetoothDevice device, String number) { 373 HeadsetClientService service = getService(); 374 if (service == null) { 375 return null; 376 } 377 return service.dial(device, number); 378 } 379 380 @Override 381 public List<BluetoothHeadsetClientCall> getCurrentCalls(BluetoothDevice device) { 382 HeadsetClientService service = getService(); 383 if (service == null) { 384 return null; 385 } 386 return service.getCurrentCalls(device); 387 } 388 389 @Override 390 public boolean sendDTMF(BluetoothDevice device, byte code) { 391 HeadsetClientService service = getService(); 392 if (service == null) { 393 return false; 394 } 395 return service.sendDTMF(device, code); 396 } 397 398 @Override 399 public boolean getLastVoiceTagNumber(BluetoothDevice device) { 400 HeadsetClientService service = getService(); 401 if (service == null) { 402 return false; 403 } 404 return service.getLastVoiceTagNumber(device); 405 } 406 407 @Override 408 public Bundle getCurrentAgEvents(BluetoothDevice device) { 409 HeadsetClientService service = getService(); 410 if (service == null) { 411 return null; 412 } 413 return service.getCurrentAgEvents(device); 414 } 415 416 @Override 417 public Bundle getCurrentAgFeatures(BluetoothDevice device) { 418 HeadsetClientService service = getService(); 419 if (service == null) { 420 return null; 421 } 422 return service.getCurrentAgFeatures(device); 423 } 424 }; 425 426 // API methods 427 public static synchronized HeadsetClientService getHeadsetClientService() { 428 if (sHeadsetClientService != null && sHeadsetClientService.isAvailable()) { 429 if (DBG) { 430 Log.d(TAG, "getHeadsetClientService(): returning " + sHeadsetClientService); 431 } 432 return sHeadsetClientService; 433 } 434 if (DBG) { 435 if (sHeadsetClientService == null) { 436 Log.d(TAG, "getHeadsetClientService(): service is NULL"); 437 } else if (!(sHeadsetClientService.isAvailable())) { 438 Log.d(TAG, "getHeadsetClientService(): service is not available"); 439 } 440 } 441 return null; 442 } 443 444 private static synchronized void setHeadsetClientService(HeadsetClientService instance) { 445 if (instance != null && instance.isAvailable()) { 446 if (DBG) { 447 Log.d(TAG, "setHeadsetClientService(): set to: " + sHeadsetClientService); 448 } 449 sHeadsetClientService = instance; 450 } else { 451 if (DBG) { 452 if (sHeadsetClientService == null) { 453 Log.d(TAG, "setHeadsetClientService(): service not available"); 454 } else if (!sHeadsetClientService.isAvailable()) { 455 Log.d(TAG, "setHeadsetClientService(): service is cleaning up"); 456 } 457 } 458 } 459 } 460 461 private static synchronized void clearHeadsetClientService() { 462 sHeadsetClientService = null; 463 } 464 465 public boolean connect(BluetoothDevice device) { 466 enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 467 "Need BLUETOOTH ADMIN permission"); 468 469 if (getPriority(device) == BluetoothProfile.PRIORITY_OFF) { 470 return false; 471 } 472 473 int connectionState = mStateMachine.getConnectionState(device); 474 if (connectionState == BluetoothProfile.STATE_CONNECTED || 475 connectionState == BluetoothProfile.STATE_CONNECTING) { 476 return false; 477 } 478 479 mStateMachine.sendMessage(HeadsetClientStateMachine.CONNECT, device); 480 return true; 481 } 482 483 boolean disconnect(BluetoothDevice device) { 484 enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 485 "Need BLUETOOTH ADMIN permission"); 486 int connectionState = mStateMachine.getConnectionState(device); 487 if (connectionState != BluetoothProfile.STATE_CONNECTED && 488 connectionState != BluetoothProfile.STATE_CONNECTING) { 489 return false; 490 } 491 492 mStateMachine.sendMessage(HeadsetClientStateMachine.DISCONNECT, device); 493 return true; 494 } 495 496 public List<BluetoothDevice> getConnectedDevices() { 497 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 498 return mStateMachine.getConnectedDevices(); 499 } 500 501 private List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) { 502 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 503 return mStateMachine.getDevicesMatchingConnectionStates(states); 504 } 505 506 int getConnectionState(BluetoothDevice device) { 507 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 508 return mStateMachine.getConnectionState(device); 509 } 510 511 // TODO Should new setting for HeadsetClient priority be created? 512 public boolean setPriority(BluetoothDevice device, int priority) { 513 enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 514 "Need BLUETOOTH_ADMIN permission"); 515 Settings.Global.putInt(getContentResolver(), 516 Settings.Global.getBluetoothHeadsetPriorityKey(device.getAddress()), 517 priority); 518 if (DBG) { 519 Log.d(TAG, "Saved priority " + device + " = " + priority); 520 } 521 return true; 522 } 523 524 public int getPriority(BluetoothDevice device) { 525 enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 526 "Need BLUETOOTH_ADMIN permission"); 527 int priority = Settings.Global.getInt(getContentResolver(), 528 Settings.Global.getBluetoothHeadsetPriorityKey(device.getAddress()), 529 BluetoothProfile.PRIORITY_UNDEFINED); 530 return priority; 531 } 532 533 boolean startVoiceRecognition(BluetoothDevice device) { 534 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 535 int connectionState = mStateMachine.getConnectionState(device); 536 if (connectionState != BluetoothProfile.STATE_CONNECTED && 537 connectionState != BluetoothProfile.STATE_CONNECTING) { 538 return false; 539 } 540 mStateMachine.sendMessage(HeadsetClientStateMachine.VOICE_RECOGNITION_START); 541 return true; 542 } 543 544 boolean stopVoiceRecognition(BluetoothDevice device) { 545 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 546 // It seem that we really need to check the AudioOn state. 547 // But since we allow startVoiceRecognition in STATE_CONNECTED and 548 // STATE_CONNECTING state, we do these 2 in this method 549 int connectionState = mStateMachine.getConnectionState(device); 550 if (connectionState != BluetoothProfile.STATE_CONNECTED && 551 connectionState != BluetoothProfile.STATE_CONNECTING) { 552 return false; 553 } 554 mStateMachine.sendMessage(HeadsetClientStateMachine.VOICE_RECOGNITION_STOP); 555 return true; 556 } 557 558 boolean acceptIncomingConnect(BluetoothDevice device) { 559 // TODO(BT) remove it if stack does access control 560 return false; 561 } 562 563 boolean rejectIncomingConnect(BluetoothDevice device) { 564 // TODO(BT) remove it if stack does access control 565 return false; 566 } 567 568 int getAudioState(BluetoothDevice device) { 569 return mStateMachine.getAudioState(device); 570 } 571 572 public void setAudioRouteAllowed(boolean allowed) { 573 mStateMachine.setAudioRouteAllowed(allowed); 574 } 575 576 public boolean getAudioRouteAllowed() { 577 return mStateMachine.getAudioRouteAllowed(); 578 } 579 580 boolean connectAudio() { 581 enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH_ADMIN permission"); 582 if (!mStateMachine.isConnected()) { 583 return false; 584 } 585 if (mStateMachine.isAudioOn()) { 586 return false; 587 } 588 mStateMachine.sendMessage(HeadsetClientStateMachine.CONNECT_AUDIO); 589 return true; 590 } 591 592 boolean disconnectAudio() { 593 enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH_ADMIN permission"); 594 if (!mStateMachine.isAudioOn()) { 595 return false; 596 } 597 mStateMachine.sendMessage(HeadsetClientStateMachine.DISCONNECT_AUDIO); 598 return true; 599 } 600 601 boolean holdCall(BluetoothDevice device) { 602 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 603 int connectionState = mStateMachine.getConnectionState(device); 604 if (connectionState != BluetoothProfile.STATE_CONNECTED && 605 connectionState != BluetoothProfile.STATE_CONNECTING) { 606 return false; 607 } 608 Message msg = mStateMachine.obtainMessage(HeadsetClientStateMachine.HOLD_CALL); 609 mStateMachine.sendMessage(msg); 610 return true; 611 } 612 613 boolean acceptCall(BluetoothDevice device, int flag) { 614 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 615 int connectionState = mStateMachine.getConnectionState(device); 616 if (connectionState != BluetoothProfile.STATE_CONNECTED && 617 connectionState != BluetoothProfile.STATE_CONNECTING) { 618 return false; 619 } 620 Message msg = mStateMachine.obtainMessage(HeadsetClientStateMachine.ACCEPT_CALL); 621 msg.arg1 = flag; 622 mStateMachine.sendMessage(msg); 623 return true; 624 } 625 626 boolean rejectCall(BluetoothDevice device) { 627 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 628 int connectionState = mStateMachine.getConnectionState(device); 629 if (connectionState != BluetoothProfile.STATE_CONNECTED && 630 connectionState != BluetoothProfile.STATE_CONNECTING) { 631 return false; 632 } 633 634 Message msg = mStateMachine.obtainMessage(HeadsetClientStateMachine.REJECT_CALL); 635 mStateMachine.sendMessage(msg); 636 return true; 637 } 638 639 boolean terminateCall(BluetoothDevice device, UUID uuid) { 640 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 641 int connectionState = mStateMachine.getConnectionState(device); 642 if (connectionState != BluetoothProfile.STATE_CONNECTED && 643 connectionState != BluetoothProfile.STATE_CONNECTING) { 644 return false; 645 } 646 647 Message msg = mStateMachine.obtainMessage(HeadsetClientStateMachine.TERMINATE_CALL); 648 msg.obj = uuid; 649 mStateMachine.sendMessage(msg); 650 return true; 651 } 652 653 boolean enterPrivateMode(BluetoothDevice device, int index) { 654 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 655 int connectionState = mStateMachine.getConnectionState(device); 656 if (connectionState != BluetoothProfile.STATE_CONNECTED && 657 connectionState != BluetoothProfile.STATE_CONNECTING) { 658 return false; 659 } 660 661 Message msg = mStateMachine.obtainMessage(HeadsetClientStateMachine.ENTER_PRIVATE_MODE); 662 msg.arg1 = index; 663 mStateMachine.sendMessage(msg); 664 return true; 665 } 666 667 BluetoothHeadsetClientCall dial(BluetoothDevice device, String number) { 668 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 669 int connectionState = mStateMachine.getConnectionState(device); 670 if (connectionState != BluetoothProfile.STATE_CONNECTED && 671 connectionState != BluetoothProfile.STATE_CONNECTING) { 672 return null; 673 } 674 675 BluetoothHeadsetClientCall call = new BluetoothHeadsetClientCall( 676 device, HeadsetClientStateMachine.HF_ORIGINATED_CALL_ID, 677 BluetoothHeadsetClientCall.CALL_STATE_DIALING, number, false /* multiparty */, 678 true /* outgoing */); 679 Message msg = mStateMachine.obtainMessage(HeadsetClientStateMachine.DIAL_NUMBER); 680 msg.obj = call; 681 mStateMachine.sendMessage(msg); 682 return call; 683 } 684 685 public boolean sendDTMF(BluetoothDevice device, byte code) { 686 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 687 int connectionState = mStateMachine.getConnectionState(device); 688 if (connectionState != BluetoothProfile.STATE_CONNECTED && 689 connectionState != BluetoothProfile.STATE_CONNECTING) { 690 return false; 691 } 692 Message msg = mStateMachine.obtainMessage(HeadsetClientStateMachine.SEND_DTMF); 693 msg.arg1 = code; 694 mStateMachine.sendMessage(msg); 695 return true; 696 } 697 698 public boolean getLastVoiceTagNumber(BluetoothDevice device) { 699 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 700 int connectionState = mStateMachine.getConnectionState(device); 701 if (connectionState != BluetoothProfile.STATE_CONNECTED && 702 connectionState != BluetoothProfile.STATE_CONNECTING) { 703 return false; 704 } 705 Message msg = mStateMachine.obtainMessage(HeadsetClientStateMachine.LAST_VTAG_NUMBER); 706 mStateMachine.sendMessage(msg); 707 return true; 708 } 709 710 public List<BluetoothHeadsetClientCall> getCurrentCalls(BluetoothDevice device) { 711 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 712 int connectionState = mStateMachine.getConnectionState(device); 713 if (connectionState != BluetoothProfile.STATE_CONNECTED) { 714 return null; 715 } 716 return mStateMachine.getCurrentCalls(); 717 } 718 719 public boolean explicitCallTransfer(BluetoothDevice device) { 720 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 721 int connectionState = mStateMachine.getConnectionState(device); 722 if (connectionState != BluetoothProfile.STATE_CONNECTED && 723 connectionState != BluetoothProfile.STATE_CONNECTING) { 724 return false; 725 } 726 Message msg = mStateMachine 727 .obtainMessage(HeadsetClientStateMachine.EXPLICIT_CALL_TRANSFER); 728 mStateMachine.sendMessage(msg); 729 return true; 730 } 731 732 public Bundle getCurrentAgEvents(BluetoothDevice device) { 733 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 734 int connectionState = mStateMachine.getConnectionState(device); 735 if (connectionState != BluetoothProfile.STATE_CONNECTED) { 736 return null; 737 } 738 return mStateMachine.getCurrentAgEvents(); 739 } 740 741 public Bundle getCurrentAgFeatures(BluetoothDevice device) { 742 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 743 int connectionState = mStateMachine.getConnectionState(device); 744 if (connectionState != BluetoothProfile.STATE_CONNECTED) { 745 return null; 746 } 747 return mStateMachine.getCurrentAgFeatures(); 748 } 749 750 @Override 751 public void dump(StringBuilder sb) { 752 super.dump(sb); 753 if (mStateMachine != null) { 754 mStateMachine.dump(sb); 755 } 756 } 757} 758