• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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