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