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