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

Commit bb57a013 authored by Hyundo Moon's avatar Hyundo Moon Committed by Gerrit Code Review
Browse files

Merge "Add AvrcpControllerServiceTest"

parents 2be49bc6 a108a06d
Loading
Loading
Loading
Loading
+46 −26
Original line number Diff line number Diff line
@@ -35,6 +35,7 @@ import com.android.bluetooth.Utils;
import com.android.bluetooth.a2dpsink.A2dpSinkService;
import com.android.bluetooth.btservice.AdapterService;
import com.android.bluetooth.btservice.ProfileService;
import com.android.internal.annotations.VisibleForTesting;
import com.android.modules.utils.SynchronousResultReceiver;

import java.util.ArrayList;
@@ -67,7 +68,8 @@ public class AvrcpControllerService extends ProfileService {
    private static final byte JNI_PLAY_STATUS_PLAYING = 0x01;
    private static final byte JNI_PLAY_STATUS_PAUSED = 0x02;
    private static final byte JNI_PLAY_STATUS_FWD_SEEK = 0x03;
    private static final byte JNI_PLAY_STATUS_REV_SEEK = 0x04;
    @VisibleForTesting
    static final byte JNI_PLAY_STATUS_REV_SEEK = 0x04;
    private static final byte JNI_PLAY_STATUS_ERROR = -1;

    /* Folder/Media Item scopes.
@@ -173,6 +175,7 @@ public class AvrcpControllerService extends ProfileService {
        for (AvrcpControllerStateMachine stateMachine : mDeviceStateMap.values()) {
            stateMachine.quitNow();
        }
        mDeviceStateMap.clear();

        sService = null;
        sBrowseTree = null;
@@ -201,7 +204,8 @@ public class AvrcpControllerService extends ProfileService {
    /**
     * Set the current active device, notify devices of activity status
     */
    private boolean setActiveDevice(BluetoothDevice device) {
    @VisibleForTesting
    boolean setActiveDevice(BluetoothDevice device) {
        A2dpSinkService a2dpSinkService = A2dpSinkService.getA2dpSinkService();
        if (a2dpSinkService == null) {
            return false;
@@ -277,7 +281,8 @@ public class AvrcpControllerService extends ProfileService {
        }
    }

    private void refreshContents(BrowseTree.BrowseNode node) {
    @VisibleForTesting
    void refreshContents(BrowseTree.BrowseNode node) {
        BluetoothDevice device = node.getDevice();
        if (device == null) {
            return;
@@ -467,14 +472,16 @@ public class AvrcpControllerService extends ProfileService {

    /* JNI API*/
    // Called by JNI when a passthrough key was received.
    private void handlePassthroughRsp(int id, int keyState, byte[] address) {
    @VisibleForTesting
    void handlePassthroughRsp(int id, int keyState, byte[] address) {
        if (DBG) {
            Log.d(TAG, "passthrough response received as: key: " + id
                    + " state: " + keyState + "address:" + Arrays.toString(address));
        }
    }

    private void handleGroupNavigationRsp(int id, int keyState) {
    @VisibleForTesting
    void handleGroupNavigationRsp(int id, int keyState) {
        if (DBG) {
            Log.d(TAG, "group navigation response received as: key: " + id + " state: "
                    + keyState);
@@ -482,17 +489,14 @@ public class AvrcpControllerService extends ProfileService {
    }

    // Called by JNI when a device has connected or disconnected.
    private synchronized void onConnectionStateChanged(boolean remoteControlConnected,
    @VisibleForTesting
    synchronized void onConnectionStateChanged(boolean remoteControlConnected,
            boolean browsingConnected, byte[] address) {
        BluetoothDevice device = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(address);
        if (DBG) {
            Log.d(TAG, "onConnectionStateChanged " + remoteControlConnected + " "
                    + browsingConnected + device);
        }
        if (device == null) {
            Log.e(TAG, "onConnectionStateChanged Device is null");
            return;
        }

        StackEvent event =
                StackEvent.connectionStateChanged(remoteControlConnected, browsingConnected);
@@ -514,12 +518,14 @@ public class AvrcpControllerService extends ProfileService {
    }

    // Called by JNI to notify Avrcp of features supported by the Remote device.
    private void getRcFeatures(byte[] address, int features) {
    @VisibleForTesting
    void getRcFeatures(byte[] address, int features) {
        /* Do Nothing. */
    }

    // Called by JNI to notify Avrcp of a remote device's Cover Art PSM
    private void getRcPsm(byte[] address, int psm) {
    @VisibleForTesting
    void getRcPsm(byte[] address, int psm) {
        BluetoothDevice device = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(address);
        if (DBG) Log.d(TAG, "getRcPsm(device=" + device + ", psm=" + psm + ")");
        AvrcpControllerStateMachine stateMachine = getOrCreateStateMachine(device);
@@ -530,12 +536,14 @@ public class AvrcpControllerService extends ProfileService {
    }

    // Called by JNI
    private void setPlayerAppSettingRsp(byte[] address, byte accepted) {
    @VisibleForTesting
    void setPlayerAppSettingRsp(byte[] address, byte accepted) {
        /* Do Nothing. */
    }

    // Called by JNI when remote wants to receive absolute volume notifications.
    private synchronized void handleRegisterNotificationAbsVol(byte[] address, byte label) {
    @VisibleForTesting
    synchronized void handleRegisterNotificationAbsVol(byte[] address, byte label) {
        if (DBG) {
            Log.d(TAG, "handleRegisterNotificationAbsVol");
        }
@@ -548,7 +556,8 @@ public class AvrcpControllerService extends ProfileService {
    }

    // Called by JNI when remote wants to set absolute volume.
    private synchronized void handleSetAbsVolume(byte[] address, byte absVol, byte label) {
    @VisibleForTesting
    synchronized void handleSetAbsVolume(byte[] address, byte absVol, byte label) {
        if (DBG) {
            Log.d(TAG, "handleSetAbsVolume ");
        }
@@ -588,7 +597,8 @@ public class AvrcpControllerService extends ProfileService {
    }

    // Called by JNI when a track changes and local AvrcpController is registered for updates.
    private synchronized void onTrackChanged(byte[] address, byte numAttributes, int[] attributes,
    @VisibleForTesting
    synchronized void onTrackChanged(byte[] address, byte numAttributes, int[] attributes,
            String[] attribVals) {
        if (DBG) {
            Log.d(TAG, "onTrackChanged");
@@ -615,7 +625,8 @@ public class AvrcpControllerService extends ProfileService {
    }

    // Called by JNI periodically based upon timer to update play position
    private synchronized void onPlayPositionChanged(byte[] address, int songLen,
    @VisibleForTesting
    synchronized void onPlayPositionChanged(byte[] address, int songLen,
            int currSongPosition) {
        if (DBG) {
            Log.d(TAG, "onPlayPositionChanged pos " + currSongPosition);
@@ -630,7 +641,8 @@ public class AvrcpControllerService extends ProfileService {
    }

    // Called by JNI on changes of play status
    private synchronized void onPlayStatusChanged(byte[] address, byte playStatus) {
    @VisibleForTesting
    synchronized void onPlayStatusChanged(byte[] address, byte playStatus) {
        if (DBG) {
            Log.d(TAG, "onPlayStatusChanged " + playStatus);
        }
@@ -644,7 +656,8 @@ public class AvrcpControllerService extends ProfileService {
    }

    // Called by JNI to report remote Player's capabilities
    private synchronized void handlePlayerAppSetting(byte[] address, byte[] playerAttribRsp,
    @VisibleForTesting
    synchronized void handlePlayerAppSetting(byte[] address, byte[] playerAttribRsp,
            int rspLen) {
        if (DBG) {
            Log.d(TAG, "handlePlayerAppSetting rspLen = " + rspLen);
@@ -660,7 +673,8 @@ public class AvrcpControllerService extends ProfileService {
        }
    }

    private synchronized void onPlayerAppSettingChanged(byte[] address, byte[] playerAttribRsp,
    @VisibleForTesting
    synchronized void onPlayerAppSettingChanged(byte[] address, byte[] playerAttribRsp,
            int rspLen) {
        if (DBG) {
            Log.d(TAG, "onPlayerAppSettingChanged ");
@@ -677,7 +691,8 @@ public class AvrcpControllerService extends ProfileService {
        }
    }

    private void onAvailablePlayerChanged(byte[] address) {
    @VisibleForTesting
    void onAvailablePlayerChanged(byte[] address) {
        if (DBG) {
            Log.d(TAG," onAvailablePlayerChanged");
        }
@@ -795,7 +810,8 @@ public class AvrcpControllerService extends ProfileService {
        return apb.build();
    }

    private void handleChangeFolderRsp(byte[] address, int count) {
    @VisibleForTesting
    void handleChangeFolderRsp(byte[] address, int count) {
        if (DBG) {
            Log.d(TAG, "handleChangeFolderRsp count: " + count);
        }
@@ -807,7 +823,8 @@ public class AvrcpControllerService extends ProfileService {
        }
    }

    private void handleSetBrowsedPlayerRsp(byte[] address, int items, int depth) {
    @VisibleForTesting
    void handleSetBrowsedPlayerRsp(byte[] address, int items, int depth) {
        if (DBG) {
            Log.d(TAG, "handleSetBrowsedPlayerRsp depth: " + depth);
        }
@@ -820,7 +837,8 @@ public class AvrcpControllerService extends ProfileService {
        }
    }

    private void handleSetAddressedPlayerRsp(byte[] address, int status) {
    @VisibleForTesting
    void handleSetAddressedPlayerRsp(byte[] address, int status) {
        if (DBG) {
            Log.d(TAG, "handleSetAddressedPlayerRsp status: " + status);
        }
@@ -833,7 +851,8 @@ public class AvrcpControllerService extends ProfileService {
        }
    }

    private void handleAddressedPlayerChanged(byte[] address, int id) {
    @VisibleForTesting
    void handleAddressedPlayerChanged(byte[] address, int id) {
        if (DBG) {
            Log.d(TAG, "handleAddressedPlayerChanged id: " + id);
        }
@@ -846,7 +865,8 @@ public class AvrcpControllerService extends ProfileService {
        }
    }

    private void handleNowPlayingContentChanged(byte[] address) {
    @VisibleForTesting
    void handleNowPlayingContentChanged(byte[] address) {
        if (DBG) {
            Log.d(TAG, "handleNowPlayingContentChanged");
        }
+357 −11
Original line number Diff line number Diff line
@@ -15,45 +15,59 @@
 */
package com.android.bluetooth.avrcpcontroller;

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

import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyString;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import android.bluetooth.BluetoothAdapter;
import android.content.Context;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothProfile;
import android.support.v4.media.session.PlaybackStateCompat;

import androidx.test.InstrumentationRegistry;
import androidx.test.filters.MediumTest;
import androidx.test.rule.ServiceTestRule;
import androidx.test.runner.AndroidJUnit4;

import com.android.bluetooth.R;
import com.android.bluetooth.TestUtils;
import com.android.bluetooth.btservice.AdapterService;

import org.junit.After;
import org.junit.Assert;
import org.junit.Assume;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

import java.util.ArrayList;
import java.util.Arrays;

@MediumTest
@RunWith(AndroidJUnit4.class)
public class AvrcpControllerServiceTest {
    private static final String REMOTE_DEVICE_ADDRESS = "00:00:00:00:00:00";
    private static final byte[] REMOTE_DEVICE_ADDRESS_AS_ARRAY = new byte[] {0, 0, 0, 0, 0, 0};

    private AvrcpControllerService mService = null;
    private BluetoothAdapter mAdapter = null;
    private Context mTargetContext;

    @Rule public final ServiceTestRule mServiceRule = new ServiceTestRule();

    @Mock private AdapterService mAdapterService;
    @Mock private AvrcpControllerStateMachine mStateMachine;

    private BluetoothDevice mRemoteDevice;

    @Before
    public void setUp() throws Exception {
        mTargetContext = InstrumentationRegistry.getTargetContext();
        Assume.assumeTrue("Ignore test when AvrcpControllerService is not enabled",
                AvrcpControllerService.isEnabled());
        MockitoAnnotations.initMocks(this);
@@ -61,10 +75,12 @@ public class AvrcpControllerServiceTest {
        doReturn(true, false).when(mAdapterService).isStartedProfile(anyString());
        TestUtils.startService(mServiceRule, AvrcpControllerService.class);
        mService = AvrcpControllerService.getAvrcpControllerService();
        Assert.assertNotNull(mService);
        assertThat(mService).isNotNull();
        // Try getting the Bluetooth adapter
        mAdapter = BluetoothAdapter.getDefaultAdapter();
        Assert.assertNotNull(mAdapter);
        assertThat(mAdapter).isNotNull();
        mRemoteDevice = mAdapter.getRemoteDevice(REMOTE_DEVICE_ADDRESS);
        mService.mDeviceStateMap.put(mRemoteDevice, mStateMachine);
    }

    @After
@@ -74,12 +90,342 @@ public class AvrcpControllerServiceTest {
        }
        TestUtils.stopService(mServiceRule, AvrcpControllerService.class);
        mService = AvrcpControllerService.getAvrcpControllerService();
        Assert.assertNull(mService);
        assertThat(mService).isNull();
        TestUtils.clearAdapterService(mAdapterService);
    }

    @Test
    public void testInitialize() {
        Assert.assertNotNull(AvrcpControllerService.getAvrcpControllerService());
    public void initialize() {
        assertThat(AvrcpControllerService.getAvrcpControllerService()).isNotNull();
    }

    @Test
    public void disconnect_whenDisconnected_returnsFalse() {
        when(mStateMachine.getState()).thenReturn(BluetoothProfile.STATE_DISCONNECTED);

        assertThat(mService.disconnect(mRemoteDevice)).isFalse();
    }

    @Test
    public void disconnect_whenDisconnected_returnsTrue() {
        when(mStateMachine.getState()).thenReturn(BluetoothProfile.STATE_CONNECTED);

        assertThat(mService.disconnect(mRemoteDevice)).isTrue();
        verify(mStateMachine).disconnect();
    }

    @Test
    public void removeStateMachine() {
        when(mStateMachine.getDevice()).thenReturn(mRemoteDevice);

        mService.removeStateMachine(mStateMachine);

        assertThat(mService.mDeviceStateMap).doesNotContainKey(mRemoteDevice);
    }

    @Test
    public void getConnectedDevices() {
        when(mAdapterService.getBondedDevices()).thenReturn(
                new BluetoothDevice[]{mRemoteDevice});
        when(mStateMachine.getState()).thenReturn(BluetoothProfile.STATE_CONNECTED);

        assertThat(mService.getConnectedDevices()).contains(mRemoteDevice);
    }

    @Test
    public void setActiveDevice_whenA2dpSinkServiceIsNotInitailized_returnsFalse() {
        assertThat(mService.setActiveDevice(mRemoteDevice)).isFalse();

        assertThat(mService.getActiveDevice()).isNull();
    }

    @Test
    public void getCurrentMetadataIfNoCoverArt_doesNotCrash() {
        mService.getCurrentMetadataIfNoCoverArt(mRemoteDevice);
    }

    @Test
    public void refreshContents() {
        BrowseTree.BrowseNode node = mock(BrowseTree.BrowseNode.class);
        when(node.getDevice()).thenReturn(mRemoteDevice);

        mService.refreshContents(node);

        verify(mStateMachine).requestContents(node);
    }

    @Test
    public void playItem() {
        String parentMediaId = "test_parent_media_id";
        BrowseTree.BrowseNode node = mock(BrowseTree.BrowseNode.class);
        when(mStateMachine.findNode(parentMediaId)).thenReturn(node);

        mService.playItem(parentMediaId);

        verify(mStateMachine).playItem(node);
    }

    @Test
    public void getContents() {
        String parentMediaId = "test_parent_media_id";
        BrowseTree.BrowseNode node = mock(BrowseTree.BrowseNode.class);
        when(mStateMachine.findNode(parentMediaId)).thenReturn(node);

        mService.getContents(parentMediaId);

        verify(node).getContents();
    }

    @Test
    public void createFromNativeMediaItem() {
        long uid = 1;
        int type = 2;
        int[] attrIds = new int[] { 0x01 }; // MEDIA_ATTRIBUTE_TITLE}
        String[] attrVals = new String[] {"test_title"};

        AvrcpItem item = mService.createFromNativeMediaItem(
                REMOTE_DEVICE_ADDRESS_AS_ARRAY, uid, type, "unused_name", attrIds, attrVals);

        assertThat(item.getDevice().getAddress()).isEqualTo(REMOTE_DEVICE_ADDRESS);
        assertThat(item.getItemType()).isEqualTo(AvrcpItem.TYPE_MEDIA);
        assertThat(item.getType()).isEqualTo(type);
        assertThat(item.getUid()).isEqualTo(uid);
        assertThat(item.getUuid()).isNotNull(); // Random uuid
        assertThat(item.getTitle()).isEqualTo(attrVals[0]);
        assertThat(item.isPlayable()).isTrue();
    }

    @Test
    public void createFromNativeFolderItem() {
        long uid = 1;
        int type = 2;
        String folderName = "test_folder_name";
        int playable = 0x01; // Playable folder

        AvrcpItem item = mService.createFromNativeFolderItem(
                REMOTE_DEVICE_ADDRESS_AS_ARRAY, uid, type, folderName, playable);

        assertThat(item.getDevice().getAddress()).isEqualTo(REMOTE_DEVICE_ADDRESS);
        assertThat(item.getItemType()).isEqualTo(AvrcpItem.TYPE_FOLDER);
        assertThat(item.getType()).isEqualTo(type);
        assertThat(item.getUid()).isEqualTo(uid);
        assertThat(item.getUuid()).isNotNull(); // Random uuid
        assertThat(item.getDisplayableName()).isEqualTo(folderName);
        assertThat(item.isPlayable()).isTrue();
    }

    @Test
    public void createFromNativePlayerItem() {
        int playerId = 1;
        String name = "test_name";
        byte[] transportFlags = new byte[] {1, 0, 0, 0, 0, 0, 0, 0};
        int playStatus = AvrcpControllerService.JNI_PLAY_STATUS_REV_SEEK;
        int playerType = AvrcpPlayer.TYPE_AUDIO; // No getter exists

        AvrcpPlayer player = mService.createFromNativePlayerItem(
                REMOTE_DEVICE_ADDRESS_AS_ARRAY, playerId, name, transportFlags,
                playStatus, playerType);

        assertThat(player.getDevice().getAddress()).isEqualTo(REMOTE_DEVICE_ADDRESS);
        assertThat(player.getId()).isEqualTo(playerId);
        assertThat(player.supportsFeature(0)).isTrue();
        assertThat(player.getName()).isEqualTo(name);
        assertThat(player.getPlayStatus()).isEqualTo(PlaybackStateCompat.STATE_REWINDING);
    }

    @Test
    public void handleChangeFolderRsp() {
        int count = 1;

        mService.handleChangeFolderRsp(REMOTE_DEVICE_ADDRESS_AS_ARRAY, count);

        verify(mStateMachine).sendMessage(
                AvrcpControllerStateMachine.MESSAGE_PROCESS_FOLDER_PATH, count);
    }

    @Test
    public void handleSetBrowsedPlayerRsp() {
        int items = 3;
        int depth = 5;

        mService.handleSetBrowsedPlayerRsp(REMOTE_DEVICE_ADDRESS_AS_ARRAY, items, depth);

        verify(mStateMachine).sendMessage(
                AvrcpControllerStateMachine.MESSAGE_PROCESS_SET_BROWSED_PLAYER, items, depth);
    }

    @Test
    public void handleSetAddressedPlayerRsp() {
        int status = 1;

        mService.handleSetAddressedPlayerRsp(REMOTE_DEVICE_ADDRESS_AS_ARRAY, status);

        verify(mStateMachine).sendMessage(
                AvrcpControllerStateMachine.MESSAGE_PROCESS_SET_ADDRESSED_PLAYER);
    }

    @Test
    public void handleAddressedPlayerChanged() {
        int id = 1;

        mService.handleAddressedPlayerChanged(REMOTE_DEVICE_ADDRESS_AS_ARRAY, id);

        verify(mStateMachine).sendMessage(
                AvrcpControllerStateMachine.MESSAGE_PROCESS_ADDRESSED_PLAYER_CHANGED, id);
    }

    @Test
    public void handleNowPlayingContentChanged() {
        mService.handleNowPlayingContentChanged(REMOTE_DEVICE_ADDRESS_AS_ARRAY);

        verify(mStateMachine).nowPlayingContentChanged();
    }

    @Test
    public void JniApisWithNoBehaviors_doNotCrash() {
        mService.handlePassthroughRsp(1, 2, new byte[0]);
        mService.handleGroupNavigationRsp(1, 2);
        mService.getRcFeatures(new byte[0], 1);
        mService.setPlayerAppSettingRsp(new byte[0], (byte) 0);
    }

    @Test
    public void onConnectionStateChanged_connectCase() {
        boolean remoteControlConnected = true;
        boolean browsingConnected = true; // Calls connect when any of them is true.

        mService.onConnectionStateChanged(remoteControlConnected, browsingConnected,
                REMOTE_DEVICE_ADDRESS_AS_ARRAY);

        ArgumentCaptor<StackEvent> captor = ArgumentCaptor.forClass(StackEvent.class);
        verify(mStateMachine).connect(captor.capture());
        StackEvent event = captor.getValue();
        assertThat(event.mType).isEqualTo(StackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED);
        assertThat(event.mRemoteControlConnected).isEqualTo(remoteControlConnected);
        assertThat(event.mBrowsingConnected).isEqualTo(browsingConnected);
    }

    @Test
    public void onConnectionStateChanged_disconnectCase() {
        boolean remoteControlConnected = false;
        boolean browsingConnected = false; // Calls disconnect when both of them are false.

        mService.onConnectionStateChanged(
                remoteControlConnected, browsingConnected, REMOTE_DEVICE_ADDRESS_AS_ARRAY);

        verify(mStateMachine).disconnect();
    }

    @Test
    public void getRcPsm() {
        int psm = 1;

        mService.getRcPsm(REMOTE_DEVICE_ADDRESS_AS_ARRAY, psm);

        verify(mStateMachine).sendMessage(
                AvrcpControllerStateMachine.MESSAGE_PROCESS_RECEIVED_COVER_ART_PSM, psm);
    }

    @Test
    public void handleRegisterNotificationAbsVol() {
        byte label = 1;

        mService.handleRegisterNotificationAbsVol(REMOTE_DEVICE_ADDRESS_AS_ARRAY, label);

        verify(mStateMachine).sendMessage(
                AvrcpControllerStateMachine.MESSAGE_PROCESS_REGISTER_ABS_VOL_NOTIFICATION);
    }

    @Test
    public void handleSetAbsVolume() {
        byte absVol = 15;
        byte label = 1;

        mService.handleSetAbsVolume(REMOTE_DEVICE_ADDRESS_AS_ARRAY, absVol, label);

        verify(mStateMachine).sendMessage(
                AvrcpControllerStateMachine.MESSAGE_PROCESS_SET_ABS_VOL_CMD, absVol);
    }

    @Test
    public void onTrackChanged() {
        byte numAttrs = 0;
        int[] attrs = new int[0];
        String[] attrVals = new String[0];

        mService.onTrackChanged(REMOTE_DEVICE_ADDRESS_AS_ARRAY, numAttrs, attrs, attrVals);

        ArgumentCaptor<AvrcpItem> captor = ArgumentCaptor.forClass(AvrcpItem.class);
        verify(mStateMachine).sendMessage(
                eq(AvrcpControllerStateMachine.MESSAGE_PROCESS_TRACK_CHANGED), captor.capture());
        AvrcpItem item = captor.getValue();
        assertThat(item.getDevice().getAddress()).isEqualTo(REMOTE_DEVICE_ADDRESS);
        assertThat(item.getItemType()).isEqualTo(AvrcpItem.TYPE_MEDIA);
        assertThat(item.getUuid()).isNotNull(); // Random uuid
    }

    @Test
    public void onPlayPositionChanged() {
        int songLen = 100;
        int currSongPos = 33;

        mService.onPlayPositionChanged(REMOTE_DEVICE_ADDRESS_AS_ARRAY, songLen, currSongPos);

        verify(mStateMachine).sendMessage(
                AvrcpControllerStateMachine.MESSAGE_PROCESS_PLAY_POS_CHANGED, songLen, currSongPos);
    }

    @Test
    public void onPlayStatusChanged() {
        byte status = AvrcpControllerService.JNI_PLAY_STATUS_REV_SEEK;

        mService.onPlayStatusChanged(REMOTE_DEVICE_ADDRESS_AS_ARRAY, status);

        verify(mStateMachine).sendMessage(
                AvrcpControllerStateMachine.MESSAGE_PROCESS_PLAY_STATUS_CHANGED,
                PlaybackStateCompat.STATE_REWINDING);
    }

    @Test
    public void onPlayerAppSettingChanged() {
        byte[] playerAttribRsp = new byte[] {PlayerApplicationSettings.REPEAT_STATUS,
                PlayerApplicationSettings.JNI_REPEAT_STATUS_ALL_TRACK_REPEAT};

        mService.onPlayerAppSettingChanged(REMOTE_DEVICE_ADDRESS_AS_ARRAY, playerAttribRsp, 2);

        verify(mStateMachine).sendMessage(
                eq(AvrcpControllerStateMachine.MESSAGE_PROCESS_CURRENT_APPLICATION_SETTINGS),
                any(PlayerApplicationSettings.class));
    }

    @Test
    public void onAvailablePlayerChanged() {
        mService.onAvailablePlayerChanged(REMOTE_DEVICE_ADDRESS_AS_ARRAY);

        verify(mStateMachine).sendMessage(
                AvrcpControllerStateMachine.MESSAGE_PROCESS_AVAILABLE_PLAYER_CHANGED);
    }

    @Test
    public void handleGetFolderItemsRsp() {
        int status = 2;
        AvrcpItem[] items = new AvrcpItem[] {mock(AvrcpItem.class)};

        mService.handleGetFolderItemsRsp(REMOTE_DEVICE_ADDRESS_AS_ARRAY, status, items);

        verify(mStateMachine).sendMessage(
                eq(AvrcpControllerStateMachine.MESSAGE_PROCESS_GET_FOLDER_ITEMS),
                eq(new ArrayList<>(Arrays.asList(items))));
    }

    @Test
    public void handleGetPlayerItemsRsp() {
        AvrcpPlayer[] items = new AvrcpPlayer[] {mock(AvrcpPlayer.class)};

        mService.handleGetPlayerItemsRsp(REMOTE_DEVICE_ADDRESS_AS_ARRAY, items);

        verify(mStateMachine).sendMessage(
                eq(AvrcpControllerStateMachine.MESSAGE_PROCESS_GET_PLAYER_ITEMS),
                eq(new ArrayList<>(Arrays.asList(items))));
    }
}