Loading android/app/jni/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ cc_library_shared { ], shared_libs: [ "libandroid_runtime", "libbase", "libbinder", "libbluetooth-binder", "libchrome", Loading android/app/jni/com_android_bluetooth_hfpclient.cpp +18 −0 Original line number Diff line number Diff line Loading @@ -49,6 +49,7 @@ static jmethodID method_onSubscriberInfo; static jmethodID method_onInBandRing; static jmethodID method_onLastVoiceTagNumber; static jmethodID method_onRingIndication; static jmethodID method_onUnknownEvent; static jbyteArray marshall_bda(const RawAddress* bd_addr) { CallbackEnv sCallbackEnv(__func__); Loading Loading @@ -368,6 +369,20 @@ static void ring_indication_cb(const RawAddress* bd_addr) { addr.get()); } static void unknown_event_cb(const RawAddress* bd_addr, const char* eventString) { CallbackEnv sCallbackEnv(__func__); if (!sCallbackEnv.valid()) return; ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(), marshall_bda(bd_addr)); if (!addr.get()) return; ScopedLocalRef<jstring> js_event(sCallbackEnv.get(), sCallbackEnv->NewStringUTF(eventString)); sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onUnknownEvent, js_event.get(), addr.get()); } static bthf_client_callbacks_t sBluetoothHfpClientCallbacks = { sizeof(sBluetoothHfpClientCallbacks), connection_state_cb, Loading @@ -391,6 +406,7 @@ static bthf_client_callbacks_t sBluetoothHfpClientCallbacks = { in_band_ring_cb, last_voice_tag_number_cb, ring_indication_cb, unknown_event_cb, }; static void classInitNative(JNIEnv* env, jclass clazz) { Loading Loading @@ -423,6 +439,8 @@ static void classInitNative(JNIEnv* env, jclass clazz) { method_onLastVoiceTagNumber = env->GetMethodID(clazz, "onLastVoiceTagNumber", "(Ljava/lang/String;[B)V"); method_onRingIndication = env->GetMethodID(clazz, "onRingIndication", "([B)V"); method_onUnknownEvent = env->GetMethodID(clazz, "onUnknownEvent", "(Ljava/lang/String;[B)V"); ALOGI("%s succeeds", __func__); } Loading android/app/src/com/android/bluetooth/hfpclient/HeadsetClientHalConstants.java +1 −0 Original line number Diff line number Diff line Loading @@ -170,6 +170,7 @@ public final class HeadsetClientHalConstants { // used for sending vendor specific AT cmds to AG. static final int HANDSFREECLIENT_AT_CMD_NREC = 15; static final int HANDSFREECLIENT_AT_CMD_VENDOR_SPECIFIC_CMD = 16; // Flag to check for local NREC support static final boolean HANDSFREECLIENT_NREC_SUPPORTED = true; Loading android/app/src/com/android/bluetooth/hfpclient/HeadsetClientService.java +33 −4 Original line number Diff line number Diff line Loading @@ -80,8 +80,8 @@ public class HeadsetClientService extends ProfileService { } // Setup the JNI service mNativeInterface = new NativeInterface(); mNativeInterface.initializeNative(); mNativeInterface = NativeInterface.getInstance(); mNativeInterface.initialize(); mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE); if (mAudioManager == null) { Loading Loading @@ -137,7 +137,7 @@ public class HeadsetClientService extends ProfileService { mSmThread.quit(); mSmThread = null; mNativeInterface.cleanupNative(); mNativeInterface.cleanup(); mNativeInterface = null; return true; Loading Loading @@ -430,6 +430,15 @@ public class HeadsetClientService extends ProfileService { return service.getCurrentAgEvents(device); } @Override public boolean sendVendorAtCommand(BluetoothDevice device, int vendorId, String atCommand) { HeadsetClientService service = getService(); if (service == null) { return false; } return service.sendVendorAtCommand(device, vendorId, atCommand); } @Override public Bundle getCurrentAgFeatures(BluetoothDevice device) { HeadsetClientService service = getService(); Loading Loading @@ -820,6 +829,26 @@ public class HeadsetClientService extends ProfileService { return true; } /** Send vendor AT command. */ public boolean sendVendorAtCommand(BluetoothDevice device, int vendorId, String atCommand) { enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); HeadsetClientStateMachine sm = getStateMachine(device); if (sm == null) { Log.e(TAG, "Cannot allocate SM for device " + device); return false; } int connectionState = sm.getConnectionState(device); if (connectionState != BluetoothProfile.STATE_CONNECTED) { return false; } Message msg = sm.obtainMessage(HeadsetClientStateMachine.SEND_VENDOR_AT_COMMAND, vendorId, 0, atCommand); sm.sendMessage(msg); return true; } public Bundle getCurrentAgEvents(BluetoothDevice device) { enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); HeadsetClientStateMachine sm = getStateMachine(device); Loading Loading @@ -885,7 +914,7 @@ public class HeadsetClientService extends ProfileService { // Allocate a new SM Log.d(TAG, "Creating a new state machine"); sm = mSmFactory.make(this, mSmThread); sm = mSmFactory.make(this, mSmThread, mNativeInterface); mStateMachineMap.put(device, sm); return sm; } Loading android/app/src/com/android/bluetooth/hfpclient/HeadsetClientStateMachine.java +51 −29 Original line number Diff line number Diff line Loading @@ -99,6 +99,7 @@ public class HeadsetClientStateMachine extends StateMachine { public static final int SEND_DTMF = 17; public static final int EXPLICIT_CALL_TRANSFER = 18; public static final int DISABLE_NREC = 20; public static final int SEND_VENDOR_AT_COMMAND = 21; // internal actions private static final int QUERY_CURRENT_CALLS = 50; Loading Loading @@ -174,7 +175,9 @@ public class HeadsetClientStateMachine extends StateMachine { // This is returned when requesting focus from AudioManager private AudioFocusRequest mAudioFocusRequest; private AudioManager mAudioManager; private final AudioManager mAudioManager; private final NativeInterface mNativeInterface; private final VendorCommandResponseProcessor mVendorProcessor; // Accessor for the states, useful for reusing the state machines public IState getDisconnectedState() { Loading Loading @@ -264,7 +267,7 @@ public class HeadsetClientStateMachine extends StateMachine { private boolean queryCallsStart() { logD("queryCallsStart"); clearPendingAction(); NativeInterface.queryCurrentCallsNative(getByteAddress(mCurrentDevice)); mNativeInterface.queryCurrentCalls(getByteAddress(mCurrentDevice)); addQueuedAction(QUERY_CURRENT_CALLS, 0); return true; } Loading Loading @@ -487,7 +490,7 @@ public class HeadsetClientStateMachine extends StateMachine { routeHfpAudio(true); } if (NativeInterface.handleCallActionNative(getByteAddress(mCurrentDevice), action, 0)) { if (mNativeInterface.handleCallAction(getByteAddress(mCurrentDevice), action, 0)) { addQueuedAction(ACCEPT_CALL, action); } else { Log.e(TAG, "ERROR: Couldn't accept a call, action:" + action); Loading Loading @@ -526,8 +529,8 @@ public class HeadsetClientStateMachine extends StateMachine { return; } if (mNativeInterface.handleCallAction(getByteAddress(mCurrentDevice), action, 0)) { logD("Reject call action " + action); if (NativeInterface.handleCallActionNative(getByteAddress(mCurrentDevice), action, 0)) { addQueuedAction(REJECT_CALL, action); } else { Log.e(TAG, "ERROR: Couldn't reject a call, action:" + action); Loading @@ -551,7 +554,7 @@ public class HeadsetClientStateMachine extends StateMachine { action = HeadsetClientHalConstants.CALL_ACTION_CHLD_2; } if (NativeInterface.handleCallActionNative(getByteAddress(mCurrentDevice), action, 0)) { if (mNativeInterface.handleCallAction(getByteAddress(mCurrentDevice), action, 0)) { addQueuedAction(HOLD_CALL, action); } else { Log.e(TAG, "ERROR: Couldn't hold a call, action:" + action); Loading @@ -572,7 +575,7 @@ public class HeadsetClientStateMachine extends StateMachine { action = HeadsetClientHalConstants.CALL_ACTION_CHLD_0; } if (c != null) { if (NativeInterface.handleCallActionNative(getByteAddress(mCurrentDevice), action, 0)) { if (mNativeInterface.handleCallAction(getByteAddress(mCurrentDevice), action, 0)) { addQueuedAction(TERMINATE_CALL, action); } else { Log.e(TAG, "ERROR: Couldn't terminate outgoing call"); Loading @@ -590,7 +593,7 @@ public class HeadsetClientStateMachine extends StateMachine { return; } if (NativeInterface.handleCallActionNative(getByteAddress(mCurrentDevice), if (mNativeInterface.handleCallAction(getByteAddress(mCurrentDevice), HeadsetClientHalConstants.CALL_ACTION_CHLD_2X, idx)) { addQueuedAction(ENTER_PRIVATE_MODE, c); } else { Loading @@ -606,7 +609,7 @@ public class HeadsetClientStateMachine extends StateMachine { return; } if (NativeInterface.handleCallActionNative(getByteAddress(mCurrentDevice), if (mNativeInterface.handleCallAction(getByteAddress(mCurrentDevice), HeadsetClientHalConstants.CALL_ACTION_CHLD_4, -1)) { addQueuedAction(EXPLICIT_CALL_TRANSFER); } else { Loading Loading @@ -659,11 +662,15 @@ public class HeadsetClientStateMachine extends StateMachine { return b; } HeadsetClientStateMachine(HeadsetClientService context, Looper looper) { HeadsetClientStateMachine(HeadsetClientService context, Looper looper, NativeInterface nativeInterface) { super(TAG, looper); mService = context; mNativeInterface = nativeInterface; mAudioManager = mService.getAudioManager(); mVendorProcessor = new VendorCommandResponseProcessor(mService, mNativeInterface); mAdapter = BluetoothAdapter.getDefaultAdapter(); mAudioState = BluetoothHeadsetClient.STATE_AUDIO_DISCONNECTED; mAudioWbs = false; Loading Loading @@ -699,9 +706,11 @@ public class HeadsetClientStateMachine extends StateMachine { setInitialState(mDisconnected); } static HeadsetClientStateMachine make(HeadsetClientService context, Looper l) { static HeadsetClientStateMachine make(HeadsetClientService context, Looper looper, NativeInterface nativeInterface) { logD("make"); HeadsetClientStateMachine hfcsm = new HeadsetClientStateMachine(context, l); HeadsetClientStateMachine hfcsm = new HeadsetClientStateMachine(context, looper, nativeInterface); hfcsm.start(); return hfcsm; } Loading Loading @@ -739,7 +748,7 @@ public class HeadsetClientStateMachine extends StateMachine { public void doQuit() { logD("doQuit"); if (mCurrentDevice != null) { NativeInterface.disconnectNative(getByteAddress(mCurrentDevice)); mNativeInterface.disconnect(getByteAddress(mCurrentDevice)); } routeHfpAudio(false); returnAudioFocusIfNecessary(); Loading Loading @@ -825,7 +834,7 @@ public class HeadsetClientStateMachine extends StateMachine { switch (message.what) { case CONNECT: BluetoothDevice device = (BluetoothDevice) message.obj; if (!NativeInterface.connectNative(getByteAddress(device))) { if (!mNativeInterface.connect(getByteAddress(device))) { // No state transition is involved, fire broadcast immediately broadcastConnectionState(device, BluetoothProfile.STATE_DISCONNECTED, BluetoothProfile.STATE_DISCONNECTED); Loading Loading @@ -871,7 +880,7 @@ public class HeadsetClientStateMachine extends StateMachine { + " bondState=" + device.getBondState()); // reject the connection and stay in Disconnected state // itself NativeInterface.disconnectNative(getByteAddress(device)); mNativeInterface.disconnect(getByteAddress(device)); // the other profile connection should be initiated AdapterService adapterService = AdapterService.getAdapterService(); // No state transition is involved, fire broadcast immediately Loading Loading @@ -985,7 +994,7 @@ public class HeadsetClientStateMachine extends StateMachine { // We do not support devices which do not support enhanced call status (ECS). if ((mPeerFeatures & HeadsetClientHalConstants.PEER_FEAT_ECS) == 0) { NativeInterface.disconnectNative(getByteAddress(device)); mNativeInterface.disconnect(getByteAddress(device)); return; } Loading @@ -993,7 +1002,7 @@ public class HeadsetClientStateMachine extends StateMachine { if (HeadsetClientHalConstants.HANDSFREECLIENT_NREC_SUPPORTED && ( (mPeerFeatures & HeadsetClientHalConstants.PEER_FEAT_ECNR) == HeadsetClientHalConstants.PEER_FEAT_ECNR)) { if (NativeInterface.sendATCmdNative(getByteAddress(mCurrentDevice), if (mNativeInterface.sendATCmd(getByteAddress(mCurrentDevice), HeadsetClientHalConstants.HANDSFREECLIENT_AT_CMD_NREC, 1, 0, null)) { addQueuedAction(DISABLE_NREC); Loading Loading @@ -1083,20 +1092,20 @@ public class HeadsetClientStateMachine extends StateMachine { // already connected to this device, do nothing break; } NativeInterface.connectNative(getByteAddress(device)); mNativeInterface.connect(getByteAddress(device)); break; case DISCONNECT: BluetoothDevice dev = (BluetoothDevice) message.obj; if (!mCurrentDevice.equals(dev)) { break; } if (!NativeInterface.disconnectNative(getByteAddress(dev))) { if (!mNativeInterface.disconnect(getByteAddress(dev))) { Log.e(TAG, "disconnectNative failed for " + dev); } break; case CONNECT_AUDIO: if (!NativeInterface.connectAudioNative(getByteAddress(mCurrentDevice))) { if (!mNativeInterface.connectAudio(getByteAddress(mCurrentDevice))) { Log.e(TAG, "ERROR: Couldn't connect Audio for device " + mCurrentDevice); // No state transition is involved, fire broadcast immediately broadcastAudioState(mCurrentDevice, Loading @@ -1108,14 +1117,14 @@ public class HeadsetClientStateMachine extends StateMachine { break; case DISCONNECT_AUDIO: if (!NativeInterface.disconnectAudioNative(getByteAddress(mCurrentDevice))) { if (!mNativeInterface.disconnectAudio(getByteAddress(mCurrentDevice))) { Log.e(TAG, "ERROR: Couldn't disconnect Audio for device " + mCurrentDevice); } break; case VOICE_RECOGNITION_START: if (mVoiceRecognitionActive == HeadsetClientHalConstants.VR_STATE_STOPPED) { if (NativeInterface.startVoiceRecognitionNative( if (mNativeInterface.startVoiceRecognition( getByteAddress(mCurrentDevice))) { addQueuedAction(VOICE_RECOGNITION_START); } else { Loading @@ -1126,7 +1135,7 @@ public class HeadsetClientStateMachine extends StateMachine { case VOICE_RECOGNITION_STOP: if (mVoiceRecognitionActive == HeadsetClientHalConstants.VR_STATE_STARTED) { if (NativeInterface.stopVoiceRecognitionNative( if (mNativeInterface.stopVoiceRecognition( getByteAddress(mCurrentDevice))) { addQueuedAction(VOICE_RECOGNITION_STOP); } else { Loading @@ -1135,6 +1144,13 @@ public class HeadsetClientStateMachine extends StateMachine { } break; case SEND_VENDOR_AT_COMMAND: { int vendorId = message.arg1; String atCommand = (String) (message.obj); mVendorProcessor.sendCommand(vendorId, atCommand, mCurrentDevice); break; } // Called only for Mute/Un-mute - Mic volume change is not allowed. case SET_MIC_VOLUME: break; Loading @@ -1146,7 +1162,7 @@ public class HeadsetClientStateMachine extends StateMachine { logD("Volume" + amVol + ":" + mCommandedSpeakerVolume); // Volume was changed by a 3rd party mCommandedSpeakerVolume = -1; if (NativeInterface.setVolumeNative(getByteAddress(mCurrentDevice), if (mNativeInterface.setVolume(getByteAddress(mCurrentDevice), HeadsetClientHalConstants.VOLUME_TYPE_SPK, hfVol)) { addQueuedAction(SET_SPEAKER_VOLUME); } Loading @@ -1157,7 +1173,7 @@ public class HeadsetClientStateMachine extends StateMachine { BluetoothHeadsetClientCall c = (BluetoothHeadsetClientCall) message.obj; mCalls.put(HF_ORIGINATED_CALL_ID, c); if (NativeInterface.dialNative(getByteAddress(mCurrentDevice), c.getNumber())) { if (mNativeInterface.dial(getByteAddress(mCurrentDevice), c.getNumber())) { addQueuedAction(DIAL_NUMBER, c.getNumber()); // Start looping on calling current calls. sendMessage(QUERY_CURRENT_CALLS); Loading Loading @@ -1189,7 +1205,7 @@ public class HeadsetClientStateMachine extends StateMachine { explicitCallTransfer(); break; case SEND_DTMF: if (NativeInterface.sendDtmfNative(getByteAddress(mCurrentDevice), if (mNativeInterface.sendDtmf(getByteAddress(mCurrentDevice), (byte) message.arg1)) { addQueuedAction(SEND_DTMF); } else { Loading @@ -1197,7 +1213,7 @@ public class HeadsetClientStateMachine extends StateMachine { } break; case SUBSCRIBER_INFO: if (NativeInterface.retrieveSubscriberInfoNative( if (mNativeInterface.retrieveSubscriberInfo( getByteAddress(mCurrentDevice))) { addQueuedAction(SUBSCRIBER_INFO); } else { Loading Loading @@ -1248,7 +1264,7 @@ public class HeadsetClientStateMachine extends StateMachine { if (mIndicatorNetworkState == HeadsetClientHalConstants.NETWORK_STATE_AVAILABLE) { if (NativeInterface.queryCurrentOperatorNameNative( if (mNativeInterface.queryCurrentOperatorName( getByteAddress(mCurrentDevice))) { addQueuedAction(QUERY_OPERATOR_NAME); } else { Loading Loading @@ -1385,6 +1401,12 @@ public class HeadsetClientStateMachine extends StateMachine { // implemented (by the client of this service). Use the // CALL_STATE_INCOMING (and similar) handle ringing. break; case StackEvent.EVENT_TYPE_UNKNOWN_EVENT: if (!mVendorProcessor.processEvent(event.valueString, event.device)) { Log.e(TAG, "Unknown event :" + event.valueString + " for device " + event.device); } break; default: Log.e(TAG, "Unknown stack event: " + event.type); break; Loading Loading @@ -1529,7 +1551,7 @@ public class HeadsetClientStateMachine extends StateMachine { * StackEvent.EVENT_TYPE_AUDIO_STATE_CHANGED, that triggers State * Machines state changing */ if (NativeInterface.disconnectAudioNative(getByteAddress(mCurrentDevice))) { if (mNativeInterface.disconnectAudio(getByteAddress(mCurrentDevice))) { routeHfpAudio(false); returnAudioFocusIfNecessary(); } Loading Loading
android/app/jni/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ cc_library_shared { ], shared_libs: [ "libandroid_runtime", "libbase", "libbinder", "libbluetooth-binder", "libchrome", Loading
android/app/jni/com_android_bluetooth_hfpclient.cpp +18 −0 Original line number Diff line number Diff line Loading @@ -49,6 +49,7 @@ static jmethodID method_onSubscriberInfo; static jmethodID method_onInBandRing; static jmethodID method_onLastVoiceTagNumber; static jmethodID method_onRingIndication; static jmethodID method_onUnknownEvent; static jbyteArray marshall_bda(const RawAddress* bd_addr) { CallbackEnv sCallbackEnv(__func__); Loading Loading @@ -368,6 +369,20 @@ static void ring_indication_cb(const RawAddress* bd_addr) { addr.get()); } static void unknown_event_cb(const RawAddress* bd_addr, const char* eventString) { CallbackEnv sCallbackEnv(__func__); if (!sCallbackEnv.valid()) return; ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(), marshall_bda(bd_addr)); if (!addr.get()) return; ScopedLocalRef<jstring> js_event(sCallbackEnv.get(), sCallbackEnv->NewStringUTF(eventString)); sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onUnknownEvent, js_event.get(), addr.get()); } static bthf_client_callbacks_t sBluetoothHfpClientCallbacks = { sizeof(sBluetoothHfpClientCallbacks), connection_state_cb, Loading @@ -391,6 +406,7 @@ static bthf_client_callbacks_t sBluetoothHfpClientCallbacks = { in_band_ring_cb, last_voice_tag_number_cb, ring_indication_cb, unknown_event_cb, }; static void classInitNative(JNIEnv* env, jclass clazz) { Loading Loading @@ -423,6 +439,8 @@ static void classInitNative(JNIEnv* env, jclass clazz) { method_onLastVoiceTagNumber = env->GetMethodID(clazz, "onLastVoiceTagNumber", "(Ljava/lang/String;[B)V"); method_onRingIndication = env->GetMethodID(clazz, "onRingIndication", "([B)V"); method_onUnknownEvent = env->GetMethodID(clazz, "onUnknownEvent", "(Ljava/lang/String;[B)V"); ALOGI("%s succeeds", __func__); } Loading
android/app/src/com/android/bluetooth/hfpclient/HeadsetClientHalConstants.java +1 −0 Original line number Diff line number Diff line Loading @@ -170,6 +170,7 @@ public final class HeadsetClientHalConstants { // used for sending vendor specific AT cmds to AG. static final int HANDSFREECLIENT_AT_CMD_NREC = 15; static final int HANDSFREECLIENT_AT_CMD_VENDOR_SPECIFIC_CMD = 16; // Flag to check for local NREC support static final boolean HANDSFREECLIENT_NREC_SUPPORTED = true; Loading
android/app/src/com/android/bluetooth/hfpclient/HeadsetClientService.java +33 −4 Original line number Diff line number Diff line Loading @@ -80,8 +80,8 @@ public class HeadsetClientService extends ProfileService { } // Setup the JNI service mNativeInterface = new NativeInterface(); mNativeInterface.initializeNative(); mNativeInterface = NativeInterface.getInstance(); mNativeInterface.initialize(); mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE); if (mAudioManager == null) { Loading Loading @@ -137,7 +137,7 @@ public class HeadsetClientService extends ProfileService { mSmThread.quit(); mSmThread = null; mNativeInterface.cleanupNative(); mNativeInterface.cleanup(); mNativeInterface = null; return true; Loading Loading @@ -430,6 +430,15 @@ public class HeadsetClientService extends ProfileService { return service.getCurrentAgEvents(device); } @Override public boolean sendVendorAtCommand(BluetoothDevice device, int vendorId, String atCommand) { HeadsetClientService service = getService(); if (service == null) { return false; } return service.sendVendorAtCommand(device, vendorId, atCommand); } @Override public Bundle getCurrentAgFeatures(BluetoothDevice device) { HeadsetClientService service = getService(); Loading Loading @@ -820,6 +829,26 @@ public class HeadsetClientService extends ProfileService { return true; } /** Send vendor AT command. */ public boolean sendVendorAtCommand(BluetoothDevice device, int vendorId, String atCommand) { enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); HeadsetClientStateMachine sm = getStateMachine(device); if (sm == null) { Log.e(TAG, "Cannot allocate SM for device " + device); return false; } int connectionState = sm.getConnectionState(device); if (connectionState != BluetoothProfile.STATE_CONNECTED) { return false; } Message msg = sm.obtainMessage(HeadsetClientStateMachine.SEND_VENDOR_AT_COMMAND, vendorId, 0, atCommand); sm.sendMessage(msg); return true; } public Bundle getCurrentAgEvents(BluetoothDevice device) { enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); HeadsetClientStateMachine sm = getStateMachine(device); Loading Loading @@ -885,7 +914,7 @@ public class HeadsetClientService extends ProfileService { // Allocate a new SM Log.d(TAG, "Creating a new state machine"); sm = mSmFactory.make(this, mSmThread); sm = mSmFactory.make(this, mSmThread, mNativeInterface); mStateMachineMap.put(device, sm); return sm; } Loading
android/app/src/com/android/bluetooth/hfpclient/HeadsetClientStateMachine.java +51 −29 Original line number Diff line number Diff line Loading @@ -99,6 +99,7 @@ public class HeadsetClientStateMachine extends StateMachine { public static final int SEND_DTMF = 17; public static final int EXPLICIT_CALL_TRANSFER = 18; public static final int DISABLE_NREC = 20; public static final int SEND_VENDOR_AT_COMMAND = 21; // internal actions private static final int QUERY_CURRENT_CALLS = 50; Loading Loading @@ -174,7 +175,9 @@ public class HeadsetClientStateMachine extends StateMachine { // This is returned when requesting focus from AudioManager private AudioFocusRequest mAudioFocusRequest; private AudioManager mAudioManager; private final AudioManager mAudioManager; private final NativeInterface mNativeInterface; private final VendorCommandResponseProcessor mVendorProcessor; // Accessor for the states, useful for reusing the state machines public IState getDisconnectedState() { Loading Loading @@ -264,7 +267,7 @@ public class HeadsetClientStateMachine extends StateMachine { private boolean queryCallsStart() { logD("queryCallsStart"); clearPendingAction(); NativeInterface.queryCurrentCallsNative(getByteAddress(mCurrentDevice)); mNativeInterface.queryCurrentCalls(getByteAddress(mCurrentDevice)); addQueuedAction(QUERY_CURRENT_CALLS, 0); return true; } Loading Loading @@ -487,7 +490,7 @@ public class HeadsetClientStateMachine extends StateMachine { routeHfpAudio(true); } if (NativeInterface.handleCallActionNative(getByteAddress(mCurrentDevice), action, 0)) { if (mNativeInterface.handleCallAction(getByteAddress(mCurrentDevice), action, 0)) { addQueuedAction(ACCEPT_CALL, action); } else { Log.e(TAG, "ERROR: Couldn't accept a call, action:" + action); Loading Loading @@ -526,8 +529,8 @@ public class HeadsetClientStateMachine extends StateMachine { return; } if (mNativeInterface.handleCallAction(getByteAddress(mCurrentDevice), action, 0)) { logD("Reject call action " + action); if (NativeInterface.handleCallActionNative(getByteAddress(mCurrentDevice), action, 0)) { addQueuedAction(REJECT_CALL, action); } else { Log.e(TAG, "ERROR: Couldn't reject a call, action:" + action); Loading @@ -551,7 +554,7 @@ public class HeadsetClientStateMachine extends StateMachine { action = HeadsetClientHalConstants.CALL_ACTION_CHLD_2; } if (NativeInterface.handleCallActionNative(getByteAddress(mCurrentDevice), action, 0)) { if (mNativeInterface.handleCallAction(getByteAddress(mCurrentDevice), action, 0)) { addQueuedAction(HOLD_CALL, action); } else { Log.e(TAG, "ERROR: Couldn't hold a call, action:" + action); Loading @@ -572,7 +575,7 @@ public class HeadsetClientStateMachine extends StateMachine { action = HeadsetClientHalConstants.CALL_ACTION_CHLD_0; } if (c != null) { if (NativeInterface.handleCallActionNative(getByteAddress(mCurrentDevice), action, 0)) { if (mNativeInterface.handleCallAction(getByteAddress(mCurrentDevice), action, 0)) { addQueuedAction(TERMINATE_CALL, action); } else { Log.e(TAG, "ERROR: Couldn't terminate outgoing call"); Loading @@ -590,7 +593,7 @@ public class HeadsetClientStateMachine extends StateMachine { return; } if (NativeInterface.handleCallActionNative(getByteAddress(mCurrentDevice), if (mNativeInterface.handleCallAction(getByteAddress(mCurrentDevice), HeadsetClientHalConstants.CALL_ACTION_CHLD_2X, idx)) { addQueuedAction(ENTER_PRIVATE_MODE, c); } else { Loading @@ -606,7 +609,7 @@ public class HeadsetClientStateMachine extends StateMachine { return; } if (NativeInterface.handleCallActionNative(getByteAddress(mCurrentDevice), if (mNativeInterface.handleCallAction(getByteAddress(mCurrentDevice), HeadsetClientHalConstants.CALL_ACTION_CHLD_4, -1)) { addQueuedAction(EXPLICIT_CALL_TRANSFER); } else { Loading Loading @@ -659,11 +662,15 @@ public class HeadsetClientStateMachine extends StateMachine { return b; } HeadsetClientStateMachine(HeadsetClientService context, Looper looper) { HeadsetClientStateMachine(HeadsetClientService context, Looper looper, NativeInterface nativeInterface) { super(TAG, looper); mService = context; mNativeInterface = nativeInterface; mAudioManager = mService.getAudioManager(); mVendorProcessor = new VendorCommandResponseProcessor(mService, mNativeInterface); mAdapter = BluetoothAdapter.getDefaultAdapter(); mAudioState = BluetoothHeadsetClient.STATE_AUDIO_DISCONNECTED; mAudioWbs = false; Loading Loading @@ -699,9 +706,11 @@ public class HeadsetClientStateMachine extends StateMachine { setInitialState(mDisconnected); } static HeadsetClientStateMachine make(HeadsetClientService context, Looper l) { static HeadsetClientStateMachine make(HeadsetClientService context, Looper looper, NativeInterface nativeInterface) { logD("make"); HeadsetClientStateMachine hfcsm = new HeadsetClientStateMachine(context, l); HeadsetClientStateMachine hfcsm = new HeadsetClientStateMachine(context, looper, nativeInterface); hfcsm.start(); return hfcsm; } Loading Loading @@ -739,7 +748,7 @@ public class HeadsetClientStateMachine extends StateMachine { public void doQuit() { logD("doQuit"); if (mCurrentDevice != null) { NativeInterface.disconnectNative(getByteAddress(mCurrentDevice)); mNativeInterface.disconnect(getByteAddress(mCurrentDevice)); } routeHfpAudio(false); returnAudioFocusIfNecessary(); Loading Loading @@ -825,7 +834,7 @@ public class HeadsetClientStateMachine extends StateMachine { switch (message.what) { case CONNECT: BluetoothDevice device = (BluetoothDevice) message.obj; if (!NativeInterface.connectNative(getByteAddress(device))) { if (!mNativeInterface.connect(getByteAddress(device))) { // No state transition is involved, fire broadcast immediately broadcastConnectionState(device, BluetoothProfile.STATE_DISCONNECTED, BluetoothProfile.STATE_DISCONNECTED); Loading Loading @@ -871,7 +880,7 @@ public class HeadsetClientStateMachine extends StateMachine { + " bondState=" + device.getBondState()); // reject the connection and stay in Disconnected state // itself NativeInterface.disconnectNative(getByteAddress(device)); mNativeInterface.disconnect(getByteAddress(device)); // the other profile connection should be initiated AdapterService adapterService = AdapterService.getAdapterService(); // No state transition is involved, fire broadcast immediately Loading Loading @@ -985,7 +994,7 @@ public class HeadsetClientStateMachine extends StateMachine { // We do not support devices which do not support enhanced call status (ECS). if ((mPeerFeatures & HeadsetClientHalConstants.PEER_FEAT_ECS) == 0) { NativeInterface.disconnectNative(getByteAddress(device)); mNativeInterface.disconnect(getByteAddress(device)); return; } Loading @@ -993,7 +1002,7 @@ public class HeadsetClientStateMachine extends StateMachine { if (HeadsetClientHalConstants.HANDSFREECLIENT_NREC_SUPPORTED && ( (mPeerFeatures & HeadsetClientHalConstants.PEER_FEAT_ECNR) == HeadsetClientHalConstants.PEER_FEAT_ECNR)) { if (NativeInterface.sendATCmdNative(getByteAddress(mCurrentDevice), if (mNativeInterface.sendATCmd(getByteAddress(mCurrentDevice), HeadsetClientHalConstants.HANDSFREECLIENT_AT_CMD_NREC, 1, 0, null)) { addQueuedAction(DISABLE_NREC); Loading Loading @@ -1083,20 +1092,20 @@ public class HeadsetClientStateMachine extends StateMachine { // already connected to this device, do nothing break; } NativeInterface.connectNative(getByteAddress(device)); mNativeInterface.connect(getByteAddress(device)); break; case DISCONNECT: BluetoothDevice dev = (BluetoothDevice) message.obj; if (!mCurrentDevice.equals(dev)) { break; } if (!NativeInterface.disconnectNative(getByteAddress(dev))) { if (!mNativeInterface.disconnect(getByteAddress(dev))) { Log.e(TAG, "disconnectNative failed for " + dev); } break; case CONNECT_AUDIO: if (!NativeInterface.connectAudioNative(getByteAddress(mCurrentDevice))) { if (!mNativeInterface.connectAudio(getByteAddress(mCurrentDevice))) { Log.e(TAG, "ERROR: Couldn't connect Audio for device " + mCurrentDevice); // No state transition is involved, fire broadcast immediately broadcastAudioState(mCurrentDevice, Loading @@ -1108,14 +1117,14 @@ public class HeadsetClientStateMachine extends StateMachine { break; case DISCONNECT_AUDIO: if (!NativeInterface.disconnectAudioNative(getByteAddress(mCurrentDevice))) { if (!mNativeInterface.disconnectAudio(getByteAddress(mCurrentDevice))) { Log.e(TAG, "ERROR: Couldn't disconnect Audio for device " + mCurrentDevice); } break; case VOICE_RECOGNITION_START: if (mVoiceRecognitionActive == HeadsetClientHalConstants.VR_STATE_STOPPED) { if (NativeInterface.startVoiceRecognitionNative( if (mNativeInterface.startVoiceRecognition( getByteAddress(mCurrentDevice))) { addQueuedAction(VOICE_RECOGNITION_START); } else { Loading @@ -1126,7 +1135,7 @@ public class HeadsetClientStateMachine extends StateMachine { case VOICE_RECOGNITION_STOP: if (mVoiceRecognitionActive == HeadsetClientHalConstants.VR_STATE_STARTED) { if (NativeInterface.stopVoiceRecognitionNative( if (mNativeInterface.stopVoiceRecognition( getByteAddress(mCurrentDevice))) { addQueuedAction(VOICE_RECOGNITION_STOP); } else { Loading @@ -1135,6 +1144,13 @@ public class HeadsetClientStateMachine extends StateMachine { } break; case SEND_VENDOR_AT_COMMAND: { int vendorId = message.arg1; String atCommand = (String) (message.obj); mVendorProcessor.sendCommand(vendorId, atCommand, mCurrentDevice); break; } // Called only for Mute/Un-mute - Mic volume change is not allowed. case SET_MIC_VOLUME: break; Loading @@ -1146,7 +1162,7 @@ public class HeadsetClientStateMachine extends StateMachine { logD("Volume" + amVol + ":" + mCommandedSpeakerVolume); // Volume was changed by a 3rd party mCommandedSpeakerVolume = -1; if (NativeInterface.setVolumeNative(getByteAddress(mCurrentDevice), if (mNativeInterface.setVolume(getByteAddress(mCurrentDevice), HeadsetClientHalConstants.VOLUME_TYPE_SPK, hfVol)) { addQueuedAction(SET_SPEAKER_VOLUME); } Loading @@ -1157,7 +1173,7 @@ public class HeadsetClientStateMachine extends StateMachine { BluetoothHeadsetClientCall c = (BluetoothHeadsetClientCall) message.obj; mCalls.put(HF_ORIGINATED_CALL_ID, c); if (NativeInterface.dialNative(getByteAddress(mCurrentDevice), c.getNumber())) { if (mNativeInterface.dial(getByteAddress(mCurrentDevice), c.getNumber())) { addQueuedAction(DIAL_NUMBER, c.getNumber()); // Start looping on calling current calls. sendMessage(QUERY_CURRENT_CALLS); Loading Loading @@ -1189,7 +1205,7 @@ public class HeadsetClientStateMachine extends StateMachine { explicitCallTransfer(); break; case SEND_DTMF: if (NativeInterface.sendDtmfNative(getByteAddress(mCurrentDevice), if (mNativeInterface.sendDtmf(getByteAddress(mCurrentDevice), (byte) message.arg1)) { addQueuedAction(SEND_DTMF); } else { Loading @@ -1197,7 +1213,7 @@ public class HeadsetClientStateMachine extends StateMachine { } break; case SUBSCRIBER_INFO: if (NativeInterface.retrieveSubscriberInfoNative( if (mNativeInterface.retrieveSubscriberInfo( getByteAddress(mCurrentDevice))) { addQueuedAction(SUBSCRIBER_INFO); } else { Loading Loading @@ -1248,7 +1264,7 @@ public class HeadsetClientStateMachine extends StateMachine { if (mIndicatorNetworkState == HeadsetClientHalConstants.NETWORK_STATE_AVAILABLE) { if (NativeInterface.queryCurrentOperatorNameNative( if (mNativeInterface.queryCurrentOperatorName( getByteAddress(mCurrentDevice))) { addQueuedAction(QUERY_OPERATOR_NAME); } else { Loading Loading @@ -1385,6 +1401,12 @@ public class HeadsetClientStateMachine extends StateMachine { // implemented (by the client of this service). Use the // CALL_STATE_INCOMING (and similar) handle ringing. break; case StackEvent.EVENT_TYPE_UNKNOWN_EVENT: if (!mVendorProcessor.processEvent(event.valueString, event.device)) { Log.e(TAG, "Unknown event :" + event.valueString + " for device " + event.device); } break; default: Log.e(TAG, "Unknown stack event: " + event.type); break; Loading Loading @@ -1529,7 +1551,7 @@ public class HeadsetClientStateMachine extends StateMachine { * StackEvent.EVENT_TYPE_AUDIO_STATE_CHANGED, that triggers State * Machines state changing */ if (NativeInterface.disconnectAudioNative(getByteAddress(mCurrentDevice))) { if (mNativeInterface.disconnectAudio(getByteAddress(mCurrentDevice))) { routeHfpAudio(false); returnAudioFocusIfNecessary(); } Loading