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

Commit b0fc59df authored by Sal Savage's avatar Sal Savage
Browse files

Remove HFP Client Connection Service's usage of BluetoothHeadsetClient

Currently, the HFP Client Connection Service uses the
BluetoothHeadsetClient profile proxy to get the HFP Client Service to do
things like accept calls, hang up, etc. This proxy exposes a surface we
don't need to expose outside of the Bluetooth stack, and causes calls to
leave the stack and come back.

The HFP Client Connection Service is now a singleton started by the HFP
Client Service itself. The HFP Client Service is also a singleton that
we can get an instance of to invoke functions directly against.

This change makes the connection service invoke things directly against
the HFP Client Service.

Tag: #refactor
Bug: 206035301
Test: atest BluetoothInstrumentationTests
Change-Id: Ic7d003108f1b8ca8d83b77a12b10190621a92769
parent a807315f
Loading
Loading
Loading
Loading
+26 −14
Original line number Original line Diff line number Diff line
@@ -48,6 +48,7 @@ import java.util.Iterator;
import java.util.List;
import java.util.List;
import java.util.Map;
import java.util.Map;
import java.util.Objects;
import java.util.Objects;
import java.util.Set;
import java.util.UUID;
import java.util.UUID;


/**
/**
@@ -668,7 +669,7 @@ public class HeadsetClientService extends ProfileService {
                HeadsetClientService service = getService(source);
                HeadsetClientService service = getService(source);
                Bundle defaultValue = null;
                Bundle defaultValue = null;
                if (service != null) {
                if (service != null) {
                    defaultValue = service.getCurrentAgFeatures(device);
                    defaultValue = service.getCurrentAgFeaturesBundle(device);
                }
                }
                receiver.send(defaultValue);
                receiver.send(defaultValue);
            } catch (RuntimeException e) {
            } catch (RuntimeException e) {
@@ -677,8 +678,6 @@ public class HeadsetClientService extends ProfileService {
        }
        }
    }
    }


    ;

    // API methods
    // API methods
    public static synchronized HeadsetClientService getHeadsetClientService() {
    public static synchronized HeadsetClientService getHeadsetClientService() {
        if (sHeadsetClientService == null) {
        if (sHeadsetClientService == null) {
@@ -902,7 +901,7 @@ public class HeadsetClientService extends ProfileService {
        return false;
        return false;
    }
    }


    boolean connectAudio(BluetoothDevice device) {
    public boolean connectAudio(BluetoothDevice device) {
        HeadsetClientStateMachine sm = getStateMachine(device);
        HeadsetClientStateMachine sm = getStateMachine(device);
        if (sm == null) {
        if (sm == null) {
            Log.e(TAG, "SM does not exist for device " + device);
            Log.e(TAG, "SM does not exist for device " + device);
@@ -919,7 +918,7 @@ public class HeadsetClientService extends ProfileService {
        return true;
        return true;
    }
    }


    boolean disconnectAudio(BluetoothDevice device) {
    public boolean disconnectAudio(BluetoothDevice device) {
        HeadsetClientStateMachine sm = getStateMachine(device);
        HeadsetClientStateMachine sm = getStateMachine(device);
        if (sm == null) {
        if (sm == null) {
            Log.e(TAG, "SM does not exist for device " + device);
            Log.e(TAG, "SM does not exist for device " + device);
@@ -933,7 +932,7 @@ public class HeadsetClientService extends ProfileService {
        return true;
        return true;
    }
    }


    boolean holdCall(BluetoothDevice device) {
    public boolean holdCall(BluetoothDevice device) {
        HeadsetClientStateMachine sm = getStateMachine(device);
        HeadsetClientStateMachine sm = getStateMachine(device);
        if (sm == null) {
        if (sm == null) {
            Log.e(TAG, "SM does not exist for device " + device);
            Log.e(TAG, "SM does not exist for device " + device);
@@ -950,7 +949,7 @@ public class HeadsetClientService extends ProfileService {
        return true;
        return true;
    }
    }


    boolean acceptCall(BluetoothDevice device, int flag) {
    public boolean acceptCall(BluetoothDevice device, int flag) {
        /* Phonecalls from a single device are supported, hang up any calls on the other phone */
        /* Phonecalls from a single device are supported, hang up any calls on the other phone */
        synchronized (mStateMachineMap) {
        synchronized (mStateMachineMap) {
            for (Map.Entry<BluetoothDevice, HeadsetClientStateMachine> entry : mStateMachineMap
            for (Map.Entry<BluetoothDevice, HeadsetClientStateMachine> entry : mStateMachineMap
@@ -987,7 +986,7 @@ public class HeadsetClientService extends ProfileService {
        return true;
        return true;
    }
    }


    boolean rejectCall(BluetoothDevice device) {
    public boolean rejectCall(BluetoothDevice device) {
        HeadsetClientStateMachine sm = getStateMachine(device);
        HeadsetClientStateMachine sm = getStateMachine(device);
        if (sm == null) {
        if (sm == null) {
            Log.e(TAG, "SM does not exist for device " + device);
            Log.e(TAG, "SM does not exist for device " + device);
@@ -1005,7 +1004,7 @@ public class HeadsetClientService extends ProfileService {
        return true;
        return true;
    }
    }


    boolean terminateCall(BluetoothDevice device, UUID uuid) {
    public boolean terminateCall(BluetoothDevice device, UUID uuid) {
        HeadsetClientStateMachine sm = getStateMachine(device);
        HeadsetClientStateMachine sm = getStateMachine(device);
        if (sm == null) {
        if (sm == null) {
            Log.e(TAG, "SM does not exist for device " + device);
            Log.e(TAG, "SM does not exist for device " + device);
@@ -1024,7 +1023,7 @@ public class HeadsetClientService extends ProfileService {
        return true;
        return true;
    }
    }


    boolean enterPrivateMode(BluetoothDevice device, int index) {
    public boolean enterPrivateMode(BluetoothDevice device, int index) {
        HeadsetClientStateMachine sm = getStateMachine(device);
        HeadsetClientStateMachine sm = getStateMachine(device);
        if (sm == null) {
        if (sm == null) {
            Log.e(TAG, "SM does not exist for device " + device);
            Log.e(TAG, "SM does not exist for device " + device);
@@ -1043,7 +1042,7 @@ public class HeadsetClientService extends ProfileService {
        return true;
        return true;
    }
    }


    BluetoothHeadsetClientCall dial(BluetoothDevice device, String number) {
    public BluetoothHeadsetClientCall dial(BluetoothDevice device, String number) {
        HeadsetClientStateMachine sm = getStateMachine(device);
        HeadsetClientStateMachine sm = getStateMachine(device);
        if (sm == null) {
        if (sm == null) {
            Log.e(TAG, "SM does not exist for device " + device);
            Log.e(TAG, "SM does not exist for device " + device);
@@ -1058,7 +1057,7 @@ public class HeadsetClientService extends ProfileService {


        BluetoothHeadsetClientCall call = new BluetoothHeadsetClientCall(device,
        BluetoothHeadsetClientCall call = new BluetoothHeadsetClientCall(device,
                HeadsetClientStateMachine.HF_ORIGINATED_CALL_ID,
                HeadsetClientStateMachine.HF_ORIGINATED_CALL_ID,
                BluetoothHeadsetClientCall.CALL_STATE_DIALING, number, false  /* multiparty */,
                HeadsetClientHalConstants.CALL_STATE_DIALING, number, false  /* multiparty */,
                true  /* outgoing */, sm.getInBandRing());
                true  /* outgoing */, sm.getInBandRing());
        Message msg = sm.obtainMessage(HeadsetClientStateMachine.DIAL_NUMBER);
        Message msg = sm.obtainMessage(HeadsetClientStateMachine.DIAL_NUMBER);
        msg.obj = call;
        msg.obj = call;
@@ -1152,7 +1151,20 @@ public class HeadsetClientService extends ProfileService {
        return sm.getCurrentAgEvents();
        return sm.getCurrentAgEvents();
    }
    }


    public Bundle getCurrentAgFeatures(BluetoothDevice device) {
    public Bundle getCurrentAgFeaturesBundle(BluetoothDevice device) {
        HeadsetClientStateMachine sm = getStateMachine(device);
        if (sm == null) {
            Log.e(TAG, "SM does not exist for device " + device);
            return null;
        }
        int connectionState = sm.getConnectionState(device);
        if (connectionState != BluetoothProfile.STATE_CONNECTED) {
            return null;
        }
        return sm.getCurrentAgFeaturesBundle();
    }

    public Set<Integer> getCurrentAgFeatures(BluetoothDevice device) {
        HeadsetClientStateMachine sm = getStateMachine(device);
        HeadsetClientStateMachine sm = getStateMachine(device);
        if (sm == null) {
        if (sm == null) {
            Log.e(TAG, "SM does not exist for device " + device);
            Log.e(TAG, "SM does not exist for device " + device);
@@ -1269,7 +1281,7 @@ public class HeadsetClientService extends ProfileService {
                    .entrySet()) {
                    .entrySet()) {
                if (entry.getValue() != null) {
                if (entry.getValue() != null) {
                    int audioState = entry.getValue().getAudioState(entry.getKey());
                    int audioState = entry.getValue().getAudioState(entry.getKey());
                    if (audioState == BluetoothHeadsetClient.STATE_AUDIO_CONNECTED) {
                    if (audioState == HeadsetClientHalConstants.AUDIO_STATE_CONNECTED) {
                        if (DBG) {
                        if (DBG) {
                            Log.d(TAG, "Device " + entry.getKey() + " audio state " + audioState
                            Log.d(TAG, "Device " + entry.getKey() + " audio state " + audioState
                                    + " Connected");
                                    + " Connected");
+41 −1
Original line number Original line Diff line number Diff line
@@ -720,7 +720,7 @@ public class HeadsetClientStateMachine extends StateMachine {
        }
        }
    }
    }


    public Bundle getCurrentAgFeatures() {
    public Bundle getCurrentAgFeaturesBundle() {
        Bundle b = new Bundle();
        Bundle b = new Bundle();
        if ((mPeerFeatures & HeadsetClientHalConstants.PEER_FEAT_3WAY)
        if ((mPeerFeatures & HeadsetClientHalConstants.PEER_FEAT_3WAY)
                == HeadsetClientHalConstants.PEER_FEAT_3WAY) {
                == HeadsetClientHalConstants.PEER_FEAT_3WAY) {
@@ -765,6 +765,46 @@ public class HeadsetClientStateMachine extends StateMachine {
        return b;
        return b;
    }
    }


    public Set<Integer> getCurrentAgFeatures() {
        HashSet<Integer> features = new HashSet<>();

        if (isSupported(mPeerFeatures, HeadsetClientHalConstants.PEER_FEAT_3WAY)) {
            features.add(HeadsetClientHalConstants.PEER_FEAT_3WAY);
        }
        if (isSupported(mPeerFeatures, HeadsetClientHalConstants.PEER_FEAT_VREC)) {
            features.add(HeadsetClientHalConstants.PEER_FEAT_VREC);
        }
        if (isSupported(mPeerFeatures, HeadsetClientHalConstants.PEER_FEAT_REJECT)) {
            features.add(HeadsetClientHalConstants.PEER_FEAT_REJECT);
        }
        if (isSupported(mPeerFeatures, HeadsetClientHalConstants.PEER_FEAT_ECC)) {
            features.add(HeadsetClientHalConstants.PEER_FEAT_ECC);
        }

        // add individual CHLD support extras
        if (isSupported(mChldFeatures, HeadsetClientHalConstants.CHLD_FEAT_HOLD_ACC)) {
            features.add(HeadsetClientHalConstants.CHLD_FEAT_HOLD_ACC);
        }
        if (isSupported(mChldFeatures, HeadsetClientHalConstants.CHLD_FEAT_REL)) {
            features.add(HeadsetClientHalConstants.CHLD_FEAT_REL);
        }
        if (isSupported(mChldFeatures, HeadsetClientHalConstants.CHLD_FEAT_REL_ACC)) {
            features.add(HeadsetClientHalConstants.CHLD_FEAT_REL_ACC);
        }
        if (isSupported(mChldFeatures, HeadsetClientHalConstants.CHLD_FEAT_MERGE)) {
            features.add(HeadsetClientHalConstants.CHLD_FEAT_MERGE);
        }
        if (isSupported(mChldFeatures, HeadsetClientHalConstants.CHLD_FEAT_MERGE_DETACH)) {
            features.add(HeadsetClientHalConstants.CHLD_FEAT_MERGE_DETACH);
        }

        return features;
    }

    private boolean isSupported(int bitfield, int mask) {
        return (bitfield & mask) == mask;
    }

    HeadsetClientStateMachine(HeadsetClientService context, Looper looper,
    HeadsetClientStateMachine(HeadsetClientService context, Looper looper,
                              NativeInterface nativeInterface) {
                              NativeInterface nativeInterface) {
        super(TAG, looper);
        super(TAG, looper);
+133 −0
Original line number Original line Diff line number Diff line
@@ -17,112 +17,117 @@
package com.android.bluetooth.hfpclient;
package com.android.bluetooth.hfpclient;


import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothHeadsetClient;
import android.bluetooth.BluetoothHeadsetClientCall;
import android.bluetooth.BluetoothHeadsetClientCall;
import android.os.Bundle;
import android.os.Bundle;

import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;


import java.util.List;
import java.util.List;
import java.util.Set;


/**
/**
 * A mockable proxy class that facilitates testing of the {@code hfpclient.connserv} package.
 * Interface for talking to the HeadsetClientService
 *
 *
 * <p>This is necessary due to the "final" attribute of the BluetoothHeadsetClient class.
 * Deals with service lifecycle and returns consistent error values
 */
 */
public class BluetoothHeadsetClientProxy {
public class HeadsetClientServiceInterface {
    private static final String TAG = "HeadsetClientServiceInterface";


    private final BluetoothHeadsetClient mBluetoothHeadsetClient;
    /* Action policy for other calls when accepting call */
    public static final int CALL_ACCEPT_NONE = 0;
    public static final int CALL_ACCEPT_HOLD = 1;
    public static final int CALL_ACCEPT_TERMINATE = 2;


    private BluetoothHeadsetClientProxy(BluetoothHeadsetClient bluetoothHeadsetClient) {
    public HeadsetClientServiceInterface() {
        mBluetoothHeadsetClient = bluetoothHeadsetClient;
    }
    }


    public BluetoothHeadsetClient getProxiedBluetoothHeadsetClient() {
    private boolean isServiceAvailable(HeadsetClientService service) {
        return mBluetoothHeadsetClient;
        if (service == null) {
            Log.w(TAG, "HeadsetClientService is not available");
            return false;
        }
        return true;
    }
    }


    /** @see BluetoothHeadsetClient#dial(BluetoothDevice, String) */
    public BluetoothHeadsetClientCall dial(BluetoothDevice device, String number) {
    public BluetoothHeadsetClientCall dial(BluetoothDevice device, String number) {
        return mBluetoothHeadsetClient.dial(device, number);
        HeadsetClientService service = HeadsetClientService.getHeadsetClientService();
        if (!isServiceAvailable(service)) return null;
        return service.dial(device, number);
    }
    }


    /** @see BluetoothHeadsetClient#enterPrivateMode(BluetoothDevice, int) */
    public boolean enterPrivateMode(BluetoothDevice device, int index) {
    public boolean enterPrivateMode(BluetoothDevice device, int index) {
        return mBluetoothHeadsetClient.enterPrivateMode(device, index);
        HeadsetClientService service = HeadsetClientService.getHeadsetClientService();
        if (!isServiceAvailable(service)) return false;
        return service.enterPrivateMode(device, index);
    }
    }


    /** @see BluetoothHeadsetClient#sendDTMF(BluetoothDevice, byte) */
    public boolean sendDTMF(BluetoothDevice device, byte code) {
    public boolean sendDTMF(BluetoothDevice device, byte code) {
        return mBluetoothHeadsetClient.sendDTMF(device, code);
        HeadsetClientService service = HeadsetClientService.getHeadsetClientService();
        if (!isServiceAvailable(service)) return false;
        return service.sendDTMF(device, code);
    }
    }


    /** @see BluetoothHeadsetClient#terminateCall(BluetoothDevice, BluetoothHeadsetClientCall) */
    public boolean terminateCall(BluetoothDevice device, BluetoothHeadsetClientCall call) {
    public boolean terminateCall(BluetoothDevice device, BluetoothHeadsetClientCall call) {
        return mBluetoothHeadsetClient.terminateCall(device, call);
        HeadsetClientService service = HeadsetClientService.getHeadsetClientService();
        if (!isServiceAvailable(service)) return false;
        return service.terminateCall(device, call != null ? call.getUUID() : null);
    }
    }


    /** @see BluetoothHeadsetClient#holdCall(BluetoothDevice) */
    public boolean holdCall(BluetoothDevice device) {
    public boolean holdCall(BluetoothDevice device) {
        return mBluetoothHeadsetClient.holdCall(device);
        HeadsetClientService service = HeadsetClientService.getHeadsetClientService();
        if (!isServiceAvailable(service)) return false;
        return service.holdCall(device);
    }
    }


    /** @see BluetoothHeadsetClient#acceptCall(BluetoothDevice, int) */
    public boolean acceptCall(BluetoothDevice device, int flag) {
    public boolean acceptCall(BluetoothDevice device, int flag) {
        return mBluetoothHeadsetClient.acceptCall(device, flag);
        HeadsetClientService service = HeadsetClientService.getHeadsetClientService();
        if (!isServiceAvailable(service)) return false;
        return service.acceptCall(device, flag);
    }
    }


    /** @see BluetoothHeadsetClient#rejectCall(BluetoothDevice) */
    public boolean rejectCall(BluetoothDevice device) {
    public boolean rejectCall(BluetoothDevice device) {
        return mBluetoothHeadsetClient.rejectCall(device);
        HeadsetClientService service = HeadsetClientService.getHeadsetClientService();
        if (!isServiceAvailable(service)) return false;
        return service.rejectCall(device);
    }
    }


    /** @see BluetoothHeadsetClient#connectAudio(BluetoothDevice) */
    public boolean connectAudio(BluetoothDevice device) {
    public boolean connectAudio(BluetoothDevice device) {
        return mBluetoothHeadsetClient.connectAudio(device);
        HeadsetClientService service = HeadsetClientService.getHeadsetClientService();
        if (!isServiceAvailable(service)) return false;
        return service.connectAudio(device);
    }
    }


    /** @see BluetoothHeadsetClient#disconnectAudio(BluetoothDevice) */
    public boolean disconnectAudio(BluetoothDevice device) {
    public boolean disconnectAudio(BluetoothDevice device) {
        return mBluetoothHeadsetClient.disconnectAudio(device);
        HeadsetClientService service = HeadsetClientService.getHeadsetClientService();
        if (!isServiceAvailable(service)) return false;
        return service.disconnectAudio(device);
    }

    public Set<Integer> getCurrentAgFeatures(BluetoothDevice device) {
        HeadsetClientService service = HeadsetClientService.getHeadsetClientService();
        if (!isServiceAvailable(service)) return null;
        return service.getCurrentAgFeatures(device);
    }
    }


    /** @see BluetoothHeadsetClient#getCurrentAgEvents(BluetoothDevice) */
    public Bundle getCurrentAgEvents(BluetoothDevice device) {
    public Bundle getCurrentAgEvents(BluetoothDevice device) {
        return mBluetoothHeadsetClient.getCurrentAgEvents(device);
        HeadsetClientService service = HeadsetClientService.getHeadsetClientService();
        if (!isServiceAvailable(service)) return null;
        return service.getCurrentAgEvents(device);
    }
    }


    /** @see BluetoothHeadsetClient#getConnectedDevices() */
    public List<BluetoothDevice> getConnectedDevices() {
    public List<BluetoothDevice> getConnectedDevices() {
        return mBluetoothHeadsetClient.getConnectedDevices();
        HeadsetClientService service = HeadsetClientService.getHeadsetClientService();
        if (!isServiceAvailable(service)) return null;
        return service.getConnectedDevices();
    }
    }


    /** @see BluetoothHeadsetClient#getCurrentCalls(BluetoothDevice) */
    public List<BluetoothHeadsetClientCall> getCurrentCalls(BluetoothDevice device) {
    public List<BluetoothHeadsetClientCall> getCurrentCalls(BluetoothDevice device) {
        return mBluetoothHeadsetClient.getCurrentCalls(device);
        HeadsetClientService service = HeadsetClientService.getHeadsetClientService();
    }
        if (!isServiceAvailable(service)) return null;

        return service.getCurrentCalls(device);
    /**
     * Factory class for {@link BluetoothHeadsetClientProxy}
     */
    public static class Factory {
        private static Factory sInstance = new Factory();

        @VisibleForTesting
        static void setInstance(Factory instance) {
            sInstance = instance;
        }

        /**
         * Returns an instance of {@link BluetoothHeadsetClientProxy}
         */
        public static BluetoothHeadsetClientProxy build(BluetoothHeadsetClient proxy) {
            return sInstance.buildInternal(proxy);
        }

        protected BluetoothHeadsetClientProxy buildInternal(BluetoothHeadsetClient proxy) {
            return  new BluetoothHeadsetClientProxy(proxy);
    }
    }


    public boolean hasHfpClientEcc(BluetoothDevice device) {
        Set<Integer> features = getCurrentAgFeatures(device);
        return features != null && features.contains(HeadsetClientHalConstants.PEER_FEAT_ECC);
    }
    }
}
}
+11 −14
Original line number Original line Diff line number Diff line
@@ -16,7 +16,6 @@
package com.android.bluetooth.hfpclient;
package com.android.bluetooth.hfpclient;


import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothHeadsetClient;
import android.telecom.Conference;
import android.telecom.Conference;
import android.telecom.Connection;
import android.telecom.Connection;
import android.telecom.PhoneAccountHandle;
import android.telecom.PhoneAccountHandle;
@@ -25,15 +24,15 @@ import android.util.Log;
public class HfpClientConference extends Conference {
public class HfpClientConference extends Conference {
    private static final String TAG = "HfpClientConference";
    private static final String TAG = "HfpClientConference";


    private BluetoothDevice mDevice;
    private final BluetoothDevice mDevice;
    private BluetoothHeadsetClientProxy mHeadsetProfile;
    private final HeadsetClientServiceInterface mServiceInterface;


    public HfpClientConference(PhoneAccountHandle handle, BluetoothDevice device,
    public HfpClientConference(BluetoothDevice device, PhoneAccountHandle handle,
            BluetoothHeadsetClientProxy client) {
            HeadsetClientServiceInterface serviceInterface) {
        super(handle);
        super(handle);
        mDevice = device;
        mDevice = device;
        mHeadsetProfile = client;
        mServiceInterface = serviceInterface;
        boolean manage = HfpClientConnectionService.hasHfpClientEcc(client, device);
        boolean manage = mServiceInterface.hasHfpClientEcc(device);
        setConnectionCapabilities(
        setConnectionCapabilities(
                Connection.CAPABILITY_SUPPORT_HOLD | Connection.CAPABILITY_HOLD | (manage
                Connection.CAPABILITY_SUPPORT_HOLD | Connection.CAPABILITY_HOLD | (manage
                        ? Connection.CAPABILITY_MANAGE_CONFERENCE : 0));
                        ? Connection.CAPABILITY_MANAGE_CONFERENCE : 0));
@@ -43,7 +42,7 @@ public class HfpClientConference extends Conference {
    @Override
    @Override
    public void onDisconnect() {
    public void onDisconnect() {
        Log.d(TAG, "onDisconnect");
        Log.d(TAG, "onDisconnect");
        mHeadsetProfile.terminateCall(mDevice, null);
        mServiceInterface.terminateCall(mDevice, null);
    }
    }


    @Override
    @Override
@@ -62,21 +61,19 @@ public class HfpClientConference extends Conference {
    @Override
    @Override
    public void onHold() {
    public void onHold() {
        Log.d(TAG, "onHold");
        Log.d(TAG, "onHold");
        mHeadsetProfile.holdCall(mDevice);
        mServiceInterface.holdCall(mDevice);
    }
    }


    @Override
    @Override
    public void onUnhold() {
    public void onUnhold() {
        Log.d(TAG, "onUnhold");
        Log.d(TAG, "onUnhold");
        mHeadsetProfile.acceptCall(mDevice, BluetoothHeadsetClient.CALL_ACCEPT_HOLD);
        mServiceInterface.acceptCall(mDevice, HeadsetClientServiceInterface.CALL_ACCEPT_HOLD);
    }
    }


    @Override
    @Override
    public void onPlayDtmfTone(char c) {
    public void onPlayDtmfTone(char c) {
        Log.d(TAG, "onPlayDtmfTone " + c);
        Log.d(TAG, "onPlayDtmfTone " + c);
        if (mHeadsetProfile != null) {
        mServiceInterface.sendDTMF(mDevice, (byte) c);
            mHeadsetProfile.sendDTMF(mDevice, (byte) c);
        }
    }
    }


    @Override
    @Override
@@ -87,7 +84,7 @@ public class HfpClientConference extends Conference {
            connection.onAnswer();
            connection.onAnswer();
        } else if (connection.getState() == Connection.STATE_ACTIVE
        } else if (connection.getState() == Connection.STATE_ACTIVE
                && getState() == Connection.STATE_HOLDING) {
                && getState() == Connection.STATE_HOLDING) {
            mHeadsetProfile.acceptCall(mDevice, BluetoothHeadsetClient.CALL_ACCEPT_NONE);
            mServiceInterface.acceptCall(mDevice, HeadsetClientServiceInterface.CALL_ACCEPT_NONE);
        }
        }
    }
    }
}
}
+29 −48
Original line number Original line Diff line number Diff line
@@ -16,9 +16,7 @@
package com.android.bluetooth.hfpclient;
package com.android.bluetooth.hfpclient;


import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothHeadsetClient;
import android.bluetooth.BluetoothHeadsetClientCall;
import android.bluetooth.BluetoothHeadsetClientCall;
import android.content.Context;
import android.net.Uri;
import android.net.Uri;
import android.os.Bundle;
import android.os.Bundle;
import android.telecom.Connection;
import android.telecom.Connection;
@@ -27,6 +25,7 @@ import android.telecom.PhoneAccount;
import android.telecom.TelecomManager;
import android.telecom.TelecomManager;
import android.util.Log;
import android.util.Log;


import java.util.Objects;
import java.util.UUID;
import java.util.UUID;


public class HfpClientConnection extends Connection {
public class HfpClientConnection extends Connection {
@@ -37,12 +36,11 @@ public class HfpClientConnection extends Connection {
    private static final String EVENT_SCO_DISCONNECT =
    private static final String EVENT_SCO_DISCONNECT =
             "com.android.bluetooth.hfpclient.SCO_DISCONNECT";
             "com.android.bluetooth.hfpclient.SCO_DISCONNECT";


    private final Context mContext;
    private final BluetoothDevice mDevice;
    private final BluetoothDevice mDevice;
    private BluetoothHeadsetClientProxy mHeadsetProfile;
    private HfpClientConnectionService mHfpClientConnectionService;

    private BluetoothHeadsetClientCall mCurrentCall;
    private BluetoothHeadsetClientCall mCurrentCall;
    private final HfpClientConnectionService mConnServ;
    private final HeadsetClientServiceInterface mServiceInterface;

    private int mPreviousCallState = -1;
    private int mPreviousCallState = -1;
    private boolean mClosed;
    private boolean mClosed;
    private boolean mClosing = false;
    private boolean mClosing = false;
@@ -52,34 +50,25 @@ public class HfpClientConnection extends Connection {


    // Constructor to be used when there's an existing call (such as that created on the AG or
    // Constructor to be used when there's an existing call (such as that created on the AG or
    // when connection happens and we see calls for the first time).
    // when connection happens and we see calls for the first time).
    public HfpClientConnection(Context context, BluetoothDevice device,
    public HfpClientConnection(BluetoothDevice device, BluetoothHeadsetClientCall call,
            BluetoothHeadsetClientProxy client, BluetoothHeadsetClientCall call) {
            HfpClientConnectionService connServ, HeadsetClientServiceInterface serviceInterface) {
        mDevice = device;
        mDevice = device;
        mContext = context;
        mConnServ = connServ;
        mHeadsetProfile = client;
        mServiceInterface = serviceInterface;

        mCurrentCall = Objects.requireNonNull(call);
        if (call == null) {
            throw new IllegalStateException("Call is null");
        }


        mCurrentCall = call;
        handleCallChanged();
        handleCallChanged();
        finishInitializing();
        finishInitializing();
    }
    }


    // Constructor to be used when a call is intiated on the HF. The call handle is obtained by
    // Constructor to be used when a call is intiated on the HF. The call handle is obtained by
    // using the dial() command.
    // using the dial() command.
    public HfpClientConnection(Context context, BluetoothDevice device,
    public HfpClientConnection(BluetoothDevice device, Uri number,
            BluetoothHeadsetClientProxy client, Uri number) {
            HfpClientConnectionService connServ, HeadsetClientServiceInterface serviceInterface) {
        mDevice = device;
        mDevice = device;
        mContext = context;
        mConnServ = connServ;
        mHeadsetProfile = client;
        mServiceInterface = serviceInterface;

        mCurrentCall = mServiceInterface.dial(mDevice, number.getSchemeSpecificPart());
        if (mHeadsetProfile == null) {
            throw new IllegalStateException("HeadsetProfile is null, returning");
        }

        mCurrentCall = mHeadsetProfile.dial(mDevice, number.getSchemeSpecificPart());
        if (mCurrentCall == null) {
        if (mCurrentCall == null) {
            close(DisconnectCause.ERROR);
            close(DisconnectCause.ERROR);
            Log.e(TAG, "Failed to create the call, dial failed.");
            Log.e(TAG, "Failed to create the call, dial failed.");
@@ -92,7 +81,7 @@ public class HfpClientConnection extends Connection {
    }
    }


    void finishInitializing() {
    void finishInitializing() {
        mClientHasEcc = HfpClientConnectionService.hasHfpClientEcc(mHeadsetProfile, mDevice);
        mClientHasEcc = mServiceInterface.hasHfpClientEcc(mDevice);
        setAudioModeIsVoip(false);
        setAudioModeIsVoip(false);
        Uri number = Uri.fromParts(PhoneAccount.SCHEME_TEL, mCurrentCall.getNumber(), null);
        Uri number = Uri.fromParts(PhoneAccount.SCHEME_TEL, mCurrentCall.getNumber(), null);
        setAddress(number, TelecomManager.PRESENTATION_ALLOWED);
        setAddress(number, TelecomManager.PRESENTATION_ALLOWED);
@@ -108,7 +97,6 @@ public class HfpClientConnection extends Connection {
    }
    }


    public void onHfpDisconnected() {
    public void onHfpDisconnected() {
        mHeadsetProfile = null;
        close(DisconnectCause.ERROR);
        close(DisconnectCause.ERROR);
    }
    }


@@ -126,7 +114,7 @@ public class HfpClientConnection extends Connection {
    }
    }


    public void enterPrivateMode() {
    public void enterPrivateMode() {
        mHeadsetProfile.enterPrivateMode(mDevice, mCurrentCall.getId());
        mServiceInterface.enterPrivateMode(mDevice, mCurrentCall.getId());
        setActive();
        setActive();
    }
    }


@@ -203,7 +191,7 @@ public class HfpClientConnection extends Connection {
        return mClosing;
        return mClosing;
    }
    }


    public synchronized BluetoothDevice getDevice() {
    public BluetoothDevice getDevice() {
        return mDevice;
        return mDevice;
    }
    }


@@ -213,7 +201,7 @@ public class HfpClientConnection extends Connection {
            Log.d(TAG, "onPlayDtmfTone " + c + " " + mCurrentCall);
            Log.d(TAG, "onPlayDtmfTone " + c + " " + mCurrentCall);
        }
        }
        if (!mClosed) {
        if (!mClosed) {
            mHeadsetProfile.sendDTMF(mDevice, (byte) c);
            mServiceInterface.sendDTMF(mDevice, (byte) c);
        }
        }
    }
    }


@@ -224,7 +212,7 @@ public class HfpClientConnection extends Connection {
        }
        }
        // The call is not closed so we should send a terminate here.
        // The call is not closed so we should send a terminate here.
        if (!mClosed) {
        if (!mClosed) {
            mHeadsetProfile.terminateCall(mDevice, mCurrentCall);
            mServiceInterface.terminateCall(mDevice, mCurrentCall);
            mLocalDisconnect = true;
            mLocalDisconnect = true;
            mClosing = true;
            mClosing = true;
        }
        }
@@ -244,13 +232,13 @@ public class HfpClientConnection extends Connection {
            Log.d(TAG, "onHold " + mCurrentCall);
            Log.d(TAG, "onHold " + mCurrentCall);
        }
        }
        if (!mClosed) {
        if (!mClosed) {
            mHeadsetProfile.holdCall(mDevice);
            mServiceInterface.holdCall(mDevice);
        }
        }
    }
    }


    @Override
    @Override
    public synchronized void onUnhold() {
    public synchronized void onUnhold() {
        if (getHfpClientConnectionService().getAllConnections().size() > 1) {
        if (mConnServ.getAllConnections().size() > 1) {
            Log.w(TAG, "Ignoring unhold; call hold on the foreground call");
            Log.w(TAG, "Ignoring unhold; call hold on the foreground call");
            return;
            return;
        }
        }
@@ -258,7 +246,7 @@ public class HfpClientConnection extends Connection {
            Log.d(TAG, "onUnhold " + mCurrentCall);
            Log.d(TAG, "onUnhold " + mCurrentCall);
        }
        }
        if (!mClosed) {
        if (!mClosed) {
            mHeadsetProfile.acceptCall(mDevice, BluetoothHeadsetClient.CALL_ACCEPT_HOLD);
            mServiceInterface.acceptCall(mDevice, HeadsetClientServiceInterface.CALL_ACCEPT_HOLD);
        }
        }
    }
    }


@@ -268,7 +256,7 @@ public class HfpClientConnection extends Connection {
            Log.d(TAG, "onAnswer " + mCurrentCall);
            Log.d(TAG, "onAnswer " + mCurrentCall);
        }
        }
        if (!mClosed) {
        if (!mClosed) {
            mHeadsetProfile.acceptCall(mDevice, BluetoothHeadsetClient.CALL_ACCEPT_NONE);
            mServiceInterface.acceptCall(mDevice, HeadsetClientServiceInterface.CALL_ACCEPT_NONE);
        }
        }
    }
    }


@@ -278,7 +266,7 @@ public class HfpClientConnection extends Connection {
            Log.d(TAG, "onReject " + mCurrentCall);
            Log.d(TAG, "onReject " + mCurrentCall);
        }
        }
        if (!mClosed) {
        if (!mClosed) {
            mHeadsetProfile.rejectCall(mDevice);
            mServiceInterface.rejectCall(mDevice);
        }
        }
    }
    }


@@ -287,12 +275,15 @@ public class HfpClientConnection extends Connection {
        if (DBG) {
        if (DBG) {
            Log.d(TAG, "onCallEvent(" + event + ", " + extras + ")");
            Log.d(TAG, "onCallEvent(" + event + ", " + extras + ")");
        }
        }
        if (mClosed) {
            return;
        }
        switch (event) {
        switch (event) {
            case EVENT_SCO_CONNECT:
            case EVENT_SCO_CONNECT:
                mHeadsetProfile.connectAudio(mDevice);
                mServiceInterface.connectAudio(mDevice);
                break;
                break;
            case EVENT_SCO_DISCONNECT:
            case EVENT_SCO_DISCONNECT:
                mHeadsetProfile.disconnectAudio(mDevice);
                mServiceInterface.disconnectAudio(mDevice);
                break;
                break;
        }
        }
    }
    }
@@ -311,14 +302,4 @@ public class HfpClientConnection extends Connection {
        return "HfpClientConnection{" + getAddress() + "," + stateToString(getState()) + ","
        return "HfpClientConnection{" + getAddress() + "," + stateToString(getState()) + ","
                + mCurrentCall + "}";
                + mCurrentCall + "}";
    }
    }

    public void setHfpClientConnectionService(
            HfpClientConnectionService hfpClientConnectionService) {
        mHfpClientConnectionService = hfpClientConnectionService;
    }

    public HfpClientConnectionService getHfpClientConnectionService() {
        return mHfpClientConnectionService;
    }

}
}
Loading