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

Commit 892858da authored by Sungsoo Lim's avatar Sungsoo Lim Committed by Android (Google) Code Review
Browse files

Merge changes If7ed622d,Id31e13a4,I2d384d53 into tm-qpr-dev

* changes:
  Add test for BassClientStateMachine#Connecting
  Add test for BassClientStateMachine#Disconnected
  Add more BassClientStateMachineTest
parents d9c26a0f fb0aeba1
Loading
Loading
Loading
Loading
+6 −40
Original line number Diff line number Diff line
@@ -152,7 +152,8 @@ public class BassClientStateMachine extends StateMachine {
    private final Connecting mConnecting = new Connecting();
    private final Disconnecting mDisconnecting = new Disconnecting();
    private final ConnectedProcessing mConnectedProcessing = new ConnectedProcessing();
    private final List<BluetoothGattCharacteristic> mBroadcastCharacteristics =
    @VisibleForTesting
    final List<BluetoothGattCharacteristic> mBroadcastCharacteristics =
            new ArrayList<BluetoothGattCharacteristic>();
    @VisibleForTesting
    BluetoothDevice mDevice;
@@ -182,7 +183,8 @@ public class BassClientStateMachine extends StateMachine {
    private PeriodicAdvertisingManager mPeriodicAdvManager;
    private boolean mAutoAssist = false;
    private boolean mAutoTriggered = false;
    private boolean mNoStopScanOffload = false;
    @VisibleForTesting
    boolean mNoStopScanOffload = false;
    private boolean mDefNoPAS = false;
    private boolean mForceSB = false;
    private int mBroadcastSourceIdLength = 3;
@@ -560,7 +562,8 @@ public class BassClientStateMachine extends StateMachine {
        mService.getCallbacks().notifyReceiveStateChanged(mDevice, sourceId, state);
    }

    private static boolean isEmpty(final byte[] data) {
    @VisibleForTesting
    static boolean isEmpty(final byte[] data) {
        return IntStream.range(0, data.length).parallel().allMatch(i -> data[i] == 0);
    }

@@ -1236,18 +1239,6 @@ public class BassClientStateMachine extends StateMachine {
        }
    }

    private byte[] bluetoothAddressToBytes(String s) {
        log("BluetoothAddressToBytes: input string:" + s);
        String[] splits = s.split(":");
        byte[] addressBytes = new byte[6];
        for (int i = 0; i < 6; i++) {
            int hexValue = Integer.parseInt(splits[i], 16);
            log("hexValue:" + hexValue);
            addressBytes[i] = (byte) hexValue;
        }
        return addressBytes;
    }

    private static int getBisSyncFromChannelPreference(
                List<BluetoothLeBroadcastChannel> channels) {
        int bisSync = 0;
@@ -1397,15 +1388,6 @@ public class BassClientStateMachine extends StateMachine {
        return res;
    }

    private byte[] convertAsciitoValues(byte[] val) {
        byte[] ret = new byte[val.length];
        for (int i = 0; i < val.length; i++) {
            ret[i] = (byte) (val[i] - (byte) '0');
        }
        log("convertAsciitoValues: returns:" + Arrays.toString(val));
        return ret;
    }

    private byte[] convertRecvStateToSetBroadcastCodeByteArray(
            BluetoothLeBroadcastReceiveState recvState) {
        byte[] res = new byte[BassConstants.PIN_CODE_CMD_LEN];
@@ -1995,22 +1977,6 @@ public class BassClientStateMachine extends StateMachine {
        return Integer.toString(what);
    }

    private static String profileStateToString(int state) {
        switch (state) {
            case BluetoothProfile.STATE_DISCONNECTED:
                return "DISCONNECTED";
            case BluetoothProfile.STATE_CONNECTING:
                return "CONNECTING";
            case BluetoothProfile.STATE_CONNECTED:
                return "CONNECTED";
            case BluetoothProfile.STATE_DISCONNECTING:
                return "DISCONNECTING";
            default:
                break;
        }
        return Integer.toString(state);
    }

    /**
     * Dump info
     */
+293 −18
Original line number Diff line number Diff line
@@ -18,11 +18,22 @@ package com.android.bluetooth.bass_client;

import static android.bluetooth.BluetoothGatt.GATT_SUCCESS;

import static com.android.bluetooth.bass_client.BassClientStateMachine.CONNECT;
import static com.android.bluetooth.bass_client.BassClientStateMachine.CONNECTION_STATE_CHANGED;
import static com.android.bluetooth.bass_client.BassClientStateMachine.CONNECT_TIMEOUT;
import static com.android.bluetooth.bass_client.BassClientStateMachine.DISCONNECT;
import static com.android.bluetooth.bass_client.BassClientStateMachine.PSYNC_ACTIVE_TIMEOUT;
import static com.android.bluetooth.bass_client.BassClientStateMachine.READ_BASS_CHARACTERISTICS;

import static com.google.common.truth.Truth.assertThat;

import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.after;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.timeout;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -31,7 +42,9 @@ import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattService;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.le.ScanRecord;
import android.content.Intent;
import android.os.Bundle;
import android.os.HandlerThread;
@@ -44,8 +57,6 @@ import androidx.test.filters.MediumTest;
import com.android.bluetooth.TestUtils;
import com.android.bluetooth.btservice.AdapterService;

import static com.google.common.truth.Truth.assertThat;

import org.hamcrest.core.IsInstanceOf;
import org.junit.After;
import org.junit.Assert;
@@ -60,6 +71,8 @@ import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;

import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

@MediumTest
@@ -135,7 +148,7 @@ public class BassClientStateMachineTest {
        allowConnectGatt(true);

        // Inject an event for when incoming connection is requested
        mBassClientStateMachine.sendMessage(BassClientStateMachine.CONNECT);
        mBassClientStateMachine.sendMessage(CONNECT);

        // Verify that no connection state broadcast is executed
        verify(mBassClientService, after(WAIT_MS).never()).sendBroadcast(any(Intent.class),
@@ -152,7 +165,7 @@ public class BassClientStateMachineTest {
        allowConnectGatt(false);

        // Inject an event for when incoming connection is requested
        mBassClientStateMachine.sendMessage(BassClientStateMachine.CONNECT);
        mBassClientStateMachine.sendMessage(CONNECT);

        // Verify that no connection state broadcast is executed
        verify(mBassClientService, after(WAIT_MS).never()).sendBroadcast(any(Intent.class),
@@ -170,7 +183,7 @@ public class BassClientStateMachineTest {
        allowConnectGatt(true);

        // Inject an event for when incoming connection is requested
        mBassClientStateMachine.sendMessage(BassClientStateMachine.CONNECT);
        mBassClientStateMachine.sendMessage(CONNECT);

        // Verify that one connection state broadcast is executed
        ArgumentCaptor<Intent> intentArgument1 = ArgumentCaptor.forClass(Intent.class);
@@ -202,7 +215,7 @@ public class BassClientStateMachineTest {
        allowConnectGatt(true);

        // Inject an event for when incoming connection is requested
        mBassClientStateMachine.sendMessage(BassClientStateMachine.CONNECT);
        mBassClientStateMachine.sendMessage(CONNECT);

        // Verify that one connection state broadcast is executed
        ArgumentCaptor<Intent> intentArgument1 = ArgumentCaptor.forClass(Intent.class);
@@ -235,7 +248,7 @@ public class BassClientStateMachineTest {

        // disconnected -> connecting ---timeout---> disconnected
        sendMessageAndVerifyTransition(
                mBassClientStateMachine.obtainMessage(BassClientStateMachine.CONNECT),
                mBassClientStateMachine.obtainMessage(CONNECT),
                BassClientStateMachine.Connecting.class);
        sendMessageAndVerifyTransition(
                mBassClientStateMachine.obtainMessage(BassClientStateMachine.CONNECT_TIMEOUT),
@@ -243,7 +256,7 @@ public class BassClientStateMachineTest {

        // disconnected -> connecting ---DISCONNECT---> disconnected
        sendMessageAndVerifyTransition(
                mBassClientStateMachine.obtainMessage(BassClientStateMachine.CONNECT),
                mBassClientStateMachine.obtainMessage(CONNECT),
                BassClientStateMachine.Connecting.class);
        sendMessageAndVerifyTransition(
                mBassClientStateMachine.obtainMessage(BassClientStateMachine.DISCONNECT),
@@ -252,36 +265,36 @@ public class BassClientStateMachineTest {
        // disconnected -> connecting ---CONNECTION_STATE_CHANGED(connected)---> connected -->
        // disconnected
        sendMessageAndVerifyTransition(
                mBassClientStateMachine.obtainMessage(BassClientStateMachine.CONNECT),
                mBassClientStateMachine.obtainMessage(CONNECT),
                BassClientStateMachine.Connecting.class);
        sendMessageAndVerifyTransition(
                mBassClientStateMachine.obtainMessage(
                        BassClientStateMachine.CONNECTION_STATE_CHANGED,
                        CONNECTION_STATE_CHANGED,
                        Integer.valueOf(BluetoothProfile.STATE_CONNECTED)),
                BassClientStateMachine.Connected.class);
        sendMessageAndVerifyTransition(
                mBassClientStateMachine.obtainMessage(
                        BassClientStateMachine.CONNECTION_STATE_CHANGED,
                        CONNECTION_STATE_CHANGED,
                        Integer.valueOf(BluetoothProfile.STATE_DISCONNECTED)),
                BassClientStateMachine.Disconnected.class);

        // disconnected -> connecting ---CONNECTION_STATE_CHANGED(non-connected) --> disconnected
        sendMessageAndVerifyTransition(
                mBassClientStateMachine.obtainMessage(BassClientStateMachine.CONNECT),
                mBassClientStateMachine.obtainMessage(CONNECT),
                BassClientStateMachine.Connecting.class);
        sendMessageAndVerifyTransition(
                mBassClientStateMachine.obtainMessage(
                        BassClientStateMachine.CONNECTION_STATE_CHANGED,
                        CONNECTION_STATE_CHANGED,
                        Integer.valueOf(BluetoothProfile.STATE_DISCONNECTED)),
                BassClientStateMachine.Disconnected.class);

        // change default state to connected for the next tests
        sendMessageAndVerifyTransition(
                mBassClientStateMachine.obtainMessage(BassClientStateMachine.CONNECT),
                mBassClientStateMachine.obtainMessage(CONNECT),
                BassClientStateMachine.Connecting.class);
        sendMessageAndVerifyTransition(
                mBassClientStateMachine.obtainMessage(
                        BassClientStateMachine.CONNECTION_STATE_CHANGED,
                        CONNECTION_STATE_CHANGED,
                        Integer.valueOf(BluetoothProfile.STATE_CONNECTED)),
                BassClientStateMachine.Connected.class);

@@ -299,7 +312,7 @@ public class BassClientStateMachineTest {

        sendMessageAndVerifyTransition(
                mBassClientStateMachine.obtainMessage(
                        BassClientStateMachine.READ_BASS_CHARACTERISTICS,
                        READ_BASS_CHARACTERISTICS,
                        new BluetoothGattCharacteristic(UUID.randomUUID(),
                                BluetoothGattCharacteristic.PROPERTY_READ,
                                BluetoothGattCharacteristic.PERMISSION_READ)),
@@ -312,7 +325,7 @@ public class BassClientStateMachineTest {
        // connected
        sendMessageAndVerifyTransition(
                mBassClientStateMachine.obtainMessage(
                        BassClientStateMachine.READ_BASS_CHARACTERISTICS,
                        READ_BASS_CHARACTERISTICS,
                        new BluetoothGattCharacteristic(UUID.randomUUID(),
                                BluetoothGattCharacteristic.PROPERTY_READ,
                                BluetoothGattCharacteristic.PERMISSION_READ)),
@@ -339,6 +352,265 @@ public class BassClientStateMachineTest {
                BassClientStateMachine.Connected.class);
    }

    @Test
    public void acquireAllBassChars() {
        BassClientStateMachine.BluetoothGattTestableWrapper btGatt = Mockito.mock(
                BassClientStateMachine.BluetoothGattTestableWrapper.class);
        mBassClientStateMachine.mBluetoothGatt = btGatt;
        // Do nothing when mBluetoothGatt.getService returns null
        mBassClientStateMachine.acquireAllBassChars();

        BluetoothGattService gattService = Mockito.mock(BluetoothGattService.class);
        when(btGatt.getService(BassConstants.BASS_UUID)).thenReturn(gattService);

        List<BluetoothGattCharacteristic> characteristics = new ArrayList<>();
        BluetoothGattCharacteristic scanControlPoint = new BluetoothGattCharacteristic(
                BassConstants.BASS_BCAST_AUDIO_SCAN_CTRL_POINT,
                BluetoothGattCharacteristic.PROPERTY_READ,
                BluetoothGattCharacteristic.PERMISSION_READ);
        characteristics.add(scanControlPoint);

        BluetoothGattCharacteristic bassCharacteristic = new BluetoothGattCharacteristic(
                UUID.randomUUID(),
                BluetoothGattCharacteristic.PROPERTY_READ,
                BluetoothGattCharacteristic.PERMISSION_READ);
        characteristics.add(bassCharacteristic);

        when(gattService.getCharacteristics()).thenReturn(characteristics);
        mBassClientStateMachine.acquireAllBassChars();
        assertThat(mBassClientStateMachine.mBroadcastScanControlPoint).isEqualTo(scanControlPoint);
        assertThat(mBassClientStateMachine.mBroadcastCharacteristics).contains(bassCharacteristic);
    }

    @Test
    public void simpleMethods() {
        // dump() shouldn't crash
        StringBuilder sb = new StringBuilder();
        mBassClientStateMachine.dump(sb);

        // log() shouldn't crash
        String msg = "test-log-message";
        mBassClientStateMachine.log(msg);

        // messageWhatToString() shouldn't crash
        for (int i = CONNECT; i <= CONNECT_TIMEOUT + 1; ++i) {
            mBassClientStateMachine.messageWhatToString(i);
        }

        final int invalidSourceId = -100;
        assertThat(mBassClientStateMachine.getCurrentBroadcastMetadata(invalidSourceId)).isNull();
        assertThat(mBassClientStateMachine.getDevice()).isEqualTo(mTestDevice);
        assertThat(mBassClientStateMachine.hasPendingSourceOperation()).isFalse();
        assertThat(mBassClientStateMachine.isEmpty(new byte[] { 0 })).isTrue();
        assertThat(mBassClientStateMachine.isEmpty(new byte[] { 1 })).isFalse();
        assertThat(mBassClientStateMachine.isPendingRemove(invalidSourceId)).isFalse();
    }

    @Test
    public void parseScanRecord_withoutBaseData_makesNoStopScanOffloadFalse() {
        byte[] scanRecord = new byte[]{
                0x02, 0x01, 0x1a, // advertising flags
                0x05, 0x02, 0x0b, 0x11, 0x0a, 0x11, // 16 bit service uuids
                0x04, 0x09, 0x50, 0x65, 0x64, // name
                0x02, 0x0A, (byte) 0xec, // tx power level
                0x05, 0x16, 0x0b, 0x11, 0x50, 0x64, // service data
                0x05, (byte) 0xff, (byte) 0xe0, 0x00, 0x02, 0x15, // manufacturer specific data
                0x03, 0x50, 0x01, 0x02, // an unknown data type won't cause trouble
        };
        ScanRecord data = ScanRecord.parseFromBytes(scanRecord);
        mBassClientStateMachine.mNoStopScanOffload = true;
        mBassClientStateMachine.parseScanRecord(0, data);
        assertThat(mBassClientStateMachine.mNoStopScanOffload).isFalse();
    }

    @Test
    public void parseScanRecord_withBaseData_callsUpdateBase() {
        byte[] scanRecordWithBaseData = new byte[] {
                0x02, 0x01, 0x1a, // advertising flags
                0x05, 0x02, 0x51, 0x18, 0x0a, 0x11, // 16 bit service uuids
                0x04, 0x09, 0x50, 0x65, 0x64, // name
                0x02, 0x0A, (byte) 0xec, // tx power level
                0x15, 0x16, 0x51, 0x18, // service data (base data with 18 bytes)
                    // LEVEL 1
                    (byte) 0x01, (byte) 0x02, (byte) 0x03, // presentationDelay
                    (byte) 0x01,  // numSubGroups
                    // LEVEL 2
                    (byte) 0x01,  // numSubGroups
                    (byte) 0xFE,  // UNKNOWN_CODEC
                    (byte) 0x02,  // codecConfigLength
                    (byte) 0x01, (byte) 'A', // codecConfigInfo
                    (byte) 0x03,  // metaDataLength
                    (byte) 0x06, (byte) 0x07, (byte) 0x08,  // metaData
                    // LEVEL 3
                    (byte) 0x04,  // index
                    (byte) 0x03,  // codecConfigLength
                    (byte) 0x02, (byte) 'B', (byte) 'C', // codecConfigInfo
                0x05, (byte) 0xff, (byte) 0xe0, 0x00, 0x02, 0x15, // manufacturer specific data
                0x03, 0x50, 0x01, 0x02, // an unknown data type won't cause trouble
        };
        ScanRecord data = ScanRecord.parseFromBytes(scanRecordWithBaseData);
        assertThat(data.getServiceUuids()).contains(BassConstants.BASIC_AUDIO_UUID);
        assertThat(data.getServiceData(BassConstants.BASIC_AUDIO_UUID)).isNotNull();
        mBassClientStateMachine.parseScanRecord(0, data);
        verify(mBassClientService).updateBase(anyInt(), any());
    }

    @Test
    public void sendConnectMessage_inDisconnectedState() {
        initToDisconnectedState();

        BassClientStateMachine.BluetoothGattTestableWrapper btGatt = Mockito.mock(
                BassClientStateMachine.BluetoothGattTestableWrapper.class);
        mBassClientStateMachine.mBluetoothGatt = btGatt;

        sendMessageAndVerifyTransition(
                mBassClientStateMachine.obtainMessage(CONNECT),
                BassClientStateMachine.Connecting.class);
        verify(btGatt).disconnect();
        verify(btGatt).close();
    }

    @Test
    public void sendDisconnectMessage_inDisconnectedState() {
        initToDisconnectedState();

        BassClientStateMachine.BluetoothGattTestableWrapper btGatt = Mockito.mock(
                BassClientStateMachine.BluetoothGattTestableWrapper.class);
        mBassClientStateMachine.mBluetoothGatt = btGatt;

        mBassClientStateMachine.sendMessage(DISCONNECT);
        verify(btGatt, timeout(TIMEOUT_MS)).disconnect();
        verify(btGatt).close();
    }

    @Test
    public void sendStateChangedMessage_inDisconnectedState() {
        initToDisconnectedState();

        BassClientStateMachine.BluetoothGattTestableWrapper btGatt = Mockito.mock(
                BassClientStateMachine.BluetoothGattTestableWrapper.class);
        mBassClientStateMachine.mBluetoothGatt = btGatt;

        Message msgToConnectingState =
                mBassClientStateMachine.obtainMessage(CONNECTION_STATE_CHANGED);
        msgToConnectingState.obj = BluetoothProfile.STATE_CONNECTING;

        mBassClientStateMachine.sendMessage(msgToConnectingState);
        TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
        verify(mBassClientService, never()).sendBroadcast(any(Intent.class), anyString(), any());

        Message msgToConnectedState =
                mBassClientStateMachine.obtainMessage(CONNECTION_STATE_CHANGED);
        msgToConnectedState.obj = BluetoothProfile.STATE_CONNECTED;
        sendMessageAndVerifyTransition(msgToConnectedState, BassClientStateMachine.Connected.class);
    }

    @Test
    public void sendOtherMessages_inDisconnectedState_doesNotChangeState() {
        initToDisconnectedState();

        mBassClientStateMachine.sendMessage(PSYNC_ACTIVE_TIMEOUT);
        TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
        verify(mBassClientService, never()).sendBroadcast(any(Intent.class), anyString(), any());

        mBassClientStateMachine.sendMessage(-1);
        TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
        verify(mBassClientService, never()).sendBroadcast(any(Intent.class), anyString(), any());
    }

    @Test
    public void sendConnectMessages_inConnectingState_doesNotChangeState() {
        initToConnectingState();

        mBassClientStateMachine.sendMessage(CONNECT);
        TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
        verify(mBassClientService, never()).sendBroadcast(any(Intent.class), anyString(), any());
    }

    @Test
    public void sendDisconnectMessages_inConnectingState_defersMessage() {
        initToConnectingState();

        mBassClientStateMachine.sendMessage(DISCONNECT);
        TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
        assertThat(mBassClientStateMachine.hasDeferredMessagesSuper(DISCONNECT)).isTrue();
    }

    @Test
    public void sendReadBassCharacteristicsMessage_inConnectingState_defersMessage() {
        initToConnectingState();

        mBassClientStateMachine.sendMessage(READ_BASS_CHARACTERISTICS);
        TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
        assertThat(mBassClientStateMachine.hasDeferredMessagesSuper(READ_BASS_CHARACTERISTICS))
                .isTrue();
    }

    @Test
    public void sendPsyncActiveTimeoutMessage_inConnectingState_defersMessage() {
        initToConnectingState();

        mBassClientStateMachine.sendMessage(PSYNC_ACTIVE_TIMEOUT);
        TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
        assertThat(mBassClientStateMachine.hasDeferredMessagesSuper(PSYNC_ACTIVE_TIMEOUT)).isTrue();
    }

    @Test
    public void sendStateChangedToNonConnectedMessage_inConnectingState_movesToDisconnected() {
        initToConnectingState();

        Message msg = mBassClientStateMachine.obtainMessage(CONNECTION_STATE_CHANGED);
        msg.obj = BluetoothProfile.STATE_CONNECTING;
        sendMessageAndVerifyTransition(msg, BassClientStateMachine.Disconnected.class);
    }

    @Test
    public void sendStateChangedToConnectedMessage_inConnectingState_movesToConnected() {
        initToConnectingState();

        Message msg = mBassClientStateMachine.obtainMessage(CONNECTION_STATE_CHANGED);
        msg.obj = BluetoothProfile.STATE_CONNECTED;
        sendMessageAndVerifyTransition(msg, BassClientStateMachine.Connected.class);
    }

    @Test
    public void sendConnectTimeMessage_inConnectingState() {
        initToConnectingState();

        Message timeoutWithDifferentDevice = mBassClientStateMachine.obtainMessage(CONNECT_TIMEOUT,
                mAdapter.getRemoteDevice("00:00:00:00:00:00"));
        mBassClientStateMachine.sendMessage(timeoutWithDifferentDevice);
        TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
        verify(mBassClientService, never()).sendBroadcast(any(Intent.class), anyString(), any());

        Message msg = mBassClientStateMachine.obtainMessage(CONNECT_TIMEOUT, mTestDevice);
        sendMessageAndVerifyTransition(msg, BassClientStateMachine.Disconnected.class);
    }

    @Test
    public void sendInvalidMessage_inConnectingState_doesNotChangeState() {
        initToConnectingState();
        mBassClientStateMachine.sendMessage(-1);
        TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
        verify(mBassClientService, never()).sendBroadcast(any(Intent.class), anyString(), any());
    }

    private void initToDisconnectedState() {
        allowConnection(true);
        allowConnectGatt(true);
        assertThat(mBassClientStateMachine.getCurrentState())
                .isInstanceOf(BassClientStateMachine.Disconnected.class);
    }

    private void initToConnectingState() {
        allowConnection(true);
        allowConnectGatt(true);
        sendMessageAndVerifyTransition(
                mBassClientStateMachine.obtainMessage(CONNECT),
                BassClientStateMachine.Connecting.class);
        Mockito.clearInvocations(mBassClientService);
    }

    private <T> void sendMessageAndVerifyTransition(Message msg, Class<T> type) {
        Mockito.clearInvocations(mBassClientService);
        mBassClientStateMachine.sendMessage(msg);
@@ -349,7 +621,6 @@ public class BassClientStateMachineTest {
        Assert.assertThat(mBassClientStateMachine.getCurrentState(), IsInstanceOf.instanceOf(type));
    }


    // It simulates GATT connection for testing.
    public static class StubBassClientStateMachine extends BassClientStateMachine {
        boolean mShouldAllowGatt = true;
@@ -374,5 +645,9 @@ public class BassClientStateMachineTest {
                mGattCallback.onConnectionStateChange(gatt, status, newState);
            }
        }

        public boolean hasDeferredMessagesSuper(int what) {
            return super.hasDeferredMessages(what);
        }
    }
}