Loading android/app/src/com/android/bluetooth/avrcpcontroller/AvrcpControllerStateMachine.java +28 −17 Original line number Diff line number Diff line Loading @@ -89,7 +89,14 @@ class AvrcpControllerStateMachine extends StateMachine { */ private static final int ABS_VOL_BASE = 127; /* * Notification types for Avrcp protocol JNI. */ private static final byte NOTIFICATION_RSP_TYPE_INTERIM = 0x00; private static final byte NOTIFICATION_RSP_TYPE_CHANGED = 0x01; private final AudioManager mAudioManager; private final boolean mIsVolumeFixed; protected final BluetoothDevice mDevice; protected final byte[] mDeviceAddress; Loading @@ -108,6 +115,7 @@ class AvrcpControllerStateMachine extends StateMachine { private int mAddressedPlayerId = -1; private SparseArray<AvrcpPlayer> mAvailablePlayerList = new SparseArray<AvrcpPlayer>(); private int mVolumeChangedNotificationsToIgnore = 0; private int mVolumeNotificationLabel = -1; GetFolderList mGetFolderList = null; Loading Loading @@ -137,6 +145,7 @@ class AvrcpControllerStateMachine extends StateMachine { mGetFolderList = new GetFolderList(); addState(mGetFolderList, mConnected); mAudioManager = (AudioManager) service.getSystemService(Context.AUDIO_SERVICE); mIsVolumeFixed = mAudioManager.isVolumeFixed(); setInitialState(mDisconnected); } Loading Loading @@ -309,6 +318,13 @@ class AvrcpControllerStateMachine extends StateMachine { setAbsVolume(msg.arg1, msg.arg2); return true; case MESSAGE_PROCESS_REGISTER_ABS_VOL_NOTIFICATION: mVolumeNotificationLabel = msg.arg1; mService.sendRegisterAbsVolRspNative(mDeviceAddress, NOTIFICATION_RSP_TYPE_INTERIM, getAbsVolumeResponse(), mVolumeNotificationLabel); return true; case MESSAGE_GET_FOLDER_ITEMS: transitionTo(mGetFolderList); return true; Loading Loading @@ -548,24 +564,9 @@ class AvrcpControllerStateMachine extends StateMachine { } break; case CONNECT: case DISCONNECT: case MSG_AVRCP_PASSTHRU: case MESSAGE_PROCESS_SET_ABS_VOL_CMD: case MESSAGE_PROCESS_REGISTER_ABS_VOL_NOTIFICATION: case MESSAGE_PROCESS_TRACK_CHANGED: case MESSAGE_PROCESS_PLAY_POS_CHANGED: case MESSAGE_PROCESS_PLAY_STATUS_CHANGED: case MESSAGE_PROCESS_VOLUME_CHANGED_NOTIFICATION: case MESSAGE_PLAY_ITEM: case MESSAGE_PROCESS_ADDRESSED_PLAYER_CHANGED: default: // All of these messages should be handled by parent state immediately. return false; default: logD(STATE_TAG + " deferring message " + msg.what + " to connected!"); deferMessage(msg); } return true; } Loading Loading @@ -694,7 +695,17 @@ class AvrcpControllerStateMachine extends StateMachine { mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, newIndex, AudioManager.FLAG_SHOW_UI); } mService.sendAbsVolRspNative(mDeviceAddress, absVol, label); mService.sendAbsVolRspNative(mDeviceAddress, getAbsVolumeResponse(), label); } private int getAbsVolumeResponse() { if (mIsVolumeFixed) { return ABS_VOL_BASE; } int maxVolume = mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC); int currIndex = mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC); int newIndex = (currIndex * ABS_VOL_BASE) / maxVolume; return newIndex; } MediaSession.Callback mSessionCallbacks = new MediaSession.Callback() { Loading android/app/tests/unit/src/com/android/bluetooth/avrcpcontroller/AvrcpControllerStateMachineTest.java +20 −0 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothProfile; import android.content.Context; import android.content.Intent; import android.media.AudioManager; import android.media.session.MediaController; import android.os.Looper; Loading Loading @@ -70,6 +71,8 @@ public class AvrcpControllerStateMachineTest { @Mock private AdapterService mAdapterService; @Mock private AudioManager mAudioManager; @Mock private AvrcpControllerService mAvrcpControllerService; AvrcpControllerStateMachine mAvrcpStateMachine; Loading @@ -90,6 +93,11 @@ public class AvrcpControllerStateMachineTest { TestUtils.setAdapterService(mAdapterService); TestUtils.startService(mServiceRule, AvrcpControllerService.class); doReturn(mTargetContext.getResources()).when(mAvrcpControllerService).getResources(); doReturn(15).when(mAudioManager).getStreamMaxVolume(anyInt()); doReturn(8).when(mAudioManager).getStreamVolume(anyInt()); doReturn(true).when(mAudioManager).isVolumeFixed(); doReturn(mAudioManager).when(mAvrcpControllerService) .getSystemService(Context.AUDIO_SERVICE); // This line must be called to make sure relevant objects are initialized properly mAdapter = BluetoothAdapter.getDefaultAdapter(); Loading Loading @@ -486,6 +494,18 @@ public class AvrcpControllerStateMachineTest { eq(mTestAddress), eq(AvrcpControllerService.PASS_THRU_CMD_ID_PLAY), eq(KEY_UP)); } /** * Test that Absolute Volume Registration is working */ @Test public void testRegisterAbsVolumeNotification() { setUpConnectedState(true, true); mAvrcpStateMachine.sendMessage( AvrcpControllerStateMachine.MESSAGE_PROCESS_REGISTER_ABS_VOL_NOTIFICATION); verify(mAvrcpControllerService, timeout(ASYNC_CALL_TIMEOUT_MILLIS).times(1)) .sendRegisterAbsVolRspNative(any(), anyByte(), eq(127), anyInt()); } /** * Setup Connected State * Loading Loading
android/app/src/com/android/bluetooth/avrcpcontroller/AvrcpControllerStateMachine.java +28 −17 Original line number Diff line number Diff line Loading @@ -89,7 +89,14 @@ class AvrcpControllerStateMachine extends StateMachine { */ private static final int ABS_VOL_BASE = 127; /* * Notification types for Avrcp protocol JNI. */ private static final byte NOTIFICATION_RSP_TYPE_INTERIM = 0x00; private static final byte NOTIFICATION_RSP_TYPE_CHANGED = 0x01; private final AudioManager mAudioManager; private final boolean mIsVolumeFixed; protected final BluetoothDevice mDevice; protected final byte[] mDeviceAddress; Loading @@ -108,6 +115,7 @@ class AvrcpControllerStateMachine extends StateMachine { private int mAddressedPlayerId = -1; private SparseArray<AvrcpPlayer> mAvailablePlayerList = new SparseArray<AvrcpPlayer>(); private int mVolumeChangedNotificationsToIgnore = 0; private int mVolumeNotificationLabel = -1; GetFolderList mGetFolderList = null; Loading Loading @@ -137,6 +145,7 @@ class AvrcpControllerStateMachine extends StateMachine { mGetFolderList = new GetFolderList(); addState(mGetFolderList, mConnected); mAudioManager = (AudioManager) service.getSystemService(Context.AUDIO_SERVICE); mIsVolumeFixed = mAudioManager.isVolumeFixed(); setInitialState(mDisconnected); } Loading Loading @@ -309,6 +318,13 @@ class AvrcpControllerStateMachine extends StateMachine { setAbsVolume(msg.arg1, msg.arg2); return true; case MESSAGE_PROCESS_REGISTER_ABS_VOL_NOTIFICATION: mVolumeNotificationLabel = msg.arg1; mService.sendRegisterAbsVolRspNative(mDeviceAddress, NOTIFICATION_RSP_TYPE_INTERIM, getAbsVolumeResponse(), mVolumeNotificationLabel); return true; case MESSAGE_GET_FOLDER_ITEMS: transitionTo(mGetFolderList); return true; Loading Loading @@ -548,24 +564,9 @@ class AvrcpControllerStateMachine extends StateMachine { } break; case CONNECT: case DISCONNECT: case MSG_AVRCP_PASSTHRU: case MESSAGE_PROCESS_SET_ABS_VOL_CMD: case MESSAGE_PROCESS_REGISTER_ABS_VOL_NOTIFICATION: case MESSAGE_PROCESS_TRACK_CHANGED: case MESSAGE_PROCESS_PLAY_POS_CHANGED: case MESSAGE_PROCESS_PLAY_STATUS_CHANGED: case MESSAGE_PROCESS_VOLUME_CHANGED_NOTIFICATION: case MESSAGE_PLAY_ITEM: case MESSAGE_PROCESS_ADDRESSED_PLAYER_CHANGED: default: // All of these messages should be handled by parent state immediately. return false; default: logD(STATE_TAG + " deferring message " + msg.what + " to connected!"); deferMessage(msg); } return true; } Loading Loading @@ -694,7 +695,17 @@ class AvrcpControllerStateMachine extends StateMachine { mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, newIndex, AudioManager.FLAG_SHOW_UI); } mService.sendAbsVolRspNative(mDeviceAddress, absVol, label); mService.sendAbsVolRspNative(mDeviceAddress, getAbsVolumeResponse(), label); } private int getAbsVolumeResponse() { if (mIsVolumeFixed) { return ABS_VOL_BASE; } int maxVolume = mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC); int currIndex = mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC); int newIndex = (currIndex * ABS_VOL_BASE) / maxVolume; return newIndex; } MediaSession.Callback mSessionCallbacks = new MediaSession.Callback() { Loading
android/app/tests/unit/src/com/android/bluetooth/avrcpcontroller/AvrcpControllerStateMachineTest.java +20 −0 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothProfile; import android.content.Context; import android.content.Intent; import android.media.AudioManager; import android.media.session.MediaController; import android.os.Looper; Loading Loading @@ -70,6 +71,8 @@ public class AvrcpControllerStateMachineTest { @Mock private AdapterService mAdapterService; @Mock private AudioManager mAudioManager; @Mock private AvrcpControllerService mAvrcpControllerService; AvrcpControllerStateMachine mAvrcpStateMachine; Loading @@ -90,6 +93,11 @@ public class AvrcpControllerStateMachineTest { TestUtils.setAdapterService(mAdapterService); TestUtils.startService(mServiceRule, AvrcpControllerService.class); doReturn(mTargetContext.getResources()).when(mAvrcpControllerService).getResources(); doReturn(15).when(mAudioManager).getStreamMaxVolume(anyInt()); doReturn(8).when(mAudioManager).getStreamVolume(anyInt()); doReturn(true).when(mAudioManager).isVolumeFixed(); doReturn(mAudioManager).when(mAvrcpControllerService) .getSystemService(Context.AUDIO_SERVICE); // This line must be called to make sure relevant objects are initialized properly mAdapter = BluetoothAdapter.getDefaultAdapter(); Loading Loading @@ -486,6 +494,18 @@ public class AvrcpControllerStateMachineTest { eq(mTestAddress), eq(AvrcpControllerService.PASS_THRU_CMD_ID_PLAY), eq(KEY_UP)); } /** * Test that Absolute Volume Registration is working */ @Test public void testRegisterAbsVolumeNotification() { setUpConnectedState(true, true); mAvrcpStateMachine.sendMessage( AvrcpControllerStateMachine.MESSAGE_PROCESS_REGISTER_ABS_VOL_NOTIFICATION); verify(mAvrcpControllerService, timeout(ASYNC_CALL_TIMEOUT_MILLIS).times(1)) .sendRegisterAbsVolRspNative(any(), anyByte(), eq(127), anyInt()); } /** * Setup Connected State * Loading