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