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