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

Commit e9d0909b authored by Deqiang Chen's avatar Deqiang Chen Committed by android-build-merger
Browse files

Refactor NativeInterace to wrap static native function as public non-static...

Refactor NativeInterace to wrap static native function as public non-static function am: 26337ca3 am: aed30c90 am: dcf16a46
am: ce175854

Change-Id: I718706792669bea273bcb91685760a4695ba3795
parents 126d687c ce175854
Loading
Loading
Loading
Loading
+4 −4
Original line number Diff line number Diff line
@@ -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) {
@@ -137,7 +137,7 @@ public class HeadsetClientService extends ProfileService {
        mSmThread.quit();
        mSmThread = null;

        mNativeInterface.cleanupNative();
        mNativeInterface.cleanup();
        mNativeInterface = null;

        return true;
@@ -885,7 +885,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;
    }
+34 −29
Original line number Diff line number Diff line
@@ -174,7 +174,8 @@ 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;

    // Accessor for the states, useful for reusing the state machines
    public IState getDisconnectedState() {
@@ -264,7 +265,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;
    }
@@ -487,7 +488,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);
@@ -526,8 +527,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);
@@ -551,7 +552,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);
@@ -572,7 +573,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");
@@ -590,7 +591,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 {
@@ -606,7 +607,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 {
@@ -659,9 +660,11 @@ 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();

        mAdapter = BluetoothAdapter.getDefaultAdapter();
@@ -699,9 +702,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;
    }
@@ -739,7 +744,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();
@@ -825,7 +830,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);
@@ -871,7 +876,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
@@ -985,7 +990,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;
                    }

@@ -993,7 +998,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);
@@ -1083,20 +1088,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,
@@ -1108,14 +1113,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 {
@@ -1126,7 +1131,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 {
@@ -1146,7 +1151,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);
                        }
@@ -1157,7 +1162,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);
@@ -1189,7 +1194,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 {
@@ -1197,7 +1202,7 @@ public class HeadsetClientStateMachine extends StateMachine {
                    }
                    break;
                case SUBSCRIBER_INFO:
                    if (NativeInterface.retrieveSubscriberInfoNative(
                    if (mNativeInterface.retrieveSubscriberInfo(
                            getByteAddress(mCurrentDevice))) {
                        addQueuedAction(SUBSCRIBER_INFO);
                    } else {
@@ -1248,7 +1253,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 {
@@ -1529,7 +1534,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();
                    }
+7 −2
Original line number Diff line number Diff line
@@ -20,7 +20,12 @@ import android.os.HandlerThread;

// Factory so that StateMachine objected can be mocked
public class HeadsetClientStateMachineFactory {
    public HeadsetClientStateMachine make(HeadsetClientService context, HandlerThread t) {
        return HeadsetClientStateMachine.make(context, t.getLooper());
    /**
     * Factory method to create state machine for headset client
     *
     */
    public HeadsetClientStateMachine make(HeadsetClientService context, HandlerThread t,
            NativeInterface nativeInterface) {
        return HeadsetClientStateMachine.make(context, t.getLooper(), nativeInterface);
    }
}
+247 −21
Original line number Diff line number Diff line
@@ -24,7 +24,14 @@ import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.util.Log;

class NativeInterface {
import com.android.internal.annotations.VisibleForTesting;

/**
 * Defines native calls that are used by state machine/service to either send or receive
 * messages to/from the native stack. This file is registered for the native methods in
 * corresponding CPP file.
 */
public class NativeInterface {
    private static final String TAG = "NativeInterface";
    private static final boolean DBG = false;

@@ -32,46 +39,265 @@ class NativeInterface {
        classInitNative();
    }

    NativeInterface() {}
    private NativeInterface() {}
    private static NativeInterface sInterface;
    private static final Object INSTANCE_LOCK = new Object();

    /**
     * This class is a singleton because native library should only be loaded once
     *
     * @return default instance
     */
    public static NativeInterface getInstance() {
        synchronized (INSTANCE_LOCK) {
            if (sInterface == null) {
                sInterface = new NativeInterface();
            }
        }
        return sInterface;
    }

    // Native wrappers to help unit testing
    /**
     * Initialize native stack
     */
    @VisibleForTesting
    public void initialize() {
        initializeNative();
    }

    /**
     * Close and clean up native stack
     */
    @VisibleForTesting
    public void cleanup() {
        cleanupNative();
    }

    /**
     * Connect to the specified paired device
     *
     * @param address target device's address
     * @return True on success, False on failure
     */
    @VisibleForTesting
    public boolean connect(byte[] address) {
        return connectNative(address);
    }

    /**
     * Disconnect from the specified paired device
     *
     * @param address target device's address
     * @return True on success, False on failure
     */
    @VisibleForTesting
    public boolean disconnect(byte[] address) {
        return disconnectNative(address);
    }

    /**
     * Initiate audio connection to the specified paired device
     *
     * @param address target device's address
     * @return True on success, False on failure
     */
    @VisibleForTesting
    public boolean connectAudio(byte[] address) {
        return connectAudioNative(address);
    }

    /**
     * Close audio connection from the specified paired device
     *
     * @param address target device's address
     * @return True on success, False on failure
     */
    public boolean disconnectAudio(byte[] address) {
        return disconnectAudioNative(address);
    }

    /**
     * Initiate voice recognition to the specified paired device
     *
     * @param address target device's address
     * @return True on success, False on failure
     */
    @VisibleForTesting
    public boolean startVoiceRecognition(byte[] address) {
        return startVoiceRecognitionNative(address);
    }

    /**
     * Close voice recognition to the specified paired device
     *
     * @param address target device's address
     * @return True on success, False on failure
     */
    @VisibleForTesting
    public boolean stopVoiceRecognition(byte[] address) {
        return stopVoiceRecognitionNative(address);
    }

    /**
     * Set volume to the specified paired device
     *
     * @param volumeType type of volume as in
     *                  HeadsetClientHalConstants.VOLUME_TYPE_xxxx
     * @param volume  volume level
     * @param address target device's address
     * @return True on success, False on failure
     */
    @VisibleForTesting
    public boolean setVolume(byte[] address, int volumeType, int volume) {
        return setVolumeNative(address, volumeType, volume);
    }

    /**
     * dial number from the specified paired device
     *
     * @param number  phone number to be dialed
     * @param address target device's address
     * @return True on success, False on failure
     */
    @VisibleForTesting
    public boolean dial(byte[] address, String number) {
        return dialNative(address, number);
    }

    /**
     * Memory dialing from the specified paired device
     *
     * @param location  memory location
     * @param address target device's address
     * @return True on success, False on failure
     */
    @VisibleForTesting
    public boolean dialMemory(byte[] address, int location) {
        return dialMemoryNative(address, location);
    }

    /**
     * Apply action to call
     *
     * @action action (e.g. hold, terminate etc)
     * @index call index
     * @param address target device's address
     * @return True on success, False on failure
     */
    @VisibleForTesting
    public boolean handleCallAction(byte[] address, int action, int index) {
        return handleCallActionNative(address, action, index);
    }

    /**
     * Query current call status from the specified paired device
     *
     * @param address target device's address
     * @return True on success, False on failure
     */
    @VisibleForTesting
    public boolean queryCurrentCalls(byte[] address) {
        return queryCurrentCallsNative(address);
    }

    /**
     * Query operator name from the specified paired device
     *
     * @param address target device's address
     * @return True on success, False on failure
     */
    @VisibleForTesting
    public boolean queryCurrentOperatorName(byte[] address) {
        return queryCurrentOperatorNameNative(address);
    }

    /**
     * Retrieve subscriber number from the specified paired device
     *
     * @param address target device's address
     * @return True on success, False on failure
     */
    @VisibleForTesting
    public  boolean retrieveSubscriberInfo(byte[] address) {
        return retrieveSubscriberInfoNative(address);
    }

    /**
     * Transmit DTMF code
     *
     * @param code DTMF code
     * @param address target device's address
     * @return True on success, False on failure
     */
    @VisibleForTesting
    public boolean sendDtmf(byte[] address, byte code) {
        return sendDtmfNative(address, code);
    }

    /**
     * Request last voice tag
     *
     * @param address target device's address
     * @return True on success, False on failure
     */
    @VisibleForTesting
    public boolean requestLastVoiceTagNumber(byte[] address) {
        return requestLastVoiceTagNumberNative(address);
    }

    /**
     * Send an AT command
     *
     * @param atCmd command code
     * @param val1 command specific argurment1
     * @param val2 command specific argurment2
     * @param arg other command specific argurments
     * @return True on success, False on failure
     */
    @VisibleForTesting
    public boolean sendATCmd(byte[] address, int atCmd, int val1, int val2, String arg) {
        return sendATCmdNative(address, atCmd, val1, val2, arg);
    }

    // Native methods that call into the JNI interface
    static native void classInitNative();
    private static native void classInitNative();

    native void initializeNative();
    private native void initializeNative();

    native void cleanupNative();
    private native void cleanupNative();

    static native boolean connectNative(byte[] address);
    private static native boolean connectNative(byte[] address);

    static native boolean disconnectNative(byte[] address);
    private static native boolean disconnectNative(byte[] address);

    static native boolean connectAudioNative(byte[] address);
    private static native boolean connectAudioNative(byte[] address);

    static native boolean disconnectAudioNative(byte[] address);
    private static native boolean disconnectAudioNative(byte[] address);

    static native boolean startVoiceRecognitionNative(byte[] address);
    private static native boolean startVoiceRecognitionNative(byte[] address);

    static native boolean stopVoiceRecognitionNative(byte[] address);
    private static native boolean stopVoiceRecognitionNative(byte[] address);

    static native boolean setVolumeNative(byte[] address, int volumeType, int volume);
    private static native boolean setVolumeNative(byte[] address, int volumeType, int volume);

    static native boolean dialNative(byte[] address, String number);
    private static native boolean dialNative(byte[] address, String number);

    static native boolean dialMemoryNative(byte[] address, int location);
    private static native boolean dialMemoryNative(byte[] address, int location);

    static native boolean handleCallActionNative(byte[] address, int action, int index);
    private static native boolean handleCallActionNative(byte[] address, int action, int index);

    static native boolean queryCurrentCallsNative(byte[] address);
    private static native boolean queryCurrentCallsNative(byte[] address);

    static native boolean queryCurrentOperatorNameNative(byte[] address);
    private static native boolean queryCurrentOperatorNameNative(byte[] address);

    static native boolean retrieveSubscriberInfoNative(byte[] address);
    private static native boolean retrieveSubscriberInfoNative(byte[] address);

    static native boolean sendDtmfNative(byte[] address, byte code);
    private static native boolean sendDtmfNative(byte[] address, byte code);

    static native boolean requestLastVoiceTagNumberNative(byte[] address);
    private static native boolean requestLastVoiceTagNumberNative(byte[] address);

    static native boolean sendATCmdNative(byte[] address, int atCmd, int val1, int val2,
    private static native boolean sendATCmdNative(byte[] address, int atCmd, int val1, int val2,
            String arg);

    private BluetoothDevice getDevice(byte[] address) {
+5 −1
Original line number Diff line number Diff line
@@ -53,6 +53,8 @@ public class HeadsetClientStateMachineTest {
    @Mock
    private AudioManager mAudioManager;

    private NativeInterface mNativeInterface;

    private static final int STANDARD_WAIT_MILLIS = 1000;
    private static final int QUERY_CURRENT_CALLS_WAIT_MILLIS = 2000;
    private static final int QUERY_CURRENT_CALLS_TEST_WAIT_MILLIS = QUERY_CURRENT_CALLS_WAIT_MILLIS
@@ -73,6 +75,7 @@ public class HeadsetClientStateMachineTest {
                mAudioManager);
        when(mHeadsetClientService.getResources()).thenReturn(mMockHfpResources);
        when(mMockHfpResources.getBoolean(R.bool.hfp_clcc_poll_during_call)).thenReturn(true);
        mNativeInterface = spy(NativeInterface.getInstance());

        // This line must be called to make sure relevant objects are initialized properly
        mAdapter = BluetoothAdapter.getDefaultAdapter();
@@ -84,7 +87,8 @@ public class HeadsetClientStateMachineTest {
        mHandlerThread.start();
        // Manage looper execution in main test thread explicitly to guarantee timing consistency
        mHeadsetClientStateMachine =
                new HeadsetClientStateMachine(mHeadsetClientService, mHandlerThread.getLooper());
                new HeadsetClientStateMachine(mHeadsetClientService, mHandlerThread.getLooper(),
                                              mNativeInterface);
        mHeadsetClientStateMachine.start();
    }