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

Commit 41b339ef authored by Marie Janssen's avatar Marie Janssen
Browse files

AVRCP: Passthrough through MediaSessionService

Send passthrough keys through MediaSessionService instead of trying to
interpret them ourselves, and log who they get dispatched to.

Remove the hack around down fast-forward / rewind.

This should result in a lot less confusion about which app is addressed
when the user is sending a command (such as at car connection time).

Test: play / skip, switch app on phone, reboot, start from carkit, dumpsys logs
Bug: 33828042
Bug: 37476911

Change-Id: I8c8c40cb3792254a3720f64707e67fdcc940edaa
(cherry picked from commit 44a4da788f878d1946301dbf297dd7b938dfd730)
parent 60bd18a4
Loading
Loading
Loading
Loading
+3 −49
Original line number Diff line number Diff line
@@ -43,13 +43,9 @@ public class AddressedMediaPlayer {
    private AvrcpMediaRspInterface mMediaInterface;
    private List<MediaSession.QueueItem> mNowPlayingList;

    /* Now playing UID */
    private static final byte[] NOW_PLAYING_UID = {(byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
                                                  (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00};

    public AddressedMediaPlayer(AvrcpMediaRspInterface _mediaInterface) {
    public AddressedMediaPlayer(AvrcpMediaRspInterface mediaInterface) {
        mNowPlayingList = null;
        mMediaInterface = _mediaInterface;
        mMediaInterface = mediaInterface;
    }

    void cleanup() {
@@ -82,7 +78,7 @@ public class AddressedMediaPlayer {

        /* checking if item attributes has been asked for now playing item or
         * some other item with specific media id */
        if (Arrays.equals(itemAttr.mUid, NOW_PLAYING_UID)) {
        if (Arrays.equals(itemAttr.mUid, AvrcpConstants.TRACK_IS_SELECTED)) {
            if (DEBUG) Log.d(TAG, "getItemAttr: Remote requests for now playing contents:");

            if (mediaController == null) {
@@ -514,47 +510,6 @@ public class AddressedMediaPlayer {
        }
    }

    void handlePassthroughCmd(int id, int keyState, byte[] bdAddr,
            MediaController mediaController) {

        if (mediaController != null) {
            MediaController.TransportControls mediaControllerCntrl =
                mediaController.getTransportControls();
            if (DEBUG) Log.v(TAG, "handlePassthroughCmd - id:" + id + " keyState:" + keyState);
            if (keyState == AvrcpConstants.KEY_STATE_PRESS) {
                switch (id) {
                    case BluetoothAvrcp.PASSTHROUGH_ID_REWIND:
                        mediaControllerCntrl.rewind();
                        break;
                    case BluetoothAvrcp.PASSTHROUGH_ID_FAST_FOR:
                        mediaControllerCntrl.fastForward();
                        break;
                    case BluetoothAvrcp.PASSTHROUGH_ID_PLAY:
                        mediaControllerCntrl.play();
                        break;
                    case BluetoothAvrcp.PASSTHROUGH_ID_PAUSE:
                        mediaControllerCntrl.pause();
                        break;
                    case BluetoothAvrcp.PASSTHROUGH_ID_STOP:
                        mediaControllerCntrl.stop();
                        break;
                    case BluetoothAvrcp.PASSTHROUGH_ID_FORWARD:
                        mediaControllerCntrl.skipToNext();
                        break;
                    case BluetoothAvrcp.PASSTHROUGH_ID_BACKWARD:
                        mediaControllerCntrl.skipToPrevious();
                        break;
                    default:
                        Log.w(TAG, "unknown id:" + id + " keyState:" + keyState);
                }
            } else {
                Log.i(TAG, "ignoring the release event for id:" + id + " keyState:" + keyState);
            }
        } else {
            Log.e(TAG, "Unable to handlePassthroughCmd, mediaController is null!");
        }
    }

    private void printByteArray(String arrName, byte[] array) {
        StringBuilder byteArray = new StringBuilder(arrName + ": 0x");

@@ -563,5 +518,4 @@ public class AddressedMediaPlayer {
        }
        Log.d(TAG, byteArray + "");
    }

}
+366 −252

File changed.

Preview size limit exceeded, changes collapsed.

+64 −0
Original line number Diff line number Diff line
@@ -20,6 +20,8 @@ import android.media.session.MediaSession;

import java.util.List;
import java.util.Arrays;
import java.util.ArrayDeque;
import java.util.Collection;

/*************************************************************************************************
 * Helper classes used for callback/response of browsing commands:-
@@ -341,3 +343,65 @@ class FolderItemsData {
        mAttrValues = null; /* array of attr values */
    }
}

/** A queue that evicts the first element when you add an element to the end when it reaches a
 * maximum size.
 * This is useful for keeping a FIFO queue of items where the items drop off the front, i.e. a log
 * with a maximum size.
 */
class EvictingQueue<E> extends ArrayDeque<E> {
    private int mMaxSize;

    public EvictingQueue(int maxSize) {
        super();
        mMaxSize = maxSize;
    }

    public EvictingQueue(int maxSize, int initialElements) {
        super(initialElements);
        mMaxSize = maxSize;
    }

    public EvictingQueue(int maxSize, Collection<? extends E> c) {
        super(c);
        mMaxSize = maxSize;
    }

    @Override
    public boolean add(E e) {
        if (super.size() == mMaxSize) {
            super.remove();
        }
        return super.add(e);
    }

    @Override
    public void addFirst(E e) {
        if (super.size() == mMaxSize) return;
        super.addFirst(e);
    }

    @Override
    public void addLast(E e) {
        add(e);
    }

    @Override
    public boolean offer(E e) {
        return offerLast(e);
    }

    @Override
    public boolean offerFirst(E e) {
        if (super.size() == mMaxSize) return false;
        return super.offerFirst(e);
    }

    @Override
    public boolean offerLast(E e) {
        if (super.size() == mMaxSize) {
            super.remove();
        }
        return super.offerLast(e);
    }
}
+1 −1
Original line number Diff line number Diff line
@@ -41,7 +41,7 @@ public interface AvrcpMediaRspInterface {
    public void getTotalNumOfItemsRsp(byte[] address, int rspStatus, int uidCounter,
        int numItems);

    public void addrPlayerChangedRsp(byte[] address, int type, int playerId, int uidCounter);
    public void addrPlayerChangedRsp(int type, int playerId, int uidCounter);

    public void avalPlayerChangedRsp(byte[] address, int type);

+0 −93
Original line number Diff line number Diff line
package com.android.bluetooth.avrcp;

import android.bluetooth.BluetoothAvrcp;
import android.media.session.MediaSession;
import android.media.session.MediaSession.QueueItem;
import android.media.MediaDescription;
import android.media.MediaMetadata;
import android.os.Bundle;
import android.test.AndroidTestCase;
import android.util.Log;

import java.nio.ByteBuffer;
import java.util.List;
import java.util.Arrays;
import java.util.ArrayList;

import static org.mockito.Mockito.*;

public class AddressedMediaPlayerTest extends AndroidTestCase {

    public void testHandlePassthroughCmd() {
        MediaController mockController = mock(com.android.bluetooth.avrcp.MediaController.class);
        MediaController.TransportControls mockTransport = mock(MediaController.TransportControls.class);
        AvrcpMediaRspInterface mockRspInterface = mock(AvrcpMediaRspInterface.class);

        when(mockController.getTransportControls()).thenReturn(mockTransport);
        AddressedMediaPlayer myMediaPlayer = new AddressedMediaPlayer(mockRspInterface);


        // Test rewind
        myMediaPlayer.handlePassthroughCmd(BluetoothAvrcp.PASSTHROUGH_ID_REWIND,
                                           AvrcpConstants.KEY_STATE_PRESS,
                                           null,
                                           mockController);
        verify(mockTransport).rewind();

        // Test fast forward
        myMediaPlayer.handlePassthroughCmd(BluetoothAvrcp.PASSTHROUGH_ID_FAST_FOR,
                                           AvrcpConstants.KEY_STATE_PRESS,
                                           null,
                                           mockController);
        verify(mockTransport).fastForward();

        // Test play
        myMediaPlayer.handlePassthroughCmd(BluetoothAvrcp.PASSTHROUGH_ID_PLAY,
                                           AvrcpConstants.KEY_STATE_PRESS,
                                           null,
                                           mockController);
        verify(mockTransport).play();

        // Test pause
        myMediaPlayer.handlePassthroughCmd(BluetoothAvrcp.PASSTHROUGH_ID_PAUSE,
                                           AvrcpConstants.KEY_STATE_PRESS,
                                           null,
                                           mockController);
        verify(mockTransport).pause();

        // Test stop
        myMediaPlayer.handlePassthroughCmd(BluetoothAvrcp.PASSTHROUGH_ID_STOP,
                                           AvrcpConstants.KEY_STATE_PRESS,
                                           null,
                                           mockController);
        verify(mockTransport).stop();

        // Test skip to next
        myMediaPlayer.handlePassthroughCmd(BluetoothAvrcp.PASSTHROUGH_ID_FORWARD,
                                           AvrcpConstants.KEY_STATE_PRESS,
                                           null,
                                           mockController);
        verify(mockTransport).skipToNext();

        // Test skip backwards
        myMediaPlayer.handlePassthroughCmd(BluetoothAvrcp.PASSTHROUGH_ID_BACKWARD,
                                           AvrcpConstants.KEY_STATE_PRESS,
                                           null,
                                           mockController);
        verify(mockTransport).skipToPrevious();

        // Test invalid key
        myMediaPlayer.handlePassthroughCmd(0xFF,
                                           AvrcpConstants.KEY_STATE_PRESS,
                                           null,
                                           mockController);
        verifyNoMoreInteractions(mockTransport);

        // Test key release
        myMediaPlayer.handlePassthroughCmd(BluetoothAvrcp.PASSTHROUGH_ID_PLAY,
                                           AvrcpConstants.KEY_STATE_RELEASE,
                                           null,
                                           mockController);
        verifyNoMoreInteractions(mockTransport);
    }
}