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