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