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