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 com.android.bluetooth.Utils;
24 
25 import android.bluetooth.BluetoothAdapter;
26 import android.bluetooth.BluetoothDevice;
27 import android.util.Log;
28 
29 class NativeInterface {
30     private static String TAG = "NativeInterface";
31     private static boolean DBG = false;
32 
NativeInterface()33     NativeInterface() {}
34 
35     // Native methods that call into the JNI interface
classInitNative()36     static native void classInitNative();
initializeNative()37     static native void initializeNative();
cleanupNative()38     static native void cleanupNative();
connectNative(byte[] address)39     static native boolean connectNative(byte[] address);
disconnectNative(byte[] address)40     static native boolean disconnectNative(byte[] address);
connectAudioNative(byte[] address)41     static native boolean connectAudioNative(byte[] address);
disconnectAudioNative(byte[] address)42     static native boolean disconnectAudioNative(byte[] address);
startVoiceRecognitionNative(byte[] address)43     static native boolean startVoiceRecognitionNative(byte[] address);
stopVoiceRecognitionNative(byte[] address)44     static native boolean stopVoiceRecognitionNative(byte[] address);
setVolumeNative(byte[] address, int volumeType, int volume)45     static native boolean setVolumeNative(byte[] address, int volumeType, int volume);
dialNative(byte[] address, String number)46     static native boolean dialNative(byte[] address, String number);
dialMemoryNative(byte[] address, int location)47     static native boolean dialMemoryNative(byte[] address, int location);
handleCallActionNative(byte[] address, int action, int index)48     static native boolean handleCallActionNative(byte[] address, int action, int index);
queryCurrentCallsNative(byte[] address)49     static native boolean queryCurrentCallsNative(byte[] address);
queryCurrentOperatorNameNative(byte[] address)50     static native boolean queryCurrentOperatorNameNative(byte[] address);
retrieveSubscriberInfoNative(byte[] address)51     static native boolean retrieveSubscriberInfoNative(byte[] address);
sendDtmfNative(byte[] address, byte code)52     static native boolean sendDtmfNative(byte[] address, byte code);
requestLastVoiceTagNumberNative(byte[] address)53     static native boolean requestLastVoiceTagNumberNative(byte[] address);
sendATCmdNative(byte[] address, int atCmd, int val1, int val2, String arg)54     static native boolean sendATCmdNative(byte[] address, int atCmd, int val1,
55             int val2, String arg);
56 
getDevice(byte[] address)57     private BluetoothDevice getDevice(byte[] address) {
58         return BluetoothAdapter.getDefaultAdapter().getRemoteDevice(address);
59     }
60 
61     // Callbacks from the native back into the java framework. All callbacks are routed via the
62     // Service which will disambiguate which state machine the message should be routed through.
onConnectionStateChanged(int state, int peer_feat, int chld_feat, byte[] address)63     private void onConnectionStateChanged(int state, int peer_feat, int chld_feat, byte[] address) {
64         StackEvent event = new StackEvent(StackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED);
65         event.valueInt = state;
66         event.valueInt2 = peer_feat;
67         event.valueInt3 = chld_feat;
68         event.device = getDevice(address);
69         // BluetoothAdapter.getDefaultAdapter().getRemoteDevice(Utils.getAddressStringFromByte(address));
70         if (DBG) {
71             Log.d(TAG, "Device addr "  + event.device.getAddress() + " State " + state);
72         }
73         HeadsetClientService service = HeadsetClientService.getHeadsetClientService();
74         if (service != null) {
75             service.messageFromNative(event);
76         } else {
77             Log.w(TAG, "Ignoring message because service not available: " + event);
78         }
79     }
80 
onAudioStateChanged(int state, byte[] address)81     private void onAudioStateChanged(int state, byte[] address) {
82         StackEvent event = new StackEvent(StackEvent.EVENT_TYPE_AUDIO_STATE_CHANGED);
83         event.valueInt = state;
84         event.device = getDevice(address);
85         if (DBG) {
86             Log.d(TAG, "onAudioStateChanged: address " + address + " event "  + event);
87         }
88         HeadsetClientService service = HeadsetClientService.getHeadsetClientService();
89         if (service != null) {
90             service.messageFromNative(event);
91         } else {
92             Log.w(TAG, "onAudioStateChanged: Ignoring message because service not available: " + event);
93         }
94     }
95 
onVrStateChanged(int state)96     private void onVrStateChanged(int state) {
97         Log.w(TAG, "onVrStateChanged not supported");
98     }
99 
onNetworkState(int state, byte[] address)100     private void onNetworkState(int state, byte[] address) {
101         StackEvent event = new StackEvent(StackEvent.EVENT_TYPE_NETWORK_STATE);
102         event.valueInt = state;
103         event.device = getDevice(address);
104         if (DBG) {
105             Log.d(TAG, "onVrStateChanged: address " + address + " event "  + event);
106         }
107 
108         HeadsetClientService service = HeadsetClientService.getHeadsetClientService();
109         if (service != null) {
110             service.messageFromNative(event);
111         } else {
112             Log.w(TAG, "onVrStateChanged: Ignoring message because service not available: " + event);
113         }
114     }
115 
onNetworkRoaming(int state, byte[] address)116     private void onNetworkRoaming(int state, byte[] address) {
117         StackEvent event = new StackEvent(StackEvent.EVENT_TYPE_ROAMING_STATE);
118         event.valueInt = state;
119         event.device = getDevice(address);
120         if (DBG) {
121             Log.d(TAG, "onNetworkRoaming: incoming: " + event);
122         }
123         HeadsetClientService service = HeadsetClientService.getHeadsetClientService();
124         if (service != null) {
125             service.messageFromNative(event);
126         } else {
127             Log.w(TAG, "onNetworkRoaming: Ignoring message because service not available: " + event);
128         }
129     }
130 
onNetworkSignal(int signal, byte[] address)131     private void onNetworkSignal(int signal, byte[] address) {
132         StackEvent event = new StackEvent(StackEvent.EVENT_TYPE_NETWORK_SIGNAL);
133         event.valueInt = signal;
134         event.device = getDevice(address);
135         if (DBG) {
136             Log.d(TAG, "onNetworkSignal: address " + address + " event "  + event);
137         }
138         HeadsetClientService service = HeadsetClientService.getHeadsetClientService();
139         if (service != null) {
140             service.messageFromNative(event);
141         } else {
142             Log.w(TAG, "onNetworkSignal: Ignoring message because service not available: " + event);
143         }
144     }
145 
onBatteryLevel(int level, byte[] address)146     private void onBatteryLevel(int level, byte[] address) {
147         StackEvent event = new StackEvent(StackEvent.EVENT_TYPE_BATTERY_LEVEL);
148         event.valueInt = level;
149         event.device = getDevice(address);
150         if (DBG) {
151             Log.d(TAG, "onBatteryLevel: address " + address + " event "  + event);
152         }
153         HeadsetClientService service = HeadsetClientService.getHeadsetClientService();
154         if (service != null) {
155             service.messageFromNative(event);
156         } else {
157             Log.w(TAG, "onBatteryLevel: Ignoring message because service not available: " + event);
158         }
159     }
160 
onCurrentOperator(String name, byte[] address)161     private void onCurrentOperator(String name, byte[] address) {
162         StackEvent event = new StackEvent(StackEvent.EVENT_TYPE_OPERATOR_NAME);
163         event.valueString = name;
164         event.device = getDevice(address);
165         if (DBG) {
166             Log.d(TAG, "onCurrentOperator: address " + address + " event "  + event);
167         }
168         HeadsetClientService service = HeadsetClientService.getHeadsetClientService();
169         if (service != null) {
170             service.messageFromNative(event);
171         } else {
172             Log.w(TAG, "onCurrentOperator: Ignoring message because service not available: " + event);
173         }
174     }
175 
onCall(int call, byte[] address)176     private void onCall(int call, byte[] address) {
177         StackEvent event = new StackEvent(StackEvent.EVENT_TYPE_CALL);
178         event.valueInt = call;
179         event.device = getDevice(address);
180         if (DBG) {
181             Log.d(TAG, "onCall: address " + address + " event "  + event);
182         }
183         HeadsetClientService service = HeadsetClientService.getHeadsetClientService();
184         if (service != null) {
185             service.messageFromNative(event);
186         } else {
187             Log.w(TAG, "onCall: Ignoring message because service not available: " + event);
188         }
189     }
190 
191     /**
192      * CIEV (Call indicators) notifying if call(s) are getting set up.
193      *
194      * Values include:
195      * 0 - No current call is in setup
196      * 1 - Incoming call process ongoing
197      * 2 - Outgoing call process ongoing
198      * 3 - Remote party being alerted for outgoing call
199      */
onCallSetup(int callsetup, byte[] address)200     private void onCallSetup(int callsetup, byte[] address) {
201         StackEvent event = new StackEvent(StackEvent.EVENT_TYPE_CALLSETUP);
202         event.valueInt = callsetup;
203         event.device = getDevice(address);
204         if (DBG) {
205             Log.d(TAG, "onCallSetup: addr " + address + " device" + event.device);
206             Log.d(TAG, "onCallSetup: address " + address + " event "  + event);
207         }
208         HeadsetClientService service = HeadsetClientService.getHeadsetClientService();
209         if (service != null) {
210             service.messageFromNative(event);
211         } else {
212             Log.w(TAG, "onCallSetup: Ignoring message because service not available: " + event);
213         }
214     }
215 
216     /**
217      * CIEV (Call indicators) notifying call held states.
218      *
219      * Values include:
220      * 0 - No calls held
221      * 1 - Call is placed on hold or active/held calls wapped (The AG has both an ACTIVE and HELD
222      * call)
223      * 2 - Call on hold, no active call
224      */
onCallHeld(int callheld, byte[] address)225     private void onCallHeld(int callheld, byte[] address) {
226         StackEvent event = new StackEvent(StackEvent.EVENT_TYPE_CALLHELD);
227         event.valueInt = callheld;
228         event.device = getDevice(address);
229         if (DBG) {
230             Log.d(TAG, "onCallHeld: address " + address + " event "  + event);
231         }
232         HeadsetClientService service = HeadsetClientService.getHeadsetClientService();
233         if (service != null) {
234             service.messageFromNative(event);
235         } else {
236             Log.w(TAG, "onCallHeld: Ignoring message because service not available: " + event);
237         }
238     }
239 
onRespAndHold(int resp_and_hold, byte[] address)240     private void onRespAndHold(int resp_and_hold, byte[] address) {
241         StackEvent event = new StackEvent(StackEvent.EVENT_TYPE_RESP_AND_HOLD);
242         event.valueInt = resp_and_hold;
243         event.device = getDevice(address);
244         if (DBG) {
245             Log.d(TAG, "onRespAndHold: address " + address + " event "  + event);
246         }
247         HeadsetClientService service = HeadsetClientService.getHeadsetClientService();
248         if (service != null) {
249             service.messageFromNative(event);
250         } else {
251             Log.w(TAG, "onRespAndHold: Ignoring message because service not available: " + event);
252         }
253     }
254 
onClip(String number, byte[] address)255     private void onClip(String number, byte[] address) {
256         StackEvent event = new StackEvent(StackEvent.EVENT_TYPE_CLIP);
257         event.valueString = number;
258         event.device = getDevice(address);
259         if (DBG) {
260             Log.d(TAG, "onClip: address " + address + " event "  + event);
261         }
262         HeadsetClientService service = HeadsetClientService.getHeadsetClientService();
263         if (service != null) {
264             service.messageFromNative(event);
265         } else {
266             Log.w(TAG, "onClip: Ignoring message because service not available: " + event);
267         }
268     }
269 
onCallWaiting(String number, byte[] address)270     private void onCallWaiting(String number, byte[] address) {
271         StackEvent event = new StackEvent(StackEvent.EVENT_TYPE_CALL_WAITING);
272         event.valueString = number;
273         event.device = getDevice(address);
274         if (DBG) {
275             Log.d(TAG, "onCallWaiting: address " + address + " event "  + event);
276         }
277         HeadsetClientService service = HeadsetClientService.getHeadsetClientService();
278         if (service != null) {
279             service.messageFromNative(event);
280         } else {
281             Log.w(TAG, "onCallWaiting: Ignoring message because service not available: " + event);
282         }
283     }
284 
onCurrentCalls( int index, int dir, int state, int mparty, String number, byte[] address)285     private void onCurrentCalls(
286             int index, int dir, int state, int mparty, String number, byte[] address) {
287         StackEvent event = new StackEvent(StackEvent.EVENT_TYPE_CURRENT_CALLS);
288         event.valueInt = index;
289         event.valueInt2 = dir;
290         event.valueInt3 = state;
291         event.valueInt4 = mparty;
292         event.valueString = number;
293         event.device = getDevice(address);
294         if (DBG) {
295             Log.d(TAG, "onCurrentCalls: address " + address + " event "  + event);
296         }
297         HeadsetClientService service = HeadsetClientService.getHeadsetClientService();
298         if (service != null) {
299             service.messageFromNative(event);
300         } else {
301             Log.w(TAG, "onCurrentCalls: Ignoring message because service not available: " + event);
302         }
303     }
304 
onVolumeChange(int type, int volume, byte[] address)305     private void onVolumeChange(int type, int volume, byte[] address) {
306         StackEvent event = new StackEvent(StackEvent.EVENT_TYPE_VOLUME_CHANGED);
307         event.valueInt = type;
308         event.valueInt2 = volume;
309         event.device = getDevice(address);
310         if (DBG) {
311             Log.d(TAG, "onVolumeChange: address " + address + " event "  + event);
312         }
313         HeadsetClientService service = HeadsetClientService.getHeadsetClientService();
314         // Ignore volume changes from the Phone. This is to avoid the scenario where we may have two
315         // phones connected each tries to set different volumes.
316         Log.w(TAG, "onVolumeChange: Ignoring message: " + event);
317     }
318 
onCmdResult(int type, int cme, byte[] address)319     private void onCmdResult(int type, int cme, byte[] address) {
320         StackEvent event = new StackEvent(StackEvent.EVENT_TYPE_CMD_RESULT);
321         event.valueInt = type;
322         event.valueInt2 = cme;
323         event.device = getDevice(address);
324         if (DBG) {
325             Log.d(TAG, "onCmdResult: address " + address + " event "  + event);
326         }
327         HeadsetClientService service = HeadsetClientService.getHeadsetClientService();
328         if (service != null) {
329             service.messageFromNative(event);
330         } else {
331             Log.w(TAG, "onCmdResult: Ignoring message because service not available: " + event);
332         }
333     }
334 
onSubscriberInfo(String number, int type, byte[] address)335     private void onSubscriberInfo(String number, int type, byte[] address) {
336         StackEvent event = new StackEvent(StackEvent.EVENT_TYPE_SUBSCRIBER_INFO);
337         event.valueInt = type;
338         event.valueString = number;
339         event.device = getDevice(address);
340         if (DBG) {
341             Log.d(TAG, "onSubscriberInfo: address " + address + " event "  + event);
342         }
343         HeadsetClientService service = HeadsetClientService.getHeadsetClientService();
344         if (service != null) {
345             service.messageFromNative(event);
346         } else {
347             Log.w(TAG, "onSubscriberInfo: Ignoring message because service not available: " + event);
348         }
349     }
350 
onInBandRing(int in_band, byte[] address)351     private void onInBandRing(int in_band, byte[] address) {
352         Log.w(TAG, "onInBandRing not supported");
353     }
354 
onLastVoiceTagNumber(String number, byte[] address)355     private void onLastVoiceTagNumber(String number, byte[] address) {
356         Log.w(TAG, "onLastVoiceTagNumber not supported");
357     }
358 
onRingIndication(byte[] address)359     private void onRingIndication(byte[] address) {
360         StackEvent event = new StackEvent(StackEvent.EVENT_TYPE_RING_INDICATION);
361         event.device = getDevice(address);
362         if (DBG) {
363             Log.d(TAG, "onRingIndication: address " + address + " event "  + event);
364         }
365         HeadsetClientService service = HeadsetClientService.getHeadsetClientService();
366         if (service != null) {
367             service.messageFromNative(event);
368         } else {
369             Log.w(TAG, "onRingIndication: Ignoring message because service not available: " + event);
370         }
371     }
372 }
373