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