summaryrefslogtreecommitdiffstats
path: root/src/com/android/bluetooth/avrcpcontroller/AvrcpControllerStateMachine.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/com/android/bluetooth/avrcpcontroller/AvrcpControllerStateMachine.java')
-rw-r--r--src/com/android/bluetooth/avrcpcontroller/AvrcpControllerStateMachine.java138
1 files changed, 108 insertions, 30 deletions
diff --git a/src/com/android/bluetooth/avrcpcontroller/AvrcpControllerStateMachine.java b/src/com/android/bluetooth/avrcpcontroller/AvrcpControllerStateMachine.java
index 66571c4e7..c319364c1 100644
--- a/src/com/android/bluetooth/avrcpcontroller/AvrcpControllerStateMachine.java
+++ b/src/com/android/bluetooth/avrcpcontroller/AvrcpControllerStateMachine.java
@@ -24,10 +24,10 @@ import android.content.Intent;
import android.media.AudioManager;
import android.media.MediaMetadata;
import android.media.browse.MediaBrowser.MediaItem;
-import android.media.session.MediaSession;
-import android.media.session.PlaybackState;
import android.os.Bundle;
import android.os.Message;
+import android.support.v4.media.session.MediaSessionCompat;
+import android.support.v4.media.session.PlaybackStateCompat;
import android.util.Log;
import android.util.SparseArray;
@@ -42,6 +42,7 @@ import com.android.internal.util.StateMachine;
import java.util.ArrayList;
import java.util.List;
+
/**
* Provides Bluetooth AVRCP Controller State Machine responsible for all remote control connections
* and interactions with a remote controlable device.
@@ -76,11 +77,15 @@ class AvrcpControllerStateMachine extends StateMachine {
static final int MESSAGE_PROCESS_SET_ADDRESSED_PLAYER = 214;
static final int MESSAGE_PROCESS_ADDRESSED_PLAYER_CHANGED = 215;
static final int MESSAGE_PROCESS_NOW_PLAYING_CONTENTS_CHANGED = 216;
+ static final int MESSAGE_PROCESS_SUPPORTED_APPLICATION_SETTINGS = 217;
+ static final int MESSAGE_PROCESS_CURRENT_APPLICATION_SETTINGS = 218;
//300->399 Events for Browsing
static final int MESSAGE_GET_FOLDER_ITEMS = 300;
static final int MESSAGE_PLAY_ITEM = 301;
static final int MSG_AVRCP_PASSTHRU = 302;
+ static final int MSG_AVRCP_SET_SHUFFLE = 303;
+ static final int MSG_AVRCP_SET_REPEAT = 304;
static final int MESSAGE_INTERNAL_ABS_VOL_TIMEOUT = 404;
@@ -218,26 +223,19 @@ class AvrcpControllerStateMachine extends StateMachine {
mService.sBrowseTree.mRootNode.addChild(mBrowseTree.mRootNode);
BluetoothMediaBrowserService.notifyChanged(mService
.sBrowseTree.mRootNode);
- BluetoothMediaBrowserService.notifyChanged(mAddressedPlayer.getPlaybackState());
mBrowsingConnected = true;
}
synchronized void onBrowsingDisconnected() {
if (!mBrowsingConnected) return;
- mAddressedPlayer.setPlayStatus(PlaybackState.STATE_ERROR);
+ mAddressedPlayer.setPlayStatus(PlaybackStateCompat.STATE_ERROR);
mAddressedPlayer.updateCurrentTrack(null);
mBrowseTree.mNowPlayingNode.setCached(false);
BluetoothMediaBrowserService.notifyChanged(mBrowseTree.mNowPlayingNode);
- PlaybackState.Builder pbb = new PlaybackState.Builder();
- pbb.setState(PlaybackState.STATE_ERROR, PlaybackState.PLAYBACK_POSITION_UNKNOWN,
- 1.0f).setActions(0);
- pbb.setErrorMessage(mService.getString(R.string.bluetooth_disconnected));
- BluetoothMediaBrowserService.notifyChanged(pbb.build());
mService.sBrowseTree.mRootNode.removeChild(
mBrowseTree.mRootNode);
BluetoothMediaBrowserService.notifyChanged(mService
.sBrowseTree.mRootNode);
- BluetoothMediaBrowserService.trackChanged(null);
mBrowsingConnected = false;
}
@@ -298,8 +296,9 @@ class AvrcpControllerStateMachine extends StateMachine {
@Override
public void enter() {
if (mMostRecentState == BluetoothProfile.STATE_CONNECTING) {
- broadcastConnectionStateChanged(BluetoothProfile.STATE_CONNECTED);
BluetoothMediaBrowserService.addressedPlayerChanged(mSessionCallbacks);
+ BluetoothMediaBrowserService.notifyChanged(mAddressedPlayer.getPlaybackState());
+ broadcastConnectionStateChanged(BluetoothProfile.STATE_CONNECTED);
} else {
logD("ReEnteringConnected");
}
@@ -315,14 +314,14 @@ class AvrcpControllerStateMachine extends StateMachine {
removeMessages(MESSAGE_INTERNAL_ABS_VOL_TIMEOUT);
sendMessageDelayed(MESSAGE_INTERNAL_ABS_VOL_TIMEOUT,
ABS_VOL_TIMEOUT_MILLIS);
- setAbsVolume(msg.arg1, msg.arg2);
+ handleAbsVolumeRequest(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);
+ getAbsVolume(), mVolumeNotificationLabel);
return true;
case MESSAGE_GET_FOLDER_ITEMS:
@@ -338,6 +337,14 @@ class AvrcpControllerStateMachine extends StateMachine {
passThru(msg.arg1);
return true;
+ case MSG_AVRCP_SET_REPEAT:
+ setRepeat(msg.arg1);
+ return true;
+
+ case MSG_AVRCP_SET_SHUFFLE:
+ setShuffle(msg.arg1);
+ return true;
+
case MESSAGE_PROCESS_TRACK_CHANGED:
mAddressedPlayer.updateCurrentTrack((MediaMetadata) msg.obj);
BluetoothMediaBrowserService.trackChanged((MediaMetadata) msg.obj);
@@ -347,11 +354,14 @@ class AvrcpControllerStateMachine extends StateMachine {
mAddressedPlayer.setPlayStatus(msg.arg1);
BluetoothMediaBrowserService.notifyChanged(mAddressedPlayer.getPlaybackState());
if (mAddressedPlayer.getPlaybackState().getState()
- == PlaybackState.STATE_PLAYING
- && A2dpSinkService.getFocusState() == AudioManager.AUDIOFOCUS_NONE
- && !shouldRequestFocus()) {
+ == PlaybackStateCompat.STATE_PLAYING
+ && A2dpSinkService.getFocusState() == AudioManager.AUDIOFOCUS_NONE) {
+ if (shouldRequestFocus()) {
+ mSessionCallbacks.onPrepare();
+ } else {
sendMessage(MSG_AVRCP_PASSTHRU,
AvrcpControllerService.PASS_THRU_CMD_ID_PAUSE);
+ }
}
return true;
@@ -378,6 +388,18 @@ class AvrcpControllerStateMachine extends StateMachine {
}
return true;
+ case MESSAGE_PROCESS_SUPPORTED_APPLICATION_SETTINGS:
+ mAddressedPlayer.setSupportedPlayerApplicationSettings(
+ (PlayerApplicationSettings) msg.obj);
+ BluetoothMediaBrowserService.notifyChanged(mAddressedPlayer.getPlaybackState());
+ return true;
+
+ case MESSAGE_PROCESS_CURRENT_APPLICATION_SETTINGS:
+ mAddressedPlayer.setCurrentPlayerApplicationSettings(
+ (PlayerApplicationSettings) msg.obj);
+ BluetoothMediaBrowserService.notifyChanged(mAddressedPlayer.getPlaybackState());
+ return true;
+
case DISCONNECT:
transitionTo(mDisconnecting);
return true;
@@ -435,6 +457,20 @@ class AvrcpControllerStateMachine extends StateMachine {
return (cmd == AvrcpControllerService.PASS_THRU_CMD_ID_REWIND)
|| (cmd == AvrcpControllerService.PASS_THRU_CMD_ID_FF);
}
+
+ private void setRepeat(int repeatMode) {
+ mService.setPlayerApplicationSettingValuesNative(mDeviceAddress, (byte) 1,
+ new byte[]{PlayerApplicationSettings.REPEAT_STATUS}, new byte[]{
+ PlayerApplicationSettings.mapAvrcpPlayerSettingstoBTattribVal(
+ PlayerApplicationSettings.REPEAT_STATUS, repeatMode)});
+ }
+
+ private void setShuffle(int shuffleMode) {
+ mService.setPlayerApplicationSettingValuesNative(mDeviceAddress, (byte) 1,
+ new byte[]{PlayerApplicationSettings.SHUFFLE_STATUS}, new byte[]{
+ PlayerApplicationSettings.mapAvrcpPlayerSettingstoBTattribVal(
+ PlayerApplicationSettings.SHUFFLE_STATUS, shuffleMode)});
+ }
}
// Handle the get folder listing action
@@ -554,7 +590,7 @@ class AvrcpControllerStateMachine extends StateMachine {
case MESSAGE_GET_FOLDER_ITEMS:
if (!mBrowseNode.equals(msg.obj)) {
if (shouldAbort(mBrowseNode.getScope(),
- ((BrowseTree.BrowseNode) msg.obj).getScope())) {
+ ((BrowseTree.BrowseNode) msg.obj).getScope())) {
mAbort = true;
}
deferMessage(msg);
@@ -576,8 +612,8 @@ class AvrcpControllerStateMachine extends StateMachine {
* necessary.
*
* @return true: a new folder in the same scope
- * a new player while fetching contents of a folder
- * false: other cases, specifically Now Playing while fetching a folder
+ * a new player while fetching contents of a folder
+ * false: other cases, specifically Now Playing while fetching a folder
*/
private boolean shouldAbort(int currentScope, int fetchScope) {
if ((currentScope == fetchScope)
@@ -674,31 +710,60 @@ class AvrcpControllerStateMachine extends StateMachine {
@Override
public void enter() {
onBrowsingDisconnected();
+ BluetoothMediaBrowserService.trackChanged(null);
+ BluetoothMediaBrowserService.addressedPlayerChanged(null);
broadcastConnectionStateChanged(BluetoothProfile.STATE_DISCONNECTING);
transitionTo(mDisconnected);
}
}
+ /**
+ * Handle a request to align our local volume with the volume of a remote device. If
+ * we're assuming the source volume is fixed then a response of ABS_VOL_MAX will always be
+ * sent and no volume adjustment action will be taken on the sink side.
+ *
+ * @param absVol A volume level based on a domain of [0, ABS_VOL_MAX]
+ * @param label Volume notification label
+ */
+ private void handleAbsVolumeRequest(int absVol, int label) {
+ logD("handleAbsVolumeRequest: absVol = " + absVol + ", label = " + label);
+ if (mIsVolumeFixed) {
+ logD("Source volume is assumed to be fixed, responding with max volume");
+ absVol = ABS_VOL_BASE;
+ } else {
+ mVolumeChangedNotificationsToIgnore++;
+ removeMessages(MESSAGE_INTERNAL_ABS_VOL_TIMEOUT);
+ sendMessageDelayed(MESSAGE_INTERNAL_ABS_VOL_TIMEOUT,
+ ABS_VOL_TIMEOUT_MILLIS);
+ setAbsVolume(absVol);
+ }
+ mService.sendAbsVolRspNative(mDeviceAddress, absVol, label);
+ }
+
+ /**
+ * Align our volume with a requested absolute volume level
+ *
+ * @param absVol A volume level based on a domain of [0, ABS_VOL_MAX]
+ */
+ private void setAbsVolume(int absVol) {
+ int maxLocalVolume = mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
+ int curLocalVolume = mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC);
+ int reqLocalVolume = (maxLocalVolume * absVol) / ABS_VOL_BASE;
+ logD("setAbsVolme: absVol = " + absVol + ", reqLocal = " + reqLocalVolume
+ + ", curLocal = " + curLocalVolume + ", maxLocal = " + maxLocalVolume);
- private void setAbsVolume(int absVol, int label) {
- int maxVolume = mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
- int currIndex = mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC);
- int newIndex = (maxVolume * absVol) / ABS_VOL_BASE;
- logD(" setAbsVolume =" + absVol + " maxVol = " + maxVolume
- + " cur = " + currIndex + " new = " + newIndex);
/*
* In some cases change in percentage is not sufficient enough to warrant
* change in index values which are in range of 0-15. For such cases
* no action is required
*/
- if (newIndex != currIndex) {
- mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, newIndex,
+ if (reqLocalVolume != curLocalVolume) {
+ mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, reqLocalVolume,
AudioManager.FLAG_SHOW_UI);
}
- mService.sendAbsVolRspNative(mDeviceAddress, getAbsVolumeResponse(), label);
}
- private int getAbsVolumeResponse() {
+ private int getAbsVolume() {
if (mIsVolumeFixed) {
return ABS_VOL_BASE;
}
@@ -708,7 +773,7 @@ class AvrcpControllerStateMachine extends StateMachine {
return newIndex;
}
- MediaSession.Callback mSessionCallbacks = new MediaSession.Callback() {
+ MediaSessionCompat.Callback mSessionCallbacks = new MediaSessionCompat.Callback() {
@Override
public void onPlay() {
logD("onPlay");
@@ -781,6 +846,19 @@ class AvrcpControllerStateMachine extends StateMachine {
BrowseTree.BrowseNode node = mBrowseTree.findBrowseNodeByID(mediaId);
sendMessage(MESSAGE_PLAY_ITEM, node);
}
+
+ @Override
+ public void onSetRepeatMode(int repeatMode) {
+ logD("onSetRepeatMode");
+ sendMessage(MSG_AVRCP_SET_REPEAT, repeatMode);
+ }
+
+ @Override
+ public void onSetShuffleMode(int shuffleMode) {
+ logD("onSetShuffleMode");
+ sendMessage(MSG_AVRCP_SET_SHUFFLE, shuffleMode);
+
+ }
};
protected void broadcastConnectionStateChanged(int currentState) {