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