1 /* 2 * Copyright 2017 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 17 package com.android.bluetooth.hfp; 18 19 import android.bluetooth.BluetoothAdapter; 20 import android.bluetooth.BluetoothDevice; 21 import android.util.Log; 22 23 import com.android.bluetooth.Utils; 24 import com.android.bluetooth.btservice.AdapterService; 25 import com.android.bluetooth.flags.Flags; 26 import com.android.internal.annotations.GuardedBy; 27 import com.android.internal.annotations.VisibleForTesting; 28 29 import java.util.Objects; 30 31 /** 32 * Defines native calls that are used by state machine/service to either send or receive messages 33 * to/from the native stack. This file is registered for the native methods in corresponding CPP 34 * file. 35 */ 36 public class HeadsetNativeInterface { 37 private static final String TAG = "HeadsetNativeInterface"; 38 39 private final BluetoothAdapter mAdapter = BluetoothAdapter.getDefaultAdapter(); 40 41 @GuardedBy("INSTANCE_LOCK") 42 private static HeadsetNativeInterface sInstance; 43 44 private static final Object INSTANCE_LOCK = new Object(); 45 46 private AdapterService mAdapterService; 47 HeadsetNativeInterface()48 private HeadsetNativeInterface() { 49 mAdapterService = 50 Objects.requireNonNull( 51 AdapterService.getAdapterService(), 52 "AdapterService cannot be null when HeadsetNativeInterface init"); 53 } 54 55 /** 56 * This class is a singleton because native library should only be loaded once 57 * 58 * @return default instance 59 */ getInstance()60 public static HeadsetNativeInterface getInstance() { 61 synchronized (INSTANCE_LOCK) { 62 if (sInstance == null) { 63 sInstance = new HeadsetNativeInterface(); 64 } 65 return sInstance; 66 } 67 } 68 69 /** Set singleton instance. */ 70 @VisibleForTesting setInstance(HeadsetNativeInterface instance)71 public static void setInstance(HeadsetNativeInterface instance) { 72 synchronized (INSTANCE_LOCK) { 73 sInstance = instance; 74 } 75 } 76 sendMessageToService(HeadsetStackEvent event)77 private void sendMessageToService(HeadsetStackEvent event) { 78 HeadsetService service = HeadsetService.getHeadsetService(); 79 if (service != null) { 80 service.messageFromNative(event); 81 } else { 82 // Service must call cleanup() when quiting and native stack shouldn't send any event 83 // after cleanup() -> cleanupNative() is called. 84 Log.w(TAG, "Stack sent event while service is not available: " + event); 85 } 86 } 87 getDevice(byte[] address)88 private BluetoothDevice getDevice(byte[] address) { 89 return mAdapterService.getDeviceFromByte(address); 90 } 91 getByteAddress(BluetoothDevice device)92 private byte[] getByteAddress(BluetoothDevice device) { 93 if (device == null) { 94 // Set bt_stack's active device to default if java layer set active device to null 95 return Utils.getBytesFromAddress("00:00:00:00:00:00"); 96 } 97 if (Flags.identityAddressNullIfUnknown()) { 98 return Utils.getByteBrEdrAddress(device); 99 } else { 100 return mAdapterService.getByteIdentityAddress(device); 101 } 102 } 103 onConnectionStateChanged(int state, byte[] address)104 void onConnectionStateChanged(int state, byte[] address) { 105 HeadsetStackEvent event = 106 new HeadsetStackEvent( 107 HeadsetStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED, 108 state, 109 getDevice(address)); 110 sendMessageToService(event); 111 } 112 113 // Callbacks for native code 114 onAudioStateChanged(int state, byte[] address)115 private void onAudioStateChanged(int state, byte[] address) { 116 HeadsetStackEvent event = 117 new HeadsetStackEvent( 118 HeadsetStackEvent.EVENT_TYPE_AUDIO_STATE_CHANGED, 119 state, 120 getDevice(address)); 121 sendMessageToService(event); 122 } 123 onVrStateChanged(int state, byte[] address)124 private void onVrStateChanged(int state, byte[] address) { 125 HeadsetStackEvent event = 126 new HeadsetStackEvent( 127 HeadsetStackEvent.EVENT_TYPE_VR_STATE_CHANGED, state, getDevice(address)); 128 sendMessageToService(event); 129 } 130 onAnswerCall(byte[] address)131 private void onAnswerCall(byte[] address) { 132 HeadsetStackEvent event = 133 new HeadsetStackEvent(HeadsetStackEvent.EVENT_TYPE_ANSWER_CALL, getDevice(address)); 134 sendMessageToService(event); 135 } 136 onHangupCall(byte[] address)137 private void onHangupCall(byte[] address) { 138 HeadsetStackEvent event = 139 new HeadsetStackEvent(HeadsetStackEvent.EVENT_TYPE_HANGUP_CALL, getDevice(address)); 140 sendMessageToService(event); 141 } 142 onVolumeChanged(int type, int volume, byte[] address)143 private void onVolumeChanged(int type, int volume, byte[] address) { 144 HeadsetStackEvent event = 145 new HeadsetStackEvent( 146 HeadsetStackEvent.EVENT_TYPE_VOLUME_CHANGED, 147 type, 148 volume, 149 getDevice(address)); 150 sendMessageToService(event); 151 } 152 onDialCall(String number, byte[] address)153 private void onDialCall(String number, byte[] address) { 154 HeadsetStackEvent event = 155 new HeadsetStackEvent( 156 HeadsetStackEvent.EVENT_TYPE_DIAL_CALL, number, getDevice(address)); 157 sendMessageToService(event); 158 } 159 onSendDtmf(int dtmf, byte[] address)160 private void onSendDtmf(int dtmf, byte[] address) { 161 HeadsetStackEvent event = 162 new HeadsetStackEvent( 163 HeadsetStackEvent.EVENT_TYPE_SEND_DTMF, dtmf, getDevice(address)); 164 sendMessageToService(event); 165 } 166 onNoiseReductionEnable(boolean enable, byte[] address)167 private void onNoiseReductionEnable(boolean enable, byte[] address) { 168 HeadsetStackEvent event = 169 new HeadsetStackEvent( 170 HeadsetStackEvent.EVENT_TYPE_NOISE_REDUCTION, 171 enable ? 1 : 0, 172 getDevice(address)); 173 sendMessageToService(event); 174 } 175 onWBS(int codec, byte[] address)176 private void onWBS(int codec, byte[] address) { 177 HeadsetStackEvent event = 178 new HeadsetStackEvent(HeadsetStackEvent.EVENT_TYPE_WBS, codec, getDevice(address)); 179 sendMessageToService(event); 180 } 181 onSWB(int codec, int swb, byte[] address)182 private void onSWB(int codec, int swb, byte[] address) { 183 HeadsetStackEvent event = 184 new HeadsetStackEvent( 185 HeadsetStackEvent.EVENT_TYPE_SWB, codec, swb, getDevice(address)); 186 sendMessageToService(event); 187 } 188 onAtChld(int chld, byte[] address)189 private void onAtChld(int chld, byte[] address) { 190 HeadsetStackEvent event = 191 new HeadsetStackEvent( 192 HeadsetStackEvent.EVENT_TYPE_AT_CHLD, chld, getDevice(address)); 193 sendMessageToService(event); 194 } 195 onAtCnum(byte[] address)196 private void onAtCnum(byte[] address) { 197 HeadsetStackEvent event = 198 new HeadsetStackEvent( 199 HeadsetStackEvent.EVENT_TYPE_SUBSCRIBER_NUMBER_REQUEST, getDevice(address)); 200 sendMessageToService(event); 201 } 202 onAtCind(byte[] address)203 private void onAtCind(byte[] address) { 204 HeadsetStackEvent event = 205 new HeadsetStackEvent(HeadsetStackEvent.EVENT_TYPE_AT_CIND, getDevice(address)); 206 sendMessageToService(event); 207 } 208 onAtCops(byte[] address)209 private void onAtCops(byte[] address) { 210 HeadsetStackEvent event = 211 new HeadsetStackEvent(HeadsetStackEvent.EVENT_TYPE_AT_COPS, getDevice(address)); 212 sendMessageToService(event); 213 } 214 onAtClcc(byte[] address)215 private void onAtClcc(byte[] address) { 216 HeadsetStackEvent event = 217 new HeadsetStackEvent(HeadsetStackEvent.EVENT_TYPE_AT_CLCC, getDevice(address)); 218 sendMessageToService(event); 219 } 220 onUnknownAt(String atString, byte[] address)221 private void onUnknownAt(String atString, byte[] address) { 222 HeadsetStackEvent event = 223 new HeadsetStackEvent( 224 HeadsetStackEvent.EVENT_TYPE_UNKNOWN_AT, atString, getDevice(address)); 225 sendMessageToService(event); 226 } 227 onKeyPressed(byte[] address)228 private void onKeyPressed(byte[] address) { 229 HeadsetStackEvent event = 230 new HeadsetStackEvent(HeadsetStackEvent.EVENT_TYPE_KEY_PRESSED, getDevice(address)); 231 sendMessageToService(event); 232 } 233 onATBind(String atString, byte[] address)234 private void onATBind(String atString, byte[] address) { 235 HeadsetStackEvent event = 236 new HeadsetStackEvent( 237 HeadsetStackEvent.EVENT_TYPE_BIND, atString, getDevice(address)); 238 sendMessageToService(event); 239 } 240 onATBiev(int indId, int indValue, byte[] address)241 private void onATBiev(int indId, int indValue, byte[] address) { 242 HeadsetStackEvent event = 243 new HeadsetStackEvent( 244 HeadsetStackEvent.EVENT_TYPE_BIEV, indId, indValue, getDevice(address)); 245 sendMessageToService(event); 246 } 247 onAtBia( boolean service, boolean roam, boolean signal, boolean battery, byte[] address)248 private void onAtBia( 249 boolean service, boolean roam, boolean signal, boolean battery, byte[] address) { 250 HeadsetAgIndicatorEnableState agIndicatorEnableState = 251 new HeadsetAgIndicatorEnableState(service, roam, signal, battery); 252 HeadsetStackEvent event = 253 new HeadsetStackEvent( 254 HeadsetStackEvent.EVENT_TYPE_BIA, 255 agIndicatorEnableState, 256 getDevice(address)); 257 sendMessageToService(event); 258 } 259 260 // Native wrappers to help unit testing 261 262 /** 263 * Initialize native stack 264 * 265 * @param maxHfClients maximum number of headset clients that can be connected simultaneously 266 * @param inbandRingingEnabled whether in-band ringing is enabled on this AG 267 */ 268 @VisibleForTesting init(int maxHfClients, boolean inbandRingingEnabled)269 public void init(int maxHfClients, boolean inbandRingingEnabled) { 270 initializeNative(maxHfClients, inbandRingingEnabled); 271 } 272 273 /** Closes the interface */ 274 @VisibleForTesting cleanup()275 public void cleanup() { 276 cleanupNative(); 277 } 278 279 /** 280 * ok/error response 281 * 282 * @param device target device 283 * @param responseCode 0 - ERROR, 1 - OK 284 * @param errorCode error code in case of ERROR 285 * @return True on success, False on failure 286 */ 287 @VisibleForTesting atResponseCode(BluetoothDevice device, int responseCode, int errorCode)288 public boolean atResponseCode(BluetoothDevice device, int responseCode, int errorCode) { 289 return atResponseCodeNative(responseCode, errorCode, getByteAddress(device)); 290 } 291 292 /** 293 * Pre-formatted AT response, typically in response to unknown AT cmd 294 * 295 * @param device target device 296 * @param responseString formatted AT response string 297 * @return True on success, False on failure 298 */ 299 @VisibleForTesting atResponseString(BluetoothDevice device, String responseString)300 public boolean atResponseString(BluetoothDevice device, String responseString) { 301 return atResponseStringNative(responseString, getByteAddress(device)); 302 } 303 304 /** 305 * Connect to headset 306 * 307 * @param device target headset 308 * @return True on success, False on failure 309 */ 310 @VisibleForTesting connectHfp(BluetoothDevice device)311 public boolean connectHfp(BluetoothDevice device) { 312 return connectHfpNative(getByteAddress(device)); 313 } 314 315 /** 316 * Disconnect from headset 317 * 318 * @param device target headset 319 * @return True on success, False on failure 320 */ 321 @VisibleForTesting disconnectHfp(BluetoothDevice device)322 public boolean disconnectHfp(BluetoothDevice device) { 323 return disconnectHfpNative(getByteAddress(device)); 324 } 325 326 /** 327 * Connect HFP audio (SCO) to headset 328 * 329 * @param device target headset 330 * @return True on success, False on failure 331 */ 332 @VisibleForTesting connectAudio(BluetoothDevice device)333 public boolean connectAudio(BluetoothDevice device) { 334 return connectAudioNative(getByteAddress(device)); 335 } 336 337 /** 338 * Disconnect HFP audio (SCO) from to headset 339 * 340 * @param device target headset 341 * @return True on success, False on failure 342 */ 343 @VisibleForTesting disconnectAudio(BluetoothDevice device)344 public boolean disconnectAudio(BluetoothDevice device) { 345 return disconnectAudioNative(getByteAddress(device)); 346 } 347 348 /** 349 * Checks whether the device support echo cancellation and/or noise reduction via the AT+BRSF 350 * bitmask 351 * 352 * @param device target headset 353 * @return true if the device support echo cancellation or noise reduction, false otherwise 354 */ isNoiseReductionSupported(BluetoothDevice device)355 public boolean isNoiseReductionSupported(BluetoothDevice device) { 356 return isNoiseReductionSupportedNative(getByteAddress(device)); 357 } 358 359 /** 360 * Checks whether the device supports voice recognition via the AT+BRSF bitmask 361 * 362 * @param device target headset 363 * @return true if the device supports voice recognition, false otherwise 364 */ isVoiceRecognitionSupported(BluetoothDevice device)365 public boolean isVoiceRecognitionSupported(BluetoothDevice device) { 366 return isVoiceRecognitionSupportedNative(getByteAddress(device)); 367 } 368 369 /** 370 * Start voice recognition 371 * 372 * @param device target headset 373 * @return True on success, False on failure 374 */ 375 @VisibleForTesting startVoiceRecognition(BluetoothDevice device)376 public boolean startVoiceRecognition(BluetoothDevice device) { 377 return startVoiceRecognitionNative(getByteAddress(device)); 378 } 379 380 /** 381 * Stop voice recognition 382 * 383 * @param device target headset 384 * @return True on success, False on failure 385 */ 386 @VisibleForTesting stopVoiceRecognition(BluetoothDevice device)387 public boolean stopVoiceRecognition(BluetoothDevice device) { 388 return stopVoiceRecognitionNative(getByteAddress(device)); 389 } 390 391 /** 392 * Set HFP audio (SCO) volume 393 * 394 * @param device target headset 395 * @param volumeType type of volume 396 * @param volume value value 397 * @return True on success, False on failure 398 */ 399 @VisibleForTesting setVolume(BluetoothDevice device, int volumeType, int volume)400 public boolean setVolume(BluetoothDevice device, int volumeType, int volume) { 401 return setVolumeNative(volumeType, volume, getByteAddress(device)); 402 } 403 404 /** 405 * Response for CIND command 406 * 407 * @param device target device 408 * @param service service availability, 0 - no service, 1 - presence of service 409 * @param numActive number of active calls 410 * @param numHeld number of held calls 411 * @param callState overall call state [0-6] 412 * @param signal signal quality [0-5] 413 * @param roam roaming indicator, 0 - not roaming, 1 - roaming 414 * @param batteryCharge battery charge level [0-5] 415 * @return True on success, False on failure 416 */ 417 @VisibleForTesting cindResponse( BluetoothDevice device, int service, int numActive, int numHeld, int callState, int signal, int roam, int batteryCharge)418 public boolean cindResponse( 419 BluetoothDevice device, 420 int service, 421 int numActive, 422 int numHeld, 423 int callState, 424 int signal, 425 int roam, 426 int batteryCharge) { 427 return cindResponseNative( 428 service, 429 numActive, 430 numHeld, 431 callState, 432 signal, 433 roam, 434 batteryCharge, 435 getByteAddress(device)); 436 } 437 438 /** 439 * Combined device status change notification 440 * 441 * @param device target device 442 * @param deviceState device status object 443 * @return True on success, False on failure 444 */ 445 @VisibleForTesting notifyDeviceStatus(BluetoothDevice device, HeadsetDeviceState deviceState)446 public boolean notifyDeviceStatus(BluetoothDevice device, HeadsetDeviceState deviceState) { 447 return notifyDeviceStatusNative( 448 deviceState.mService, 449 deviceState.mRoam, 450 deviceState.mSignal, 451 deviceState.mBatteryCharge, 452 getByteAddress(device)); 453 } 454 455 /** 456 * Response for CLCC command. Can be iteratively called for each call index. Call index of 0 457 * will be treated as NULL termination (Completes response) 458 * 459 * @param device target device 460 * @param index index of the call given by the sequence of setting up or receiving the calls as 461 * seen by the served subscriber. Calls hold their number until they are released. New calls 462 * take the lowest available number. 463 * @param dir direction of the call, 0 (outgoing), 1 (incoming) 464 * @param status 0 = Active, 1 = Held, 2 = Dialing (outgoing calls only), 3 = Alerting (outgoing 465 * calls only), 4 = Incoming (incoming calls only), 5 = Waiting (incoming calls only), 6 = 466 * Call held by Response and Hold 467 * @param mode 0 (Voice), 1 (Data), 2 (FAX) 468 * @param mpty 0 - this call is NOT a member of a multi-party (conference) call, 1 - this call 469 * IS a member of a multi-party (conference) call 470 * @param number optional 471 * @param type optional 472 * @return True on success, False on failure 473 */ 474 @VisibleForTesting clccResponse( BluetoothDevice device, int index, int dir, int status, int mode, boolean mpty, String number, int type)475 public boolean clccResponse( 476 BluetoothDevice device, 477 int index, 478 int dir, 479 int status, 480 int mode, 481 boolean mpty, 482 String number, 483 int type) { 484 return clccResponseNative( 485 index, dir, status, mode, mpty, number, type, getByteAddress(device)); 486 } 487 488 /** 489 * Response for COPS command 490 * 491 * @param device target device 492 * @param operatorName operator name 493 * @return True on success, False on failure 494 */ 495 @VisibleForTesting copsResponse(BluetoothDevice device, String operatorName)496 public boolean copsResponse(BluetoothDevice device, String operatorName) { 497 return copsResponseNative(operatorName, getByteAddress(device)); 498 } 499 500 /** 501 * Notify of a call state change Each update notifies 1. Number of active/held/ringing calls 2. 502 * call_state: This denotes the state change that triggered this msg This will take one of the 503 * values from BtHfCallState 3. number & type: valid only for incoming & waiting call 504 * 505 * @param device target device for this update 506 * @param callState callstate structure 507 * @return True on success, False on failure 508 */ 509 @VisibleForTesting phoneStateChange(BluetoothDevice device, HeadsetCallState callState)510 public boolean phoneStateChange(BluetoothDevice device, HeadsetCallState callState) { 511 return phoneStateChangeNative( 512 callState.mNumActive, 513 callState.mNumHeld, 514 callState.mCallState, 515 callState.mNumber, 516 callState.mType, 517 callState.mName, 518 getByteAddress(device)); 519 } 520 521 /** 522 * Set whether we will initiate SCO or not 523 * 524 * @param value True to enable, False to disable 525 * @return True on success, False on failure 526 */ 527 @VisibleForTesting setScoAllowed(boolean value)528 public boolean setScoAllowed(boolean value) { 529 return setScoAllowedNative(value); 530 } 531 532 /** 533 * Enable or disable in-band ringing for the current service level connection through sending 534 * +BSIR AT command 535 * 536 * @param value True to enable, False to disable 537 * @return True on success, False on failure 538 */ 539 @VisibleForTesting sendBsir(BluetoothDevice device, boolean value)540 public boolean sendBsir(BluetoothDevice device, boolean value) { 541 return sendBsirNative(value, getByteAddress(device)); 542 } 543 544 /** 545 * Set the current active headset device for SCO audio 546 * 547 * @param device current active SCO device 548 * @return true on success 549 */ 550 @VisibleForTesting setActiveDevice(BluetoothDevice device)551 public boolean setActiveDevice(BluetoothDevice device) { 552 return setActiveDeviceNative(getByteAddress(device)); 553 } 554 555 /** 556 * Enable Super Wide Band 557 * 558 * @param swbCodec SWB Codec 559 * @param enable True to enable, False to disable 560 * @param device current active SCO device 561 * @return True on success, False on failure 562 */ 563 @VisibleForTesting enableSwb(int swbCodec, boolean enable, BluetoothDevice device)564 public boolean enableSwb(int swbCodec, boolean enable, BluetoothDevice device) { 565 return enableSwbNative(swbCodec, enable, getByteAddress(device)); 566 } 567 568 /* Native methods */ atResponseCodeNative(int responseCode, int errorCode, byte[] address)569 private native boolean atResponseCodeNative(int responseCode, int errorCode, byte[] address); 570 atResponseStringNative(String responseString, byte[] address)571 private native boolean atResponseStringNative(String responseString, byte[] address); 572 initializeNative(int maxHfClients, boolean inbandRingingEnabled)573 private native void initializeNative(int maxHfClients, boolean inbandRingingEnabled); 574 cleanupNative()575 private native void cleanupNative(); 576 connectHfpNative(byte[] address)577 private native boolean connectHfpNative(byte[] address); 578 disconnectHfpNative(byte[] address)579 private native boolean disconnectHfpNative(byte[] address); 580 connectAudioNative(byte[] address)581 private native boolean connectAudioNative(byte[] address); 582 disconnectAudioNative(byte[] address)583 private native boolean disconnectAudioNative(byte[] address); 584 isNoiseReductionSupportedNative(byte[] address)585 private native boolean isNoiseReductionSupportedNative(byte[] address); 586 isVoiceRecognitionSupportedNative(byte[] address)587 private native boolean isVoiceRecognitionSupportedNative(byte[] address); 588 startVoiceRecognitionNative(byte[] address)589 private native boolean startVoiceRecognitionNative(byte[] address); 590 stopVoiceRecognitionNative(byte[] address)591 private native boolean stopVoiceRecognitionNative(byte[] address); 592 setVolumeNative(int volumeType, int volume, byte[] address)593 private native boolean setVolumeNative(int volumeType, int volume, byte[] address); 594 cindResponseNative( int service, int numActive, int numHeld, int callState, int signal, int roam, int batteryCharge, byte[] address)595 private native boolean cindResponseNative( 596 int service, 597 int numActive, 598 int numHeld, 599 int callState, 600 int signal, 601 int roam, 602 int batteryCharge, 603 byte[] address); 604 notifyDeviceStatusNative( int networkState, int serviceType, int signal, int batteryCharge, byte[] address)605 private native boolean notifyDeviceStatusNative( 606 int networkState, int serviceType, int signal, int batteryCharge, byte[] address); 607 clccResponseNative( int index, int dir, int status, int mode, boolean mpty, String number, int type, byte[] address)608 private native boolean clccResponseNative( 609 int index, 610 int dir, 611 int status, 612 int mode, 613 boolean mpty, 614 String number, 615 int type, 616 byte[] address); 617 copsResponseNative(String operatorName, byte[] address)618 private native boolean copsResponseNative(String operatorName, byte[] address); 619 phoneStateChangeNative( int numActive, int numHeld, int callState, String number, int type, String name, byte[] address)620 private native boolean phoneStateChangeNative( 621 int numActive, 622 int numHeld, 623 int callState, 624 String number, 625 int type, 626 String name, 627 byte[] address); 628 setScoAllowedNative(boolean value)629 private native boolean setScoAllowedNative(boolean value); 630 sendBsirNative(boolean value, byte[] address)631 private native boolean sendBsirNative(boolean value, byte[] address); 632 setActiveDeviceNative(byte[] address)633 private native boolean setActiveDeviceNative(byte[] address); 634 enableSwbNative(int swbCodec, boolean enable, byte[] address)635 private native boolean enableSwbNative(int swbCodec, boolean enable, byte[] address); 636 } 637