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

Commit 215ccfa3 authored by Joseph Pirozzo's avatar Joseph Pirozzo Committed by android-build-merger
Browse files

Merge "AVRCP Controller Shuffle/Repeat support" am: 9345361d am: 8d142c3a am: 0d12c888

am: f598a2ec

Change-Id: I0e1c51fafb74c015b1dc831eab5806ab53b3df40
parents 1b63e7ca f598a2ec
Loading
Loading
Loading
Loading
+1 −0
Original line number Original line Diff line number Diff line
@@ -29,6 +29,7 @@ LOCAL_STATIC_JAVA_LIBRARIES := \


LOCAL_STATIC_ANDROID_LIBRARIES := \
LOCAL_STATIC_ANDROID_LIBRARIES := \
        androidx.core_core \
        androidx.core_core \
        androidx.legacy_legacy-support-v4 \
        androidx.lifecycle_lifecycle-livedata \
        androidx.lifecycle_lifecycle-livedata \
        androidx.room_room-runtime \
        androidx.room_room-runtime \
        bt-androidx-room-runtime-nodeps \
        bt-androidx-room-runtime-nodeps \
+18 −15
Original line number Original line Diff line number Diff line
@@ -412,9 +412,10 @@ public class AvrcpControllerService extends ProfileService {
        if (stateMachine != null) {
        if (stateMachine != null) {
            PlayerApplicationSettings supportedSettings =
            PlayerApplicationSettings supportedSettings =
                    PlayerApplicationSettings.makeSupportedSettings(playerAttribRsp);
                    PlayerApplicationSettings.makeSupportedSettings(playerAttribRsp);
            stateMachine.sendMessage(
                    AvrcpControllerStateMachine.MESSAGE_PROCESS_SUPPORTED_APPLICATION_SETTINGS,
                    supportedSettings);
        }
        }
        /* Do nothing */

    }
    }


    private synchronized void onPlayerAppSettingChanged(byte[] address, byte[] playerAttribRsp,
    private synchronized void onPlayerAppSettingChanged(byte[] address, byte[] playerAttribRsp,
@@ -426,10 +427,12 @@ public class AvrcpControllerService extends ProfileService {
        AvrcpControllerStateMachine stateMachine = getStateMachine(device);
        AvrcpControllerStateMachine stateMachine = getStateMachine(device);
        if (stateMachine != null) {
        if (stateMachine != null) {


            PlayerApplicationSettings desiredSettings =
            PlayerApplicationSettings currentSettings =
                    PlayerApplicationSettings.makeSettings(playerAttribRsp);
                    PlayerApplicationSettings.makeSettings(playerAttribRsp);
            stateMachine.sendMessage(
                    AvrcpControllerStateMachine.MESSAGE_PROCESS_CURRENT_APPLICATION_SETTINGS,
                    currentSettings);
        }
        }
        /* Do nothing */
    }
    }


    // Browsing related JNI callbacks.
    // Browsing related JNI callbacks.
+63 −11
Original line number Original line Diff line number Diff line
@@ -24,10 +24,10 @@ import android.content.Intent;
import android.media.AudioManager;
import android.media.AudioManager;
import android.media.MediaMetadata;
import android.media.MediaMetadata;
import android.media.browse.MediaBrowser.MediaItem;
import android.media.browse.MediaBrowser.MediaItem;
import android.media.session.MediaSession;
import android.media.session.PlaybackState;
import android.os.Bundle;
import android.os.Bundle;
import android.os.Message;
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.Log;
import android.util.SparseArray;
import android.util.SparseArray;


@@ -42,6 +42,7 @@ import com.android.internal.util.StateMachine;


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

/**
/**
 * Provides Bluetooth AVRCP Controller State Machine responsible for all remote control connections
 * Provides Bluetooth AVRCP Controller State Machine responsible for all remote control connections
 * and interactions with a remote controlable device.
 * 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_SET_ADDRESSED_PLAYER = 214;
    static final int MESSAGE_PROCESS_ADDRESSED_PLAYER_CHANGED = 215;
    static final int MESSAGE_PROCESS_ADDRESSED_PLAYER_CHANGED = 215;
    static final int MESSAGE_PROCESS_NOW_PLAYING_CONTENTS_CHANGED = 216;
    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
    //300->399 Events for Browsing
    static final int MESSAGE_GET_FOLDER_ITEMS = 300;
    static final int MESSAGE_GET_FOLDER_ITEMS = 300;
    static final int MESSAGE_PLAY_ITEM = 301;
    static final int MESSAGE_PLAY_ITEM = 301;
    static final int MSG_AVRCP_PASSTHRU = 302;
    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;
    static final int MESSAGE_INTERNAL_ABS_VOL_TIMEOUT = 404;


@@ -215,12 +220,12 @@ class AvrcpControllerStateMachine extends StateMachine {


    synchronized void onBrowsingDisconnected() {
    synchronized void onBrowsingDisconnected() {
        if (!mBrowsingConnected) return;
        if (!mBrowsingConnected) return;
        mAddressedPlayer.setPlayStatus(PlaybackState.STATE_ERROR);
        mAddressedPlayer.setPlayStatus(PlaybackStateCompat.STATE_ERROR);
        mAddressedPlayer.updateCurrentTrack(null);
        mAddressedPlayer.updateCurrentTrack(null);
        mBrowseTree.mNowPlayingNode.setCached(false);
        mBrowseTree.mNowPlayingNode.setCached(false);
        BluetoothMediaBrowserService.notifyChanged(mBrowseTree.mNowPlayingNode);
        BluetoothMediaBrowserService.notifyChanged(mBrowseTree.mNowPlayingNode);
        PlaybackState.Builder pbb = new PlaybackState.Builder();
        PlaybackStateCompat.Builder pbb = new PlaybackStateCompat.Builder();
        pbb.setState(PlaybackState.STATE_ERROR, PlaybackState.PLAYBACK_POSITION_UNKNOWN,
        pbb.setState(PlaybackStateCompat.STATE_ERROR, PlaybackStateCompat.PLAYBACK_POSITION_UNKNOWN,
                1.0f).setActions(0);
                1.0f).setActions(0);
        pbb.setErrorMessage(mService.getString(R.string.bluetooth_disconnected));
        pbb.setErrorMessage(mService.getString(R.string.bluetooth_disconnected));
        BluetoothMediaBrowserService.notifyChanged(pbb.build());
        BluetoothMediaBrowserService.notifyChanged(pbb.build());
@@ -322,6 +327,14 @@ class AvrcpControllerStateMachine extends StateMachine {
                    passThru(msg.arg1);
                    passThru(msg.arg1);
                    return true;
                    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:
                case MESSAGE_PROCESS_TRACK_CHANGED:
                    mAddressedPlayer.updateCurrentTrack((MediaMetadata) msg.obj);
                    mAddressedPlayer.updateCurrentTrack((MediaMetadata) msg.obj);
                    BluetoothMediaBrowserService.trackChanged((MediaMetadata) msg.obj);
                    BluetoothMediaBrowserService.trackChanged((MediaMetadata) msg.obj);
@@ -331,7 +344,7 @@ class AvrcpControllerStateMachine extends StateMachine {
                    mAddressedPlayer.setPlayStatus(msg.arg1);
                    mAddressedPlayer.setPlayStatus(msg.arg1);
                    BluetoothMediaBrowserService.notifyChanged(mAddressedPlayer.getPlaybackState());
                    BluetoothMediaBrowserService.notifyChanged(mAddressedPlayer.getPlaybackState());
                    if (mAddressedPlayer.getPlaybackState().getState()
                    if (mAddressedPlayer.getPlaybackState().getState()
                            == PlaybackState.STATE_PLAYING
                            == PlaybackStateCompat.STATE_PLAYING
                            && A2dpSinkService.getFocusState() == AudioManager.AUDIOFOCUS_NONE
                            && A2dpSinkService.getFocusState() == AudioManager.AUDIOFOCUS_NONE
                            && !shouldRequestFocus()) {
                            && !shouldRequestFocus()) {
                        sendMessage(MSG_AVRCP_PASSTHRU,
                        sendMessage(MSG_AVRCP_PASSTHRU,
@@ -362,6 +375,18 @@ class AvrcpControllerStateMachine extends StateMachine {
                    }
                    }
                    return true;
                    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:
                case DISCONNECT:
                    transitionTo(mDisconnecting);
                    transitionTo(mDisconnecting);
                    return true;
                    return true;
@@ -419,6 +444,20 @@ class AvrcpControllerStateMachine extends StateMachine {
            return (cmd == AvrcpControllerService.PASS_THRU_CMD_ID_REWIND)
            return (cmd == AvrcpControllerService.PASS_THRU_CMD_ID_REWIND)
                    || (cmd == AvrcpControllerService.PASS_THRU_CMD_ID_FF);
                    || (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
    // Handle the get folder listing action
@@ -697,7 +736,7 @@ class AvrcpControllerStateMachine extends StateMachine {
        mService.sendAbsVolRspNative(mDeviceAddress, absVol, label);
        mService.sendAbsVolRspNative(mDeviceAddress, absVol, label);
    }
    }


    MediaSession.Callback mSessionCallbacks = new MediaSession.Callback() {
    MediaSessionCompat.Callback mSessionCallbacks = new MediaSessionCompat.Callback() {
        @Override
        @Override
        public void onPlay() {
        public void onPlay() {
            logD("onPlay");
            logD("onPlay");
@@ -770,6 +809,19 @@ class AvrcpControllerStateMachine extends StateMachine {
            BrowseTree.BrowseNode node = mBrowseTree.findBrowseNodeByID(mediaId);
            BrowseTree.BrowseNode node = mBrowseTree.findBrowseNodeByID(mediaId);
            sendMessage(MESSAGE_PLAY_ITEM, node);
            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) {
    protected void broadcastConnectionStateChanged(int currentState) {
+71 −31
Original line number Original line Diff line number Diff line
@@ -17,8 +17,9 @@
package com.android.bluetooth.avrcpcontroller;
package com.android.bluetooth.avrcpcontroller;


import android.media.MediaMetadata;
import android.media.MediaMetadata;
import android.media.session.PlaybackState;
import android.os.SystemClock;
import android.os.SystemClock;
import android.support.v4.media.session.MediaSessionCompat;
import android.support.v4.media.session.PlaybackStateCompat;
import android.util.Log;
import android.util.Log;


import java.util.Arrays;
import java.util.Arrays;
@@ -41,27 +42,31 @@ class AvrcpPlayer {
    public static final int FEATURE_PREVIOUS = 48;
    public static final int FEATURE_PREVIOUS = 48;
    public static final int FEATURE_BROWSING = 59;
    public static final int FEATURE_BROWSING = 59;


    private int mPlayStatus = PlaybackState.STATE_NONE;
    private int mPlayStatus = PlaybackStateCompat.STATE_NONE;
    private long mPlayTime = PlaybackState.PLAYBACK_POSITION_UNKNOWN;
    private long mPlayTime = PlaybackStateCompat.PLAYBACK_POSITION_UNKNOWN;
    private long mPlayTimeUpdate = 0;
    private long mPlayTimeUpdate = 0;
    private float mPlaySpeed = 1;
    private float mPlaySpeed = 1;
    private int mId;
    private int mId;
    private String mName = "";
    private String mName = "";
    private int mPlayerType;
    private int mPlayerType;
    private byte[] mPlayerFeatures;
    private byte[] mPlayerFeatures = new byte[16];
    private long mAvailableActions;
    private long mAvailableActions;
    private MediaMetadata mCurrentTrack;
    private MediaMetadata mCurrentTrack;
    private PlaybackState mPlaybackState;
    private PlaybackStateCompat mPlaybackStateCompat;
    private PlayerApplicationSettings mSupportedPlayerApplicationSettings =
            new PlayerApplicationSettings();
    private PlayerApplicationSettings mCurrentPlayerApplicationSettings;


    AvrcpPlayer() {
    AvrcpPlayer() {
        mId = INVALID_ID;
        mId = INVALID_ID;
        //Set Default Actions in case Player data isn't available.
        //Set Default Actions in case Player data isn't available.
        mAvailableActions = PlaybackState.ACTION_PAUSE | PlaybackState.ACTION_PLAY
        mAvailableActions = PlaybackStateCompat.ACTION_PAUSE | PlaybackStateCompat.ACTION_PLAY
                | PlaybackState.ACTION_SKIP_TO_NEXT | PlaybackState.ACTION_SKIP_TO_PREVIOUS
                | PlaybackStateCompat.ACTION_SKIP_TO_NEXT
                | PlaybackState.ACTION_STOP;
                | PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS
        PlaybackState.Builder playbackStateBuilder = new PlaybackState.Builder()
                | PlaybackStateCompat.ACTION_STOP;
        PlaybackStateCompat.Builder playbackStateBuilder = new PlaybackStateCompat.Builder()
                .setActions(mAvailableActions);
                .setActions(mAvailableActions);
        mPlaybackState = playbackStateBuilder.build();
        mPlaybackStateCompat = playbackStateBuilder.build();
    }
    }


    AvrcpPlayer(int id, String name, byte[] playerFeatures, int playStatus, int playerType) {
    AvrcpPlayer(int id, String name, byte[] playerFeatures, int playStatus, int playerType) {
@@ -70,10 +75,10 @@ class AvrcpPlayer {
        mPlayStatus = playStatus;
        mPlayStatus = playStatus;
        mPlayerType = playerType;
        mPlayerType = playerType;
        mPlayerFeatures = Arrays.copyOf(playerFeatures, playerFeatures.length);
        mPlayerFeatures = Arrays.copyOf(playerFeatures, playerFeatures.length);
        updateAvailableActions();
        PlaybackStateCompat.Builder playbackStateBuilder = new PlaybackStateCompat.Builder()
        PlaybackState.Builder playbackStateBuilder = new PlaybackState.Builder()
                .setActions(mAvailableActions);
                .setActions(mAvailableActions);
        mPlaybackState = playbackStateBuilder.build();
        mPlaybackStateCompat = playbackStateBuilder.build();
        updateAvailableActions();
    }
    }


    public int getId() {
    public int getId() {
@@ -87,7 +92,8 @@ class AvrcpPlayer {
    public void setPlayTime(int playTime) {
    public void setPlayTime(int playTime) {
        mPlayTime = playTime;
        mPlayTime = playTime;
        mPlayTimeUpdate = SystemClock.elapsedRealtime();
        mPlayTimeUpdate = SystemClock.elapsedRealtime();
        mPlaybackState = new PlaybackState.Builder(mPlaybackState).setState(mPlayStatus, mPlayTime,
        mPlaybackStateCompat = new PlaybackStateCompat.Builder(mPlaybackStateCompat).setState(
                mPlayStatus, mPlayTime,
                mPlaySpeed).build();
                mPlaySpeed).build();
    }
    }


@@ -97,30 +103,48 @@ class AvrcpPlayer {


    public void setPlayStatus(int playStatus) {
    public void setPlayStatus(int playStatus) {
        mPlayTime += mPlaySpeed * (SystemClock.elapsedRealtime()
        mPlayTime += mPlaySpeed * (SystemClock.elapsedRealtime()
                - mPlaybackState.getLastPositionUpdateTime());
                - mPlaybackStateCompat.getLastPositionUpdateTime());
        mPlayStatus = playStatus;
        mPlayStatus = playStatus;
        switch (mPlayStatus) {
        switch (mPlayStatus) {
            case PlaybackState.STATE_STOPPED:
            case PlaybackStateCompat.STATE_STOPPED:
                mPlaySpeed = 0;
                mPlaySpeed = 0;
                break;
                break;
            case PlaybackState.STATE_PLAYING:
            case PlaybackStateCompat.STATE_PLAYING:
                mPlaySpeed = 1;
                mPlaySpeed = 1;
                break;
                break;
            case PlaybackState.STATE_PAUSED:
            case PlaybackStateCompat.STATE_PAUSED:
                mPlaySpeed = 0;
                mPlaySpeed = 0;
                break;
                break;
            case PlaybackState.STATE_FAST_FORWARDING:
            case PlaybackStateCompat.STATE_FAST_FORWARDING:
                mPlaySpeed = 3;
                mPlaySpeed = 3;
                break;
                break;
            case PlaybackState.STATE_REWINDING:
            case PlaybackStateCompat.STATE_REWINDING:
                mPlaySpeed = -3;
                mPlaySpeed = -3;
                break;
                break;
        }
        }


        mPlaybackState = new PlaybackState.Builder(mPlaybackState).setState(mPlayStatus, mPlayTime,
        mPlaybackStateCompat = new PlaybackStateCompat.Builder(mPlaybackStateCompat).setState(
                mPlayStatus, mPlayTime,
                mPlaySpeed).build();
                mPlaySpeed).build();
    }
    }


    public void setSupportedPlayerApplicationSettings(
            PlayerApplicationSettings playerApplicationSettings) {
        mSupportedPlayerApplicationSettings = playerApplicationSettings;
        updateAvailableActions();
    }

    public void setCurrentPlayerApplicationSettings(
            PlayerApplicationSettings playerApplicationSettings) {
        Log.d(TAG, "Settings changed");
        mCurrentPlayerApplicationSettings = playerApplicationSettings;
        MediaSessionCompat session = BluetoothMediaBrowserService.getSession();
        session.setRepeatMode(mCurrentPlayerApplicationSettings.getSetting(
                PlayerApplicationSettings.REPEAT_STATUS));
        session.setShuffleMode(mCurrentPlayerApplicationSettings.getSetting(
                PlayerApplicationSettings.SHUFFLE_STATUS));
    }

    public int getPlayStatus() {
    public int getPlayStatus() {
        return mPlayStatus;
        return mPlayStatus;
    }
    }
@@ -131,17 +155,22 @@ class AvrcpPlayer {
        return (mPlayerFeatures[byteNumber] & bitMask) == bitMask;
        return (mPlayerFeatures[byteNumber] & bitMask) == bitMask;
    }
    }


    public PlaybackState getPlaybackState() {
    public boolean supportsSetting(int settingType, int settingValue) {
        return mSupportedPlayerApplicationSettings.supportsSetting(settingType, settingValue);
    }

    public PlaybackStateCompat getPlaybackState() {
        if (DBG) {
        if (DBG) {
            Log.d(TAG, "getPlayBackState state " + mPlayStatus + " time " + mPlayTime);
            Log.d(TAG, "getPlayBackState state " + mPlayStatus + " time " + mPlayTime);
        }
        }
        return mPlaybackState;
        return mPlaybackStateCompat;
    }
    }


    public synchronized void updateCurrentTrack(MediaMetadata update) {
    public synchronized void updateCurrentTrack(MediaMetadata update) {
        if (update != null) {
        if (update != null) {
            long trackNumber = update.getLong(MediaMetadata.METADATA_KEY_TRACK_NUMBER);
            long trackNumber = update.getLong(MediaMetadata.METADATA_KEY_TRACK_NUMBER);
            mPlaybackState = new PlaybackState.Builder(mPlaybackState).setActiveQueueItemId(
            mPlaybackStateCompat = new PlaybackStateCompat.Builder(
                    mPlaybackStateCompat).setActiveQueueItemId(
                    trackNumber - 1).build();
                    trackNumber - 1).build();
        }
        }
        mCurrentTrack = update;
        mCurrentTrack = update;
@@ -153,26 +182,37 @@ class AvrcpPlayer {


    private void updateAvailableActions() {
    private void updateAvailableActions() {
        if (supportsFeature(FEATURE_PLAY)) {
        if (supportsFeature(FEATURE_PLAY)) {
            mAvailableActions = mAvailableActions | PlaybackState.ACTION_PLAY;
            mAvailableActions = mAvailableActions | PlaybackStateCompat.ACTION_PLAY;
        }
        }
        if (supportsFeature(FEATURE_STOP)) {
        if (supportsFeature(FEATURE_STOP)) {
            mAvailableActions = mAvailableActions | PlaybackState.ACTION_STOP;
            mAvailableActions = mAvailableActions | PlaybackStateCompat.ACTION_STOP;
        }
        }
        if (supportsFeature(FEATURE_PAUSE)) {
        if (supportsFeature(FEATURE_PAUSE)) {
            mAvailableActions = mAvailableActions | PlaybackState.ACTION_PAUSE;
            mAvailableActions = mAvailableActions | PlaybackStateCompat.ACTION_PAUSE;
        }
        }
        if (supportsFeature(FEATURE_REWIND)) {
        if (supportsFeature(FEATURE_REWIND)) {
            mAvailableActions = mAvailableActions | PlaybackState.ACTION_REWIND;
            mAvailableActions = mAvailableActions | PlaybackStateCompat.ACTION_REWIND;
        }
        }
        if (supportsFeature(FEATURE_FAST_FORWARD)) {
        if (supportsFeature(FEATURE_FAST_FORWARD)) {
            mAvailableActions = mAvailableActions | PlaybackState.ACTION_FAST_FORWARD;
            mAvailableActions = mAvailableActions | PlaybackStateCompat.ACTION_FAST_FORWARD;
        }
        }
        if (supportsFeature(FEATURE_FORWARD)) {
        if (supportsFeature(FEATURE_FORWARD)) {
            mAvailableActions = mAvailableActions | PlaybackState.ACTION_SKIP_TO_NEXT;
            mAvailableActions = mAvailableActions | PlaybackStateCompat.ACTION_SKIP_TO_NEXT;
        }
        }
        if (supportsFeature(FEATURE_PREVIOUS)) {
        if (supportsFeature(FEATURE_PREVIOUS)) {
            mAvailableActions = mAvailableActions | PlaybackState.ACTION_SKIP_TO_PREVIOUS;
            mAvailableActions = mAvailableActions | PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS;
        }
        }
        if (mSupportedPlayerApplicationSettings.supportsSetting(
                PlayerApplicationSettings.REPEAT_STATUS)) {
            mAvailableActions |= PlaybackStateCompat.ACTION_SET_REPEAT_MODE;
        }
        if (mSupportedPlayerApplicationSettings.supportsSetting(
                PlayerApplicationSettings.SHUFFLE_STATUS)) {
            mAvailableActions |= PlaybackStateCompat.ACTION_SET_SHUFFLE_MODE;
        }
        mPlaybackStateCompat = new PlaybackStateCompat.Builder(mPlaybackStateCompat)
                .setActions(mAvailableActions).build();

        if (DBG) Log.d(TAG, "Supported Actions = " + mAvailableActions);
        if (DBG) Log.d(TAG, "Supported Actions = " + mAvailableActions);
    }
    }
}
}
+46 −26
Original line number Original line Diff line number Diff line
@@ -18,13 +18,17 @@ package com.android.bluetooth.avrcpcontroller;


import android.media.MediaMetadata;
import android.media.MediaMetadata;
import android.media.browse.MediaBrowser.MediaItem;
import android.media.browse.MediaBrowser.MediaItem;
import android.media.session.MediaController;
import android.media.session.MediaSession;
import android.media.session.PlaybackState;
import android.os.Bundle;
import android.os.Bundle;
import android.service.media.MediaBrowserService;
import android.support.v4.media.MediaBrowserCompat;
import android.support.v4.media.MediaDescriptionCompat;
import android.support.v4.media.MediaMetadataCompat;
import android.support.v4.media.session.MediaControllerCompat;
import android.support.v4.media.session.MediaSessionCompat;
import android.support.v4.media.session.PlaybackStateCompat;
import android.util.Log;
import android.util.Log;


import androidx.media.MediaBrowserServiceCompat;

import com.android.bluetooth.R;
import com.android.bluetooth.R;


import java.util.ArrayList;
import java.util.ArrayList;
@@ -37,43 +41,44 @@ import java.util.List;
 * The applications are expected to use MediaBrowser (see API) and all the music
 * The applications are expected to use MediaBrowser (see API) and all the music
 * browsing/playback/metadata can be controlled via MediaBrowser and MediaController.
 * browsing/playback/metadata can be controlled via MediaBrowser and MediaController.
 *
 *
 * The current behavior of MediaSession exposed by this service is as follows:
 * The current behavior of MediaSessionCompat exposed by this service is as follows:
 * 1. MediaSession is active (i.e. SystemUI and other overview UIs can see updates) when device is
 * 1. MediaSessionCompat is active (i.e. SystemUI and other overview UIs can see updates) when
 * connected and first starts playing. Before it starts playing we do not active the session.
 * device is connected and first starts playing. Before it starts playing we do not activate the
 * session.
 * 1.1 The session is active throughout the duration of connection.
 * 1.1 The session is active throughout the duration of connection.
 * 2. The session is de-activated when the device disconnects. It will be connected again when (1)
 * 2. The session is de-activated when the device disconnects. It will be connected again when (1)
 * happens.
 * happens.
 */
 */
public class BluetoothMediaBrowserService extends MediaBrowserService {
public class BluetoothMediaBrowserService extends MediaBrowserServiceCompat {
    private static final String TAG = "BluetoothMediaBrowserService";
    private static final String TAG = "BluetoothMediaBrowserService";
    private static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
    private static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);


    private static BluetoothMediaBrowserService sBluetoothMediaBrowserService;
    private static BluetoothMediaBrowserService sBluetoothMediaBrowserService;


    private MediaSession mSession;
    private MediaSessionCompat mSession;


    // Browsing related structures.
    // Browsing related structures.
    private List<MediaSession.QueueItem> mMediaQueue = new ArrayList<>();
    private List<MediaSessionCompat.QueueItem> mMediaQueue = new ArrayList<>();


    /**
    /**
     * Initialize this BluetoothMediaBrowserService, creating our MediaSession, MediaPlayer and
     * Initialize this BluetoothMediaBrowserService, creating our MediaSessionCompat, MediaPlayer
     * MediaMetaData, and setting up mechanisms to talk with the AvrcpControllerService.
     * and MediaMetaData, and setting up mechanisms to talk with the AvrcpControllerService.
     */
     */
    @Override
    @Override
    public void onCreate() {
    public void onCreate() {
        if (DBG) Log.d(TAG, "onCreate");
        if (DBG) Log.d(TAG, "onCreate");
        super.onCreate();
        super.onCreate();


        // Create and configure the MediaSession
        // Create and configure the MediaSessionCompat
        mSession = new MediaSession(this, TAG);
        mSession = new MediaSessionCompat(this, TAG);
        setSessionToken(mSession.getSessionToken());
        setSessionToken(mSession.getSessionToken());
        mSession.setFlags(MediaSession.FLAG_HANDLES_MEDIA_BUTTONS
        mSession.setFlags(MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS
                | MediaSession.FLAG_HANDLES_TRANSPORT_CONTROLS);
                | MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS);
        mSession.setQueueTitle(getString(R.string.bluetooth_a2dp_sink_queue_name));
        mSession.setQueueTitle(getString(R.string.bluetooth_a2dp_sink_queue_name));
        mSession.setQueue(mMediaQueue);
        mSession.setQueue(mMediaQueue);
        PlaybackState.Builder playbackStateBuilder = new PlaybackState.Builder();
        PlaybackStateCompat.Builder playbackStateBuilder = new PlaybackStateCompat.Builder();
        playbackStateBuilder.setState(PlaybackState.STATE_ERROR,
        playbackStateBuilder.setState(PlaybackStateCompat.STATE_ERROR,
                PlaybackState.PLAYBACK_POSITION_UNKNOWN, 1.0f).setActions(0);
                PlaybackStateCompat.PLAYBACK_POSITION_UNKNOWN, 1.0f).setActions(0);
        playbackStateBuilder.setErrorMessage(getString(R.string.bluetooth_disconnected));
        playbackStateBuilder.setErrorMessage(getString(R.string.bluetooth_disconnected));
        mSession.setPlaybackState(playbackStateBuilder.build());
        mSession.setPlaybackState(playbackStateBuilder.build());
        sBluetoothMediaBrowserService = this;
        sBluetoothMediaBrowserService = this;
@@ -91,9 +96,10 @@ public class BluetoothMediaBrowserService extends MediaBrowserService {


    @Override
    @Override
    public synchronized void onLoadChildren(final String parentMediaId,
    public synchronized void onLoadChildren(final String parentMediaId,
            final Result<List<MediaItem>> result) {
            final Result<List<MediaBrowserCompat.MediaItem>> result) {
        if (DBG) Log.d(TAG, "onLoadChildren parentMediaId=" + parentMediaId);
        if (DBG) Log.d(TAG, "onLoadChildren parentMediaId=" + parentMediaId);
        List<MediaItem> contents = getContents(parentMediaId);
        List<MediaBrowserCompat.MediaItem> contents =
                MediaBrowserCompat.MediaItem.fromMediaItemList(getContents(parentMediaId));
        if (contents == null) {
        if (contents == null) {
            result.detach();
            result.detach();
        } else {
        } else {
@@ -112,7 +118,8 @@ public class BluetoothMediaBrowserService extends MediaBrowserService {
        mMediaQueue.clear();
        mMediaQueue.clear();
        if (songList != null) {
        if (songList != null) {
            for (MediaItem song : songList) {
            for (MediaItem song : songList) {
                mMediaQueue.add(new MediaSession.QueueItem(song.getDescription(),
                mMediaQueue.add(new MediaSessionCompat.QueueItem(
                        MediaDescriptionCompat.fromMediaDescription(song.getDescription()),
                        mMediaQueue.size()));
                        mMediaQueue.size()));
            }
            }
        }
        }
@@ -129,7 +136,7 @@ public class BluetoothMediaBrowserService extends MediaBrowserService {
        }
        }
    }
    }


    static synchronized void addressedPlayerChanged(MediaSession.Callback callback) {
    static synchronized void addressedPlayerChanged(MediaSessionCompat.Callback callback) {
        if (sBluetoothMediaBrowserService != null) {
        if (sBluetoothMediaBrowserService != null) {
            sBluetoothMediaBrowserService.mSession.setCallback(callback);
            sBluetoothMediaBrowserService.mSession.setCallback(callback);
        } else {
        } else {
@@ -139,13 +146,14 @@ public class BluetoothMediaBrowserService extends MediaBrowserService {


    static synchronized void trackChanged(MediaMetadata mediaMetadata) {
    static synchronized void trackChanged(MediaMetadata mediaMetadata) {
        if (sBluetoothMediaBrowserService != null) {
        if (sBluetoothMediaBrowserService != null) {
            sBluetoothMediaBrowserService.mSession.setMetadata(mediaMetadata);
            sBluetoothMediaBrowserService.mSession.setMetadata(
                    MediaMetadataCompat.fromMediaMetadata(mediaMetadata));
        } else {
        } else {
            Log.w(TAG, "trackChanged Unavailable");
            Log.w(TAG, "trackChanged Unavailable");
        }
        }
    }
    }


    static synchronized void notifyChanged(PlaybackState playbackState) {
    static synchronized void notifyChanged(PlaybackStateCompat playbackState) {
        Log.d(TAG, "notifyChanged PlaybackState" + playbackState);
        Log.d(TAG, "notifyChanged PlaybackState" + playbackState);
        if (sBluetoothMediaBrowserService != null) {
        if (sBluetoothMediaBrowserService != null) {
            sBluetoothMediaBrowserService.mSession.setPlaybackState(playbackState);
            sBluetoothMediaBrowserService.mSession.setPlaybackState(playbackState);
@@ -179,7 +187,7 @@ public class BluetoothMediaBrowserService extends MediaBrowserService {
    /**
    /**
     * Get object for controlling playback
     * Get object for controlling playback
     */
     */
    public static synchronized MediaController.TransportControls getTransportControls() {
    public static synchronized MediaControllerCompat.TransportControls getTransportControls() {
        if (sBluetoothMediaBrowserService != null) {
        if (sBluetoothMediaBrowserService != null) {
            return sBluetoothMediaBrowserService.mSession.getController().getTransportControls();
            return sBluetoothMediaBrowserService.mSession.getController().getTransportControls();
        } else {
        } else {
@@ -198,4 +206,16 @@ public class BluetoothMediaBrowserService extends MediaBrowserService {
            Log.w(TAG, "setActive Unavailable");
            Log.w(TAG, "setActive Unavailable");
        }
        }
    }
    }

    /**
     * Get Media session for updating state
     */
    public static synchronized MediaSessionCompat getSession() {
        if (sBluetoothMediaBrowserService != null) {
            return sBluetoothMediaBrowserService.mSession;
        } else {
            Log.w(TAG, "getSession Unavailable");
            return null;
        }
    }
}
}
Loading