Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3e4fde34 authored by Joseph Pirozzo's avatar Joseph Pirozzo Committed by android-build-merger
Browse files

Merge "HFP connect Audio" am: 1a7c0434 am: 48487fea

am: a97db01d

Change-Id: Icada4fafa400439072552d55a281008b417f476d
parents 5531baa5 a97db01d
Loading
Loading
Loading
Loading
+33 −13
Original line number Original line Diff line number Diff line
@@ -646,6 +646,24 @@ public class HeadsetClientService extends ProfileService {


    boolean acceptCall(BluetoothDevice device, int flag) {
    boolean acceptCall(BluetoothDevice device, int flag) {
        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
        /* Phonecalls from a single device are supported, hang up any calls on the other phone */
        synchronized (this) {
            for (Map.Entry<BluetoothDevice, HeadsetClientStateMachine> entry :
                    mStateMachineMap.entrySet()) {
                if (entry.getValue() == null) {
                    continue;
                }
                int connectionState = entry.getValue().getConnectionState(entry.getKey());
                if (DBG) {
                    Log.d(TAG, "Accepting a call on device " + device
                                    + ". Possibly disconnecting on " + entry.getValue());
                }
                if (connectionState == BluetoothProfile.STATE_CONNECTED)
                    entry.getValue()
                            .obtainMessage(HeadsetClientStateMachine.TERMINATE_CALL)
                            .sendToTarget();
            }
        }
        HeadsetClientStateMachine sm = getStateMachine(device);
        HeadsetClientStateMachine sm = getStateMachine(device);
        if (sm == null) {
        if (sm == null) {
            Log.e(TAG, "Cannot allocate SM for device " + device);
            Log.e(TAG, "Cannot allocate SM for device " + device);
@@ -653,8 +671,7 @@ public class HeadsetClientService extends ProfileService {
        }
        }


        int connectionState = sm.getConnectionState(device);
        int connectionState = sm.getConnectionState(device);
        if (connectionState != BluetoothProfile.STATE_CONNECTED &&
        if (connectionState != BluetoothProfile.STATE_CONNECTED) {
                connectionState != BluetoothProfile.STATE_CONNECTING) {
            return false;
            return false;
        }
        }
        Message msg = sm.obtainMessage(HeadsetClientStateMachine.ACCEPT_CALL);
        Message msg = sm.obtainMessage(HeadsetClientStateMachine.ACCEPT_CALL);
@@ -872,20 +889,23 @@ public class HeadsetClientService extends ProfileService {
        return sm;
        return sm;
    }
    }


    // Check if any of the state machines are currently holding the SCO audio stream
    // Check if any of the state machines have routed the SCO audio stream.
    // This function is *only* called from the SMs which are themselves run the same thread and
    synchronized boolean isScoRouted() {
    // hence we do not need synchronization here
        for (Map.Entry<BluetoothDevice, HeadsetClientStateMachine> entry :
    boolean isScoAvailable() {
                mStateMachineMap.entrySet()) {
        for (BluetoothDevice bd : mStateMachineMap.keySet()) {
            if (entry.getValue() != null) {
            HeadsetClientStateMachine sm = mStateMachineMap.get(bd);
                int audioState = entry.getValue().getAudioState(entry.getKey());
            int audioState = sm.getAudioState(bd);
                if (audioState == BluetoothHeadsetClient.STATE_AUDIO_CONNECTED) {
            if (audioState != BluetoothHeadsetClient.STATE_AUDIO_DISCONNECTED) {
                    if (DBG) {
                Log.w(TAG, "Device " + bd + " audio state " + audioState + " not disconnected");
                        Log.d(TAG, "Device " + entry.getKey() + " audio state " + audioState
                return false;
                                        + " Connected");
            }
                    }
                    }
                    return true;
                    return true;
                }
                }
            }
        }
        return false;
    }


    @Override
    @Override
    public synchronized void dump(StringBuilder sb) {
    public synchronized void dump(StringBuilder sb) {
+23 −6
Original line number Original line Diff line number Diff line
@@ -104,6 +104,8 @@ public class HeadsetClientStateMachine extends StateMachine {


    // Timeouts.
    // Timeouts.
    static final int CONNECTING_TIMEOUT_MS = 10000;  // 10s
    static final int CONNECTING_TIMEOUT_MS = 10000;  // 10s
    static final int ROUTING_DELAY_MS = 250;
    static final int SCO_DISCONNECT_TIMEOUT_MS = 750;


    static final int MAX_HFP_SCO_VOICE_CALL_VOLUME = 15; // HFP 1.5 spec.
    static final int MAX_HFP_SCO_VOICE_CALL_VOLUME = 15; // HFP 1.5 spec.
    static final int MIN_HFP_SCO_VOICE_CALL_VOLUME = 1; // HFP 1.5 spec.
    static final int MIN_HFP_SCO_VOICE_CALL_VOLUME = 1; // HFP 1.5 spec.
@@ -460,6 +462,8 @@ public class HeadsetClientStateMachine extends StateMachine {
                    action = HeadsetClientHalConstants.CALL_ACTION_CHLD_1;
                    action = HeadsetClientHalConstants.CALL_ACTION_CHLD_1;
                } else if (getCall(BluetoothHeadsetClientCall.CALL_STATE_ACTIVE) != null) {
                } else if (getCall(BluetoothHeadsetClientCall.CALL_STATE_ACTIVE) != null) {
                    action = HeadsetClientHalConstants.CALL_ACTION_CHLD_3;
                    action = HeadsetClientHalConstants.CALL_ACTION_CHLD_3;
                } else if (flag == BluetoothHeadsetClient.CALL_ACCEPT_NONE) {
                    action = HeadsetClientHalConstants.CALL_ACTION_CHLD_2;
                } else {
                } else {
                    action = HeadsetClientHalConstants.CALL_ACTION_CHLD_2;
                    action = HeadsetClientHalConstants.CALL_ACTION_CHLD_2;
                }
                }
@@ -581,6 +585,7 @@ public class HeadsetClientStateMachine extends StateMachine {
        if (c != null) {
        if (c != null) {
            if (NativeInterface.handleCallActionNative(getByteAddress(mCurrentDevice), action, 0)) {
            if (NativeInterface.handleCallActionNative(getByteAddress(mCurrentDevice), action, 0)) {
                addQueuedAction(TERMINATE_CALL, action);
                addQueuedAction(TERMINATE_CALL, action);
                sendMessageDelayed(DISCONNECT_AUDIO, SCO_DISCONNECT_TIMEOUT_MS);
            } else {
            } else {
                Log.e(TAG, "ERROR: Couldn't terminate outgoing call");
                Log.e(TAG, "ERROR: Couldn't terminate outgoing call");
            }
            }
@@ -1065,7 +1070,6 @@ public class HeadsetClientStateMachine extends StateMachine {
                    }
                    }


                    NativeInterface.connectNative(getByteAddress(device));
                    NativeInterface.connectNative(getByteAddress(device));
                    // deferMessage(message);
                    break;
                    break;
                case DISCONNECT:
                case DISCONNECT:
                    BluetoothDevice dev = (BluetoothDevice) message.obj;
                    BluetoothDevice dev = (BluetoothDevice) message.obj;
@@ -1083,11 +1087,8 @@ public class HeadsetClientStateMachine extends StateMachine {
                    break;
                    break;


                case CONNECT_AUDIO:
                case CONNECT_AUDIO:
                    if (!mService.isScoAvailable()
                    if (!NativeInterface.connectAudioNative(getByteAddress(mCurrentDevice))) {
                            || !NativeInterface.connectAudioNative(
                        Log.e(TAG, "ERROR: Couldn't connect Audio for device " + mCurrentDevice);
                                       getByteAddress(mCurrentDevice))) {
                        Log.e(TAG, "ERROR: Couldn't connect Audio for device " + mCurrentDevice
                                        + " isScoAvailable " + mService.isScoAvailable());
                        broadcastAudioState(mCurrentDevice,
                        broadcastAudioState(mCurrentDevice,
                                BluetoothHeadsetClient.STATE_AUDIO_DISCONNECTED,
                                BluetoothHeadsetClient.STATE_AUDIO_DISCONNECTED,
                                BluetoothHeadsetClient.STATE_AUDIO_DISCONNECTED);
                                BluetoothHeadsetClient.STATE_AUDIO_DISCONNECTED);
@@ -1398,6 +1399,16 @@ public class HeadsetClientStateMachine extends StateMachine {
                    // for routing and volume purposes.
                    // for routing and volume purposes.
                    // NOTE: All calls here are routed via the setParameters which changes the
                    // NOTE: All calls here are routed via the setParameters which changes the
                    // routing at the Audio HAL level.
                    // routing at the Audio HAL level.

                    if (mService.isScoRouted()) {
                        StackEvent event =
                                new StackEvent(StackEvent.EVENT_TYPE_AUDIO_STATE_CHANGED);
                        event.valueInt = state;
                        event.device = device;
                        sendMessageDelayed(StackEvent.STACK_EVENT, event, ROUTING_DELAY_MS);
                        break;
                    }

                    mAudioState = BluetoothHeadsetClient.STATE_AUDIO_CONNECTED;
                    mAudioState = BluetoothHeadsetClient.STATE_AUDIO_CONNECTED;


                    // We need to set the volume after switching into HFP mode as some Audio HALs
                    // We need to set the volume after switching into HFP mode as some Audio HALs
@@ -1501,6 +1512,11 @@ public class HeadsetClientStateMachine extends StateMachine {
                        mAudioManager.setParameters("hfp_enable=false");
                        mAudioManager.setParameters("hfp_enable=false");
                    }
                    }
                    break;
                    break;

                case HOLD_CALL:
                    holdCall();
                    break;

                case StackEvent.STACK_EVENT:
                case StackEvent.STACK_EVENT:
                    StackEvent event = (StackEvent) message.obj;
                    StackEvent event = (StackEvent) message.obj;
                    if (DBG) {
                    if (DBG) {
@@ -1561,6 +1577,7 @@ public class HeadsetClientStateMachine extends StateMachine {


            switch (state) {
            switch (state) {
                case HeadsetClientHalConstants.AUDIO_STATE_DISCONNECTED:
                case HeadsetClientHalConstants.AUDIO_STATE_DISCONNECTED:
                    removeMessages(DISCONNECT_AUDIO);
                    mAudioState = BluetoothHeadsetClient.STATE_AUDIO_DISCONNECTED;
                    mAudioState = BluetoothHeadsetClient.STATE_AUDIO_DISCONNECTED;
                    // Audio focus may still be held by the entity controlling the actual call
                    // Audio focus may still be held by the entity controlling the actual call
                    // (such as Telecom) and hence this will still keep the call around, there
                    // (such as Telecom) and hence this will still keep the call around, there
+2 −0
Original line number Original line Diff line number Diff line
@@ -81,6 +81,7 @@ public class HfpClientConnection extends Connection {
            return;
            return;
        }
        }


        mHeadsetProfile.connectAudio(device);
        setInitializing();
        setInitializing();
        setDialing();
        setDialing();
        finishInitializing();
        finishInitializing();
@@ -256,6 +257,7 @@ public class HfpClientConnection extends Connection {
        if (!mClosed) {
        if (!mClosed) {
            mHeadsetProfile.acceptCall(mDevice, BluetoothHeadsetClient.CALL_ACCEPT_NONE);
            mHeadsetProfile.acceptCall(mDevice, BluetoothHeadsetClient.CALL_ACCEPT_NONE);
        }
        }
        mHeadsetProfile.connectAudio(mDevice);
    }
    }


    @Override
    @Override