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

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

Merge "AVRCP Controller Player Capabilities" am: 41f2785c

am: e3e2c184

Change-Id: Ib901888be85681ed53b0f79ab232532a4fb362c0
parents 26b9d812 e3e2c184
Loading
Loading
Loading
Loading
+17 −1
Original line number Diff line number Diff line
@@ -46,6 +46,7 @@ static jmethodID method_createFromNativePlayerItem;
static jmethodID method_handleChangeFolderRsp;
static jmethodID method_handleSetBrowsedPlayerRsp;
static jmethodID method_handleSetAddressedPlayerRsp;
static jmethodID method_handleAddressedPlayerChanged;

static jclass class_MediaBrowser_MediaItem;
static jclass class_AvrcpPlayer;
@@ -579,6 +580,17 @@ static void btavrcp_set_addressed_player_callback(const RawAddress& bd_addr,
      sCallbacksObj, method_handleSetAddressedPlayerRsp, (jint)status);
}

static void btavrcp_addressed_player_changed_callback(const RawAddress& bd_addr,
                                                      uint16_t id) {
  ALOGI("%s status %d", __func__, id);

  CallbackEnv sCallbackEnv(__func__);
  if (!sCallbackEnv.valid()) return;

  sCallbackEnv->CallVoidMethod(sCallbacksObj,
                               method_handleAddressedPlayerChanged, (jint)id);
}

static btrc_ctrl_callbacks_t sBluetoothAvrcpCallbacks = {
    sizeof(sBluetoothAvrcpCallbacks),
    btavrcp_passthrough_response_callback,
@@ -596,7 +608,8 @@ static btrc_ctrl_callbacks_t sBluetoothAvrcpCallbacks = {
    btavrcp_get_folder_items_callback,
    btavrcp_change_path_callback,
    btavrcp_set_browsed_player_callback,
    btavrcp_set_addressed_player_callback};
    btavrcp_set_addressed_player_callback,
    btavrcp_addressed_player_changed_callback};

static void classInitNative(JNIEnv* env, jclass clazz) {
  method_handlePassthroughRsp =
@@ -658,6 +671,9 @@ static void classInitNative(JNIEnv* env, jclass clazz) {
      env->GetMethodID(clazz, "handleSetBrowsedPlayerRsp", "(II)V");
  method_handleSetAddressedPlayerRsp =
      env->GetMethodID(clazz, "handleSetAddressedPlayerRsp", "(I)V");
  method_handleAddressedPlayerChanged =
      env->GetMethodID(clazz, "handleAddressedPlayerChanged", "(I)V");

  ALOGI("%s: succeeds", __func__);
}

+19 −11
Original line number Diff line number Diff line
@@ -106,13 +106,11 @@ public class A2dpMediaBrowserService extends MediaBrowserService {
    private A2dpSinkService mA2dpSinkService = null;
    private Handler mAvrcpCommandQueue;
    private final Map<String, Result<List<MediaItem>>> mParentIdToRequestMap = new HashMap<>();
    private int mCurrentlyHeldKey = 0;

    // Browsing related structures.
    private List<MediaItem> mNowPlayingList = null;

    private long mTransportControlFlags = PlaybackState.ACTION_PAUSE | PlaybackState.ACTION_PLAY
            | PlaybackState.ACTION_SKIP_TO_NEXT | PlaybackState.ACTION_SKIP_TO_PREVIOUS;

    private static final class AvrcpCommandQueueHandler extends Handler {
        WeakReference<A2dpMediaBrowserService> mInst;

@@ -408,10 +406,6 @@ public class A2dpMediaBrowserService extends MediaBrowserService {
        mA2dpSinkService = A2dpSinkService.getA2dpSinkService();

        PlaybackState playbackState = mAvrcpCtrlSrvc.getPlaybackState(mA2dpDevice);
        // Add actions required for playback and rebuild the object.
        PlaybackState.Builder pbb = new PlaybackState.Builder(playbackState);
        playbackState = pbb.setActions(mTransportControlFlags).build();

        MediaMetadata mediaMetadata = mAvrcpCtrlSrvc.getMetaData(mA2dpDevice);
        if (VDBG) {
            Log.d(TAG, "Media metadata " + mediaMetadata + " playback state " + playbackState);
@@ -435,7 +429,6 @@ public class A2dpMediaBrowserService extends MediaBrowserService {
        PlaybackState.Builder pbb = new PlaybackState.Builder();
        pbb = pbb.setState(PlaybackState.STATE_ERROR, PlaybackState.PLAYBACK_POSITION_UNKNOWN,
                PLAYBACK_SPEED)
                .setActions(mTransportControlFlags)
                .setErrorMessage(getString(R.string.bluetooth_disconnected));
        mSession.setPlaybackState(pbb.build());

@@ -470,8 +463,6 @@ public class A2dpMediaBrowserService extends MediaBrowserService {

        if (pb != null) {
            if (DBG) Log.d(TAG, "msgTrack() playbackstate " + pb);
            PlaybackState.Builder pbb = new PlaybackState.Builder(pb);
            pb = pbb.setActions(mTransportControlFlags).build();
            mSession.setPlaybackState(pb);

            // If we are now playing then we should start pushing updates via MediaSession so that
@@ -482,6 +473,11 @@ public class A2dpMediaBrowserService extends MediaBrowserService {
        }
    }

    private boolean isHoldableKey(int cmd) {
        return  (cmd == AvrcpControllerService.PASS_THRU_CMD_ID_REWIND)
                || (cmd == AvrcpControllerService.PASS_THRU_CMD_ID_FF);
    }

    private synchronized void msgPassThru(int cmd) {
        if (DBG) Log.d(TAG, "msgPassThru " + cmd);
        if (mA2dpDevice == null) {
@@ -489,13 +485,25 @@ public class A2dpMediaBrowserService extends MediaBrowserService {
            Log.w(TAG, "Already disconnected ignoring.");
            return;
        }
        // Some keys should be held until the next event.
        if (mCurrentlyHeldKey != 0) {
            mAvrcpCtrlSrvc.sendPassThroughCmd(mA2dpDevice, mCurrentlyHeldKey,
                    AvrcpControllerService.KEY_STATE_RELEASED);
            mCurrentlyHeldKey = 0;
        }

        // Send the pass through.
        mAvrcpCtrlSrvc.sendPassThroughCmd(mA2dpDevice, cmd,
                AvrcpControllerService.KEY_STATE_PRESSED);

        if (isHoldableKey(cmd)) {
            // Release cmd next time a command is sent.
            mCurrentlyHeldKey = cmd;
        } else {
            mAvrcpCtrlSrvc.sendPassThroughCmd(mA2dpDevice, cmd,
                AvrcpControllerService.KEY_STATE_RELEASED);
        }
    }

    private synchronized void msgGetPlayStatusNative() {
        if (DBG) Log.d(TAG, "msgGetPlayStatusNative");
+10 −1
Original line number Diff line number Diff line
@@ -1031,7 +1031,7 @@ public class AvrcpControllerService extends ProfileService {
                    "createFromNativePlayerItem name: " + name + " transportFlags " + transportFlags
                            + " play status " + playStatus + " player type " + playerType);
        }
        AvrcpPlayer player = new AvrcpPlayer(id, name, 0, playStatus, playerType);
        AvrcpPlayer player = new AvrcpPlayer(id, name, transportFlags, playStatus, playerType);
        return player;
    }

@@ -1063,6 +1063,15 @@ public class AvrcpControllerService extends ProfileService {
        mAvrcpCtSm.sendMessage(msg);
    }

    private void handleAddressedPlayerChanged(int id) {
        if (DBG) {
            Log.d(TAG, "handleAddressedPlayerChanged id: " + id);
        }
        Message msg = mAvrcpCtSm.obtainMessage(
                AvrcpControllerStateMachine.MESSAGE_PROCESS_ADDRESSED_PLAYER_CHANGED, id);
        mAvrcpCtSm.sendMessage(msg);
    }

    @Override
    public void dump(StringBuilder sb) {
        super.dump(sb);
+25 −0
Original line number Diff line number Diff line
@@ -32,6 +32,7 @@ import android.media.session.PlaybackState;
import android.os.Bundle;
import android.os.Message;
import android.util.Log;
import android.util.SparseArray;

import com.android.bluetooth.BluetoothMetricsProto;
import com.android.bluetooth.Utils;
@@ -73,6 +74,7 @@ class AvrcpControllerStateMachine extends StateMachine {
    static final int MESSAGE_PROCESS_FOLDER_PATH = 112;
    static final int MESSAGE_PROCESS_SET_BROWSED_PLAYER = 113;
    static final int MESSAGE_PROCESS_SET_ADDRESSED_PLAYER = 114;
    static final int MESSAGE_PROCESS_ADDRESSED_PLAYER_CHANGED = 115;

    // commands from A2DP sink
    static final int MESSAGE_STOP_METADATA_BROADCASTS = 201;
@@ -136,6 +138,8 @@ class AvrcpControllerStateMachine extends StateMachine {
    // Only accessed from State Machine processMessage
    private int mVolumeChangedNotificationsToIgnore = 0;
    private int mPreviousPercentageVol = -1;
    private int mAddressedPlayerID = -1;
    private SparseArray<AvrcpPlayer> mAvailablePlayerList = new SparseArray<AvrcpPlayer>();

    // Depth from root of current browsing. This can be used to move to root directly.
    private int mBrowseDepth = 0;
@@ -458,6 +462,17 @@ class AvrcpControllerStateMachine extends StateMachine {
                        }
                        break;

                    case MESSAGE_PROCESS_ADDRESSED_PLAYER_CHANGED:
                        mAddressedPlayerID = msg.arg1;
                        if (DBG) Log.d(TAG, "AddressedPlayer = " + mAddressedPlayerID);
                        AvrcpPlayer updatedPlayer = mAvailablePlayerList.get(mAddressedPlayerID);
                        if (updatedPlayer != null) {
                            mAddressedPlayer = updatedPlayer;
                            if (DBG) Log.d(TAG, "AddressedPlayer = " + mAddressedPlayer.getName());
                        }
                        sendMessage(MESSAGE_PROCESS_SET_ADDRESSED_PLAYER);
                        break;

                    default:
                        return false;
                }
@@ -729,12 +744,22 @@ class AvrcpControllerStateMachine extends StateMachine {
            switch (msg.what) {
                case MESSAGE_PROCESS_GET_PLAYER_ITEMS:
                    List<AvrcpPlayer> playerList = (List<AvrcpPlayer>) msg.obj;
                    mAvailablePlayerList.clear();
                    for (AvrcpPlayer player : playerList) {
                        mAvailablePlayerList.put(player.getId(), player);
                    }
                    mBrowseTree.refreshChildren(BrowseTree.ROOT, playerList);
                    ArrayList<MediaItem> mediaItemList = new ArrayList<>();
                    for (BrowseTree.BrowseNode c : mBrowseTree.findBrowseNodeByID(BrowseTree.ROOT)
                            .getChildren()) {
                        mediaItemList.add(c.getMediaItem());
                    }
                    if (DBG) Log.d(TAG, "AddressedPlayer List Updated");
                    AvrcpPlayer updatedPlayer = mAvailablePlayerList.get(mAddressedPlayerID);
                    if (updatedPlayer != null) {
                        mAddressedPlayer = updatedPlayer;
                        if (DBG) Log.d(TAG, "AddressedPlayer = " + mAddressedPlayer.getName());
                    }
                    broadcastFolderList(BrowseTree.ROOT, mediaItemList);
                    mBrowseTree.setCurrentBrowsedFolder(BrowseTree.ROOT);
                    transitionTo(mConnected);
+57 −2
Original line number Diff line number Diff line
@@ -19,6 +19,8 @@ package com.android.bluetooth.avrcpcontroller;
import android.media.session.PlaybackState;
import android.util.Log;

import java.util.Arrays;

/*
 * Contains information about remote player
 */
@@ -28,21 +30,38 @@ class AvrcpPlayer {

    public static final int INVALID_ID = -1;

    public static final int FEATURE_PLAY = 40;
    public static final int FEATURE_STOP = 41;
    public static final int FEATURE_PAUSE = 42;
    public static final int FEATURE_REWIND = 44;
    public static final int FEATURE_FAST_FORWARD = 45;
    public static final int FEATURE_FORWARD = 47;
    public static final int FEATURE_PREVIOUS = 48;
    public static final int FEATURE_BROWSING = 59;

    private int mPlayStatus = PlaybackState.STATE_NONE;
    private long mPlayTime = PlaybackState.PLAYBACK_POSITION_UNKNOWN;
    private int mId;
    private String mName = "";
    private int mPlayerType;
    private byte[] mPlayerFeatures;
    private long mAvailableActions;
    private TrackInfo mCurrentTrack = new TrackInfo();

    AvrcpPlayer() {
        mId = INVALID_ID;
        //Set Default Actions in case Player data isn't available.
        mAvailableActions = PlaybackState.ACTION_PAUSE | PlaybackState.ACTION_PLAY
            | PlaybackState.ACTION_SKIP_TO_NEXT | PlaybackState.ACTION_SKIP_TO_PREVIOUS;
    }

    AvrcpPlayer(int id, String name, int transportFlags, int playStatus, int playerType) {
    AvrcpPlayer(int id, String name, byte[] playerFeatures, int playStatus, int playerType) {
        mId = id;
        mName = name;
        mPlayStatus = playStatus;
        mPlayerType = playerType;
        mPlayerFeatures = Arrays.copyOf(playerFeatures, playerFeatures.length);
        updateAvailableActions();
    }

    public int getId() {
@@ -65,6 +84,16 @@ class AvrcpPlayer {
        mPlayStatus = playStatus;
    }

    public int getPlayStatus() {
        return mPlayStatus;
    }

    public boolean supportsFeature(int featureId) {
        int byteNumber = featureId / 8;
        byte bitMask = (byte) (1 << (featureId % 8));
        return (mPlayerFeatures[byteNumber] & bitMask) == bitMask;
    }

    public PlaybackState getPlaybackState() {
        if (DBG) {
            Log.d(TAG, "getPlayBackState state " + mPlayStatus + " time " + mPlayTime);
@@ -87,7 +116,8 @@ class AvrcpPlayer {
                speed = -3;
                break;
        }
        return new PlaybackState.Builder().setState(mPlayStatus, position, speed).build();
        return new PlaybackState.Builder().setState(mPlayStatus, position, speed)
            .setActions(mAvailableActions).build();
    }

    public synchronized void updateCurrentTrack(TrackInfo update) {
@@ -97,4 +127,29 @@ class AvrcpPlayer {
    public synchronized TrackInfo getCurrentTrack() {
        return mCurrentTrack;
    }

    private void updateAvailableActions() {
        if (supportsFeature(FEATURE_PLAY)) {
            mAvailableActions = mAvailableActions | PlaybackState.ACTION_PLAY;
        }
        if (supportsFeature(FEATURE_STOP)) {
            mAvailableActions = mAvailableActions | PlaybackState.ACTION_STOP;
        }
        if (supportsFeature(FEATURE_PAUSE)) {
            mAvailableActions = mAvailableActions | PlaybackState.ACTION_PAUSE;
        }
        if (supportsFeature(FEATURE_REWIND)) {
            mAvailableActions = mAvailableActions | PlaybackState.ACTION_REWIND;
        }
        if (supportsFeature(FEATURE_FAST_FORWARD)) {
            mAvailableActions = mAvailableActions | PlaybackState.ACTION_FAST_FORWARD;
        }
        if (supportsFeature(FEATURE_FORWARD)) {
            mAvailableActions = mAvailableActions | PlaybackState.ACTION_SKIP_TO_NEXT;
        }
        if (supportsFeature(FEATURE_PREVIOUS)) {
            mAvailableActions = mAvailableActions | PlaybackState.ACTION_SKIP_TO_PREVIOUS;
        }
        if (DBG) Log.d(TAG, "Supported Actions = " + mAvailableActions);
    }
}
Loading