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 33 NativeInterface() {} 34 35 // Native methods that call into the JNI interface 36 static native void classInitNative(); 37 static native void initializeNative(); 38 static native void cleanupNative(); 39 static native boolean connectNative(byte[] address); 40 static native boolean disconnectNative(byte[] address); 41 static native boolean connectAudioNative(byte[] address); 42 static native boolean disconnectAudioNative(byte[] address); 43 static native boolean startVoiceRecognitionNative(byte[] address); 44 static native boolean stopVoiceRecognitionNative(byte[] address); 45 static native boolean setVolumeNative(byte[] address, int volumeType, int volume); 46 static native boolean dialNative(byte[] address, String number); 47 static native boolean dialMemoryNative(byte[] address, int location); 48 static native boolean handleCallActionNative(byte[] address, int action, int index); 49 static native boolean queryCurrentCallsNative(byte[] address); 50 static native boolean queryCurrentOperatorNameNative(byte[] address); 51 static native boolean retrieveSubscriberInfoNative(byte[] address); 52 static native boolean sendDtmfNative(byte[] address, byte code); 53 static native boolean requestLastVoiceTagNumberNative(byte[] address); 54 static native boolean sendATCmdNative(byte[] address, int atCmd, int val1, 55 int val2, String arg); 56 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. 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 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 96 private void onVrStateChanged(int state) { 97 Log.w(TAG, "onVrStateChanged not supported"); 98 } 99 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 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 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 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 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 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 */ 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 */ 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 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 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 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 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 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 if (service != null) { 315 service.messageFromNative(event); 316 } else { 317 Log.w(TAG, "onVolumeChange: Ignoring message because service not available: " + event); 318 } 319 } 320 321 private void onCmdResult(int type, int cme, byte[] address) { 322 StackEvent event = new StackEvent(StackEvent.EVENT_TYPE_CMD_RESULT); 323 event.valueInt = type; 324 event.valueInt2 = cme; 325 event.device = getDevice(address); 326 if (DBG) { 327 Log.d(TAG, "onCmdResult: address " + address + " event " + event); 328 } 329 HeadsetClientService service = HeadsetClientService.getHeadsetClientService(); 330 if (service != null) { 331 service.messageFromNative(event); 332 } else { 333 Log.w(TAG, "onCmdResult: Ignoring message because service not available: " + event); 334 } 335 } 336 337 private void onSubscriberInfo(String number, int type, byte[] address) { 338 StackEvent event = new StackEvent(StackEvent.EVENT_TYPE_SUBSCRIBER_INFO); 339 event.valueInt = type; 340 event.valueString = number; 341 event.device = getDevice(address); 342 if (DBG) { 343 Log.d(TAG, "onSubscriberInfo: address " + address + " event " + event); 344 } 345 HeadsetClientService service = HeadsetClientService.getHeadsetClientService(); 346 if (service != null) { 347 service.messageFromNative(event); 348 } else { 349 Log.w(TAG, "onSubscriberInfo: Ignoring message because service not available: " + event); 350 } 351 } 352 353 private void onInBandRing(int in_band, byte[] address) { 354 Log.w(TAG, "onInBandRing not supported"); 355 } 356 357 private void onLastVoiceTagNumber(String number, byte[] address) { 358 Log.w(TAG, "onLastVoiceTagNumber not supported"); 359 } 360 361 private void onRingIndication(byte[] address) { 362 StackEvent event = new StackEvent(StackEvent.EVENT_TYPE_RING_INDICATION); 363 event.device = getDevice(address); 364 if (DBG) { 365 Log.d(TAG, "onRingIndication: address " + address + " event " + event); 366 } 367 HeadsetClientService service = HeadsetClientService.getHeadsetClientService(); 368 if (service != null) { 369 service.messageFromNative(event); 370 } else { 371 Log.w(TAG, "onRingIndication: Ignoring message because service not available: " + event); 372 } 373 } 374 } 375