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 /* 18 * Defines the native inteface that is used by state machine/service to either or receive messages 19 * from the native stack. This file is registered for the native methods in corresponding CPP file. 20 */ 21 package com.android.bluetooth.hfpclient; 22 23 import android.bluetooth.BluetoothDevice; 24 import android.util.Log; 25 26 import com.android.bluetooth.btservice.AdapterService; 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 33 * messages to/from the native stack. This file is registered for the native methods in 34 * corresponding CPP file. 35 */ 36 public class NativeInterface { 37 private static final String TAG = "NativeInterface"; 38 private static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG); 39 private AdapterService mAdapterService; 40 41 static { classInitNative()42 classInitNative(); 43 } 44 NativeInterface()45 private NativeInterface() { 46 mAdapterService = Objects.requireNonNull(AdapterService.getAdapterService(), 47 "AdapterService cannot be null when NativeInterface init"); 48 } 49 private static NativeInterface sInterface; 50 private static final Object INSTANCE_LOCK = new Object(); 51 52 /** 53 * This class is a singleton because native library should only be loaded once 54 * 55 * @return default instance 56 */ getInstance()57 public static NativeInterface getInstance() { 58 synchronized (INSTANCE_LOCK) { 59 if (sInterface == null) { 60 sInterface = new NativeInterface(); 61 } 62 } 63 return sInterface; 64 } 65 66 // Native wrappers to help unit testing 67 /** 68 * Initialize native stack 69 */ 70 @VisibleForTesting initialize()71 public void initialize() { 72 initializeNative(); 73 } 74 75 /** 76 * Close and clean up native stack 77 */ 78 @VisibleForTesting cleanup()79 public void cleanup() { 80 cleanupNative(); 81 } 82 83 /** 84 * Connect to the specified paired device 85 * 86 * @param device target device 87 * @return True on success, False on failure 88 */ 89 @VisibleForTesting connect(BluetoothDevice device)90 public boolean connect(BluetoothDevice device) { 91 return connectNative(getByteAddress(device)); 92 } 93 94 /** 95 * Disconnect from the specified paired device 96 * 97 * @param device target device 98 * @return True on success, False on failure 99 */ 100 @VisibleForTesting disconnect(BluetoothDevice device)101 public boolean disconnect(BluetoothDevice device) { 102 return disconnectNative(getByteAddress(device)); 103 } 104 105 /** 106 * Initiate audio connection to the specified paired device 107 * 108 * @param device target device 109 * @return True on success, False on failure 110 */ 111 @VisibleForTesting connectAudio(BluetoothDevice device)112 public boolean connectAudio(BluetoothDevice device) { 113 return connectAudioNative(getByteAddress(device)); 114 } 115 116 /** 117 * Close audio connection from the specified paired device 118 * 119 * @param device target device 120 * @return True on success, False on failure 121 */ disconnectAudio(BluetoothDevice device)122 public boolean disconnectAudio(BluetoothDevice device) { 123 return disconnectAudioNative(getByteAddress(device)); 124 } 125 126 /** 127 * Initiate voice recognition to the specified paired device 128 * 129 * @param device target device 130 * @return True on success, False on failure 131 */ 132 @VisibleForTesting startVoiceRecognition(BluetoothDevice device)133 public boolean startVoiceRecognition(BluetoothDevice device) { 134 return startVoiceRecognitionNative(getByteAddress(device)); 135 } 136 137 /** 138 * Close voice recognition to the specified paired device 139 * 140 * @param device target device 141 * @return True on success, False on failure 142 */ 143 @VisibleForTesting stopVoiceRecognition(BluetoothDevice device)144 public boolean stopVoiceRecognition(BluetoothDevice device) { 145 return stopVoiceRecognitionNative(getByteAddress(device)); 146 } 147 148 /** 149 * Set volume to the specified paired device 150 * 151 * @param device target device 152 * @param volumeType type of volume as in 153 * HeadsetClientHalConstants.VOLUME_TYPE_xxxx 154 * @param volume volume level 155 * @return True on success, False on failure 156 */ 157 @VisibleForTesting setVolume(BluetoothDevice device, int volumeType, int volume)158 public boolean setVolume(BluetoothDevice device, int volumeType, int volume) { 159 return setVolumeNative(getByteAddress(device), volumeType, volume); 160 } 161 162 /** 163 * dial number from the specified paired device 164 * 165 * @param device target device 166 * @param number phone number to be dialed 167 * @return True on success, False on failure 168 */ 169 @VisibleForTesting dial(BluetoothDevice device, String number)170 public boolean dial(BluetoothDevice device, String number) { 171 return dialNative(getByteAddress(device), number); 172 } 173 174 /** 175 * Memory dialing from the specified paired device 176 * 177 * @param device target device 178 * @param location memory location 179 * @return True on success, False on failure 180 */ 181 @VisibleForTesting dialMemory(BluetoothDevice device, int location)182 public boolean dialMemory(BluetoothDevice device, int location) { 183 return dialMemoryNative(getByteAddress(device), location); 184 } 185 186 /** 187 * Apply action to call 188 * 189 * @param device target device 190 * @param action action (e.g. hold, terminate etc) 191 * @param index call index 192 * @return True on success, False on failure 193 */ 194 @VisibleForTesting handleCallAction(BluetoothDevice device, int action, int index)195 public boolean handleCallAction(BluetoothDevice device, int action, int index) { 196 return handleCallActionNative(getByteAddress(device), action, index); 197 } 198 199 /** 200 * Query current call status from the specified paired device 201 * 202 * @param device target device 203 * @return True on success, False on failure 204 */ 205 @VisibleForTesting queryCurrentCalls(BluetoothDevice device)206 public boolean queryCurrentCalls(BluetoothDevice device) { 207 return queryCurrentCallsNative(getByteAddress(device)); 208 } 209 210 /** 211 * Query operator name from the specified paired device 212 * 213 * @param device target device 214 * @return True on success, False on failure 215 */ 216 @VisibleForTesting queryCurrentOperatorName(BluetoothDevice device)217 public boolean queryCurrentOperatorName(BluetoothDevice device) { 218 return queryCurrentOperatorNameNative(getByteAddress(device)); 219 } 220 221 /** 222 * Retrieve subscriber number from the specified paired device 223 * 224 * @param device target device 225 * @return True on success, False on failure 226 */ 227 @VisibleForTesting retrieveSubscriberInfo(BluetoothDevice device)228 public boolean retrieveSubscriberInfo(BluetoothDevice device) { 229 return retrieveSubscriberInfoNative(getByteAddress(device)); 230 } 231 232 /** 233 * Transmit DTMF code 234 * 235 * @param device target device 236 * @param code DTMF code 237 * @return True on success, False on failure 238 */ 239 @VisibleForTesting sendDtmf(BluetoothDevice device, byte code)240 public boolean sendDtmf(BluetoothDevice device, byte code) { 241 return sendDtmfNative(getByteAddress(device), code); 242 } 243 244 /** 245 * Request last voice tag 246 * 247 * @param device target device 248 * @return True on success, False on failure 249 */ 250 @VisibleForTesting requestLastVoiceTagNumber(BluetoothDevice device)251 public boolean requestLastVoiceTagNumber(BluetoothDevice device) { 252 return requestLastVoiceTagNumberNative(getByteAddress(device)); 253 } 254 255 /** 256 * Send an AT command 257 * 258 * @param device target device 259 * @param atCmd command code 260 * @param val1 command specific argurment1 261 * @param val2 command specific argurment2 262 * @param arg other command specific argurments 263 * @return True on success, False on failure 264 */ 265 @VisibleForTesting sendATCmd(BluetoothDevice device, int atCmd, int val1, int val2, String arg)266 public boolean sendATCmd(BluetoothDevice device, int atCmd, int val1, int val2, String arg) { 267 return sendATCmdNative(getByteAddress(device), atCmd, val1, val2, arg); 268 } 269 270 /** 271 * Set call audio policy to the specified paired device 272 * 273 * @param cmd Android specific command string 274 * @return True on success, False on failure 275 */ 276 @VisibleForTesting sendAndroidAt(BluetoothDevice device, String cmd)277 public boolean sendAndroidAt(BluetoothDevice device, String cmd) { 278 if (device == null) { 279 Log.w(TAG, "Don't need to send " + cmd + " because no remote device"); 280 return false; 281 } 282 return sendAndroidAtNative(getByteAddress(device), cmd); 283 } 284 285 // Native methods that call into the JNI interface classInitNative()286 private static native void classInitNative(); 287 initializeNative()288 private native void initializeNative(); 289 cleanupNative()290 private native void cleanupNative(); 291 connectNative(byte[] address)292 private static native boolean connectNative(byte[] address); 293 disconnectNative(byte[] address)294 private static native boolean disconnectNative(byte[] address); 295 connectAudioNative(byte[] address)296 private static native boolean connectAudioNative(byte[] address); 297 disconnectAudioNative(byte[] address)298 private static native boolean disconnectAudioNative(byte[] address); 299 startVoiceRecognitionNative(byte[] address)300 private static native boolean startVoiceRecognitionNative(byte[] address); 301 stopVoiceRecognitionNative(byte[] address)302 private static native boolean stopVoiceRecognitionNative(byte[] address); 303 setVolumeNative(byte[] address, int volumeType, int volume)304 private static native boolean setVolumeNative(byte[] address, int volumeType, int volume); 305 dialNative(byte[] address, String number)306 private static native boolean dialNative(byte[] address, String number); 307 dialMemoryNative(byte[] address, int location)308 private static native boolean dialMemoryNative(byte[] address, int location); 309 handleCallActionNative(byte[] address, int action, int index)310 private static native boolean handleCallActionNative(byte[] address, int action, int index); 311 queryCurrentCallsNative(byte[] address)312 private static native boolean queryCurrentCallsNative(byte[] address); 313 queryCurrentOperatorNameNative(byte[] address)314 private static native boolean queryCurrentOperatorNameNative(byte[] address); 315 retrieveSubscriberInfoNative(byte[] address)316 private static native boolean retrieveSubscriberInfoNative(byte[] address); 317 sendDtmfNative(byte[] address, byte code)318 private static native boolean sendDtmfNative(byte[] address, byte code); 319 requestLastVoiceTagNumberNative(byte[] address)320 private static native boolean requestLastVoiceTagNumberNative(byte[] address); 321 sendATCmdNative(byte[] address, int atCmd, int val1, int val2, String arg)322 private static native boolean sendATCmdNative(byte[] address, int atCmd, int val1, int val2, 323 String arg); 324 sendAndroidAtNative(byte[] address, String cmd)325 private static native boolean sendAndroidAtNative(byte[] address, String cmd); 326 getDevice(byte[] address)327 private BluetoothDevice getDevice(byte[] address) { 328 return mAdapterService.getDeviceFromByte(address); 329 } 330 getByteAddress(BluetoothDevice device)331 private byte[] getByteAddress(BluetoothDevice device) { 332 return mAdapterService.getByteIdentityAddress(device); 333 } 334 335 // Callbacks from the native back into the java framework. All callbacks are routed via the 336 // Service which will disambiguate which state machine the message should be routed through. 337 @VisibleForTesting onConnectionStateChanged(int state, int peerFeat, int chldFeat, byte[] address)338 void onConnectionStateChanged(int state, int peerFeat, int chldFeat, byte[] address) { 339 StackEvent event = new StackEvent(StackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED); 340 event.valueInt = state; 341 event.valueInt2 = peerFeat; 342 event.valueInt3 = chldFeat; 343 event.device = getDevice(address); 344 // BluetoothAdapter.getDefaultAdapter().getRemoteDevice(Utils.getAddressStringFromByte 345 // (address)); 346 if (DBG) { 347 Log.d(TAG, "Device addr " + event.device + " State " + state); 348 } 349 HeadsetClientService service = HeadsetClientService.getHeadsetClientService(); 350 if (service != null) { 351 service.messageFromNative(event); 352 } else { 353 Log.w(TAG, "Ignoring message because service not available: " + event); 354 } 355 } 356 357 @VisibleForTesting onAudioStateChanged(int state, byte[] address)358 void onAudioStateChanged(int state, byte[] address) { 359 StackEvent event = new StackEvent(StackEvent.EVENT_TYPE_AUDIO_STATE_CHANGED); 360 event.valueInt = state; 361 event.device = getDevice(address); 362 if (DBG) { 363 Log.d(TAG, "onAudioStateChanged: event " + event); 364 } 365 HeadsetClientService service = HeadsetClientService.getHeadsetClientService(); 366 if (service != null) { 367 service.messageFromNative(event); 368 } else { 369 Log.w(TAG, "onAudioStateChanged: Ignoring message because service not available: " 370 + event); 371 } 372 } 373 374 @VisibleForTesting onVrStateChanged(int state, byte[] address)375 void onVrStateChanged(int state, byte[] address) { 376 StackEvent event = new StackEvent(StackEvent.EVENT_TYPE_VR_STATE_CHANGED); 377 event.valueInt = state; 378 event.device = getDevice(address); 379 if (DBG) { 380 Log.d(TAG, "onVrStateChanged: event " + event); 381 } 382 383 HeadsetClientService service = HeadsetClientService.getHeadsetClientService(); 384 if (service != null) { 385 service.messageFromNative(event); 386 } else { 387 Log.w(TAG, 388 "onVrStateChanged: Ignoring message because service not available: " + event); 389 } 390 } 391 392 @VisibleForTesting onNetworkState(int state, byte[] address)393 void onNetworkState(int state, byte[] address) { 394 StackEvent event = new StackEvent(StackEvent.EVENT_TYPE_NETWORK_STATE); 395 event.valueInt = state; 396 event.device = getDevice(address); 397 if (DBG) { 398 Log.d(TAG, "onNetworkStateChanged: event " + event); 399 } 400 401 HeadsetClientService service = HeadsetClientService.getHeadsetClientService(); 402 if (service != null) { 403 service.messageFromNative(event); 404 } else { 405 Log.w(TAG, 406 "onNetworkStateChanged: Ignoring message because service not available: " 407 + event); 408 } 409 } 410 411 @VisibleForTesting onNetworkRoaming(int state, byte[] address)412 void onNetworkRoaming(int state, byte[] address) { 413 StackEvent event = new StackEvent(StackEvent.EVENT_TYPE_ROAMING_STATE); 414 event.valueInt = state; 415 event.device = getDevice(address); 416 if (DBG) { 417 Log.d(TAG, "onNetworkRoaming: incoming: " + event); 418 } 419 HeadsetClientService service = HeadsetClientService.getHeadsetClientService(); 420 if (service != null) { 421 service.messageFromNative(event); 422 } else { 423 Log.w(TAG, 424 "onNetworkRoaming: Ignoring message because service not available: " + event); 425 } 426 } 427 428 @VisibleForTesting onNetworkSignal(int signal, byte[] address)429 void onNetworkSignal(int signal, byte[] address) { 430 StackEvent event = new StackEvent(StackEvent.EVENT_TYPE_NETWORK_SIGNAL); 431 event.valueInt = signal; 432 event.device = getDevice(address); 433 if (DBG) { 434 Log.d(TAG, "onNetworkSignal: event " + event); 435 } 436 HeadsetClientService service = HeadsetClientService.getHeadsetClientService(); 437 if (service != null) { 438 service.messageFromNative(event); 439 } else { 440 Log.w(TAG, "onNetworkSignal: Ignoring message because service not available: " + event); 441 } 442 } 443 444 @VisibleForTesting onBatteryLevel(int level, byte[] address)445 void onBatteryLevel(int level, byte[] address) { 446 StackEvent event = new StackEvent(StackEvent.EVENT_TYPE_BATTERY_LEVEL); 447 event.valueInt = level; 448 event.device = getDevice(address); 449 if (DBG) { 450 Log.d(TAG, "onBatteryLevel: event " + event); 451 } 452 HeadsetClientService service = HeadsetClientService.getHeadsetClientService(); 453 if (service != null) { 454 service.messageFromNative(event); 455 } else { 456 Log.w(TAG, "onBatteryLevel: Ignoring message because service not available: " + event); 457 } 458 } 459 460 @VisibleForTesting onCurrentOperator(String name, byte[] address)461 void onCurrentOperator(String name, byte[] address) { 462 StackEvent event = new StackEvent(StackEvent.EVENT_TYPE_OPERATOR_NAME); 463 event.valueString = name; 464 event.device = getDevice(address); 465 if (DBG) { 466 Log.d(TAG, "onCurrentOperator: event " + event); 467 } 468 HeadsetClientService service = HeadsetClientService.getHeadsetClientService(); 469 if (service != null) { 470 service.messageFromNative(event); 471 } else { 472 Log.w(TAG, 473 "onCurrentOperator: Ignoring message because service not available: " + event); 474 } 475 } 476 477 @VisibleForTesting onCall(int call, byte[] address)478 void onCall(int call, byte[] address) { 479 StackEvent event = new StackEvent(StackEvent.EVENT_TYPE_CALL); 480 event.valueInt = call; 481 event.device = getDevice(address); 482 if (DBG) { 483 Log.d(TAG, "onCall: event " + event); 484 } 485 HeadsetClientService service = HeadsetClientService.getHeadsetClientService(); 486 if (service != null) { 487 service.messageFromNative(event); 488 } else { 489 Log.w(TAG, "onCall: Ignoring message because service not available: " + event); 490 } 491 } 492 493 /** 494 * CIEV (Call indicators) notifying if call(s) are getting set up. 495 * 496 * Values include: 497 * 0 - No current call is in setup 498 * 1 - Incoming call process ongoing 499 * 2 - Outgoing call process ongoing 500 * 3 - Remote party being alerted for outgoing call 501 */ 502 @VisibleForTesting onCallSetup(int callsetup, byte[] address)503 void onCallSetup(int callsetup, byte[] address) { 504 StackEvent event = new StackEvent(StackEvent.EVENT_TYPE_CALLSETUP); 505 event.valueInt = callsetup; 506 event.device = getDevice(address); 507 if (DBG) { 508 Log.d(TAG, "onCallSetup: device" + event.device); 509 Log.d(TAG, "onCallSetup: event " + event); 510 } 511 HeadsetClientService service = HeadsetClientService.getHeadsetClientService(); 512 if (service != null) { 513 service.messageFromNative(event); 514 } else { 515 Log.w(TAG, "onCallSetup: Ignoring message because service not available: " + event); 516 } 517 } 518 519 /** 520 * CIEV (Call indicators) notifying call held states. 521 * 522 * Values include: 523 * 0 - No calls held 524 * 1 - Call is placed on hold or active/held calls wapped (The AG has both an ACTIVE and HELD 525 * call) 526 * 2 - Call on hold, no active call 527 */ 528 @VisibleForTesting onCallHeld(int callheld, byte[] address)529 void onCallHeld(int callheld, byte[] address) { 530 StackEvent event = new StackEvent(StackEvent.EVENT_TYPE_CALLHELD); 531 event.valueInt = callheld; 532 event.device = getDevice(address); 533 if (DBG) { 534 Log.d(TAG, "onCallHeld: event " + event); 535 } 536 HeadsetClientService service = HeadsetClientService.getHeadsetClientService(); 537 if (service != null) { 538 service.messageFromNative(event); 539 } else { 540 Log.w(TAG, "onCallHeld: Ignoring message because service not available: " + event); 541 } 542 } 543 544 @VisibleForTesting onRespAndHold(int respAndHold, byte[] address)545 void onRespAndHold(int respAndHold, byte[] address) { 546 StackEvent event = new StackEvent(StackEvent.EVENT_TYPE_RESP_AND_HOLD); 547 event.valueInt = respAndHold; 548 event.device = getDevice(address); 549 if (DBG) { 550 Log.d(TAG, "onRespAndHold: event " + event); 551 } 552 HeadsetClientService service = HeadsetClientService.getHeadsetClientService(); 553 if (service != null) { 554 service.messageFromNative(event); 555 } else { 556 Log.w(TAG, "onRespAndHold: Ignoring message because service not available: " + event); 557 } 558 } 559 560 @VisibleForTesting onClip(String number, byte[] address)561 void onClip(String number, byte[] address) { 562 StackEvent event = new StackEvent(StackEvent.EVENT_TYPE_CLIP); 563 event.valueString = number; 564 event.device = getDevice(address); 565 if (DBG) { 566 Log.d(TAG, "onClip: event " + event); 567 } 568 HeadsetClientService service = HeadsetClientService.getHeadsetClientService(); 569 if (service != null) { 570 service.messageFromNative(event); 571 } else { 572 Log.w(TAG, "onClip: Ignoring message because service not available: " + event); 573 } 574 } 575 576 @VisibleForTesting onCallWaiting(String number, byte[] address)577 void onCallWaiting(String number, byte[] address) { 578 StackEvent event = new StackEvent(StackEvent.EVENT_TYPE_CALL_WAITING); 579 event.valueString = number; 580 event.device = getDevice(address); 581 if (DBG) { 582 Log.d(TAG, "onCallWaiting: event " + event); 583 } 584 HeadsetClientService service = HeadsetClientService.getHeadsetClientService(); 585 if (service != null) { 586 service.messageFromNative(event); 587 } else { 588 Log.w(TAG, "onCallWaiting: Ignoring message because service not available: " + event); 589 } 590 } 591 592 @VisibleForTesting onCurrentCalls(int index, int dir, int state, int mparty, String number, byte[] address)593 void onCurrentCalls(int index, int dir, int state, int mparty, String number, 594 byte[] address) { 595 StackEvent event = new StackEvent(StackEvent.EVENT_TYPE_CURRENT_CALLS); 596 event.valueInt = index; 597 event.valueInt2 = dir; 598 event.valueInt3 = state; 599 event.valueInt4 = mparty; 600 event.valueString = number; 601 event.device = getDevice(address); 602 if (DBG) { 603 Log.d(TAG, "onCurrentCalls: event " + event); 604 } 605 HeadsetClientService service = HeadsetClientService.getHeadsetClientService(); 606 if (service != null) { 607 service.messageFromNative(event); 608 } else { 609 Log.w(TAG, "onCurrentCalls: Ignoring message because service not available: " + event); 610 } 611 } 612 613 @VisibleForTesting onVolumeChange(int type, int volume, byte[] address)614 void onVolumeChange(int type, int volume, byte[] address) { 615 StackEvent event = new StackEvent(StackEvent.EVENT_TYPE_VOLUME_CHANGED); 616 event.valueInt = type; 617 event.valueInt2 = volume; 618 event.device = getDevice(address); 619 if (DBG) { 620 Log.d(TAG, "onVolumeChange: event " + event); 621 } 622 HeadsetClientService service = HeadsetClientService.getHeadsetClientService(); 623 if (service != null) { 624 service.messageFromNative(event); 625 } else { 626 Log.w(TAG, "onVolumeChange: Ignoring message because service not available: " + event); 627 } 628 } 629 630 @VisibleForTesting onCmdResult(int type, int cme, byte[] address)631 void onCmdResult(int type, int cme, byte[] address) { 632 StackEvent event = new StackEvent(StackEvent.EVENT_TYPE_CMD_RESULT); 633 event.valueInt = type; 634 event.valueInt2 = cme; 635 event.device = getDevice(address); 636 if (DBG) { 637 Log.d(TAG, "onCmdResult: event " + event); 638 } 639 HeadsetClientService service = HeadsetClientService.getHeadsetClientService(); 640 if (service != null) { 641 service.messageFromNative(event); 642 } else { 643 Log.w(TAG, "onCmdResult: Ignoring message because service not available: " + event); 644 } 645 } 646 647 @VisibleForTesting onSubscriberInfo(String number, int type, byte[] address)648 void onSubscriberInfo(String number, int type, byte[] address) { 649 StackEvent event = new StackEvent(StackEvent.EVENT_TYPE_SUBSCRIBER_INFO); 650 event.valueInt = type; 651 event.valueString = number; 652 event.device = getDevice(address); 653 if (DBG) { 654 Log.d(TAG, "onSubscriberInfo: event " + event); 655 } 656 HeadsetClientService service = HeadsetClientService.getHeadsetClientService(); 657 if (service != null) { 658 service.messageFromNative(event); 659 } else { 660 Log.w(TAG, 661 "onSubscriberInfo: Ignoring message because service not available: " + event); 662 } 663 } 664 665 @VisibleForTesting onInBandRing(int inBand, byte[] address)666 void onInBandRing(int inBand, byte[] address) { 667 StackEvent event = new StackEvent(StackEvent.EVENT_TYPE_IN_BAND_RINGTONE); 668 event.valueInt = inBand; 669 event.device = getDevice(address); 670 if (DBG) { 671 Log.d(TAG, "onInBandRing: event " + event); 672 } 673 HeadsetClientService service = HeadsetClientService.getHeadsetClientService(); 674 if (service != null) { 675 service.messageFromNative(event); 676 } else { 677 Log.w(TAG, 678 "onInBandRing: Ignoring message because service not available: " + event); 679 } 680 } 681 682 @VisibleForTesting onLastVoiceTagNumber(String number, byte[] address)683 void onLastVoiceTagNumber(String number, byte[] address) { 684 Log.w(TAG, "onLastVoiceTagNumber not supported"); 685 } 686 687 @VisibleForTesting onRingIndication(byte[] address)688 void onRingIndication(byte[] address) { 689 StackEvent event = new StackEvent(StackEvent.EVENT_TYPE_RING_INDICATION); 690 event.device = getDevice(address); 691 if (DBG) { 692 Log.d(TAG, "onRingIndication: event " + event); 693 } 694 HeadsetClientService service = HeadsetClientService.getHeadsetClientService(); 695 if (service != null) { 696 service.messageFromNative(event); 697 } else { 698 Log.w(TAG, 699 "onRingIndication: Ignoring message because service not available: " + event); 700 } 701 } 702 703 @VisibleForTesting onUnknownEvent(String eventString, byte[] address)704 void onUnknownEvent(String eventString, byte[] address) { 705 StackEvent event = new StackEvent(StackEvent.EVENT_TYPE_UNKNOWN_EVENT); 706 event.device = getDevice(address); 707 event.valueString = eventString; 708 if (DBG) { 709 Log.d(TAG, "onUnknownEvent: event " + event); 710 } 711 HeadsetClientService service = HeadsetClientService.getHeadsetClientService(); 712 if (service != null) { 713 service.messageFromNative(event); 714 } else { 715 Log.w(TAG, 716 "onUnknowEvent: Ignoring message because service not available: " + event); 717 } 718 } 719 720 } 721