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

Commit 5a365939 authored by Joseph Pirozzo's avatar Joseph Pirozzo
Browse files

AVRCP Controller update loop.

The process for getting media browsing contents from a remote device
required several intents sent back and forth between the
MediaBrowserService and the AvrcpControllerService.  This required that
any application using A2dpMediaBrowserService utilized understood the
nuances of Bluetooth media browsing.  This update simplifies the
experience into two primary capabilities listing contents of a
directory, and selecting an item to play.

Bug: 79093111
Test: Browse media players via Bluetooth
Change-Id: I99ca081f6a5ef51917b8a9a9b7dac610650d6b57
parent 43948710
Loading
Loading
Loading
Loading
+10 −22
Original line number Diff line number Diff line
@@ -33,7 +33,6 @@ import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.Parcelable;
import android.service.media.MediaBrowserService;
import android.util.Log;
import android.util.Pair;
@@ -44,7 +43,6 @@ import com.android.bluetooth.avrcpcontroller.AvrcpControllerService;
import com.android.bluetooth.avrcpcontroller.BrowseTree;

import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
@@ -220,6 +218,7 @@ public class A2dpMediaBrowserService extends MediaBrowserService {

    @Override
    public BrowserRoot onGetRoot(String clientPackageName, int clientUid, Bundle rootHints) {
        if (DBG) Log.d(TAG, "onGetRoot");
        return new BrowserRoot(BrowseTree.ROOT, null);
    }

@@ -233,17 +232,15 @@ public class A2dpMediaBrowserService extends MediaBrowserService {
        }

        if (DBG) Log.d(TAG, "onLoadChildren parentMediaId=" + parentMediaId);
        if (!mAvrcpCtrlSrvc.getChildren(mA2dpDevice, parentMediaId, 0, 0xff)) {
            result.sendResult(Collections.emptyList());
            return;
        }

        // Since we are using this thread from a binder thread we should make sure that
        // we synchronize against other such asynchronous calls.
        synchronized (this) {
        List<MediaItem> contents = mAvrcpCtrlSrvc.getContents(mA2dpDevice, parentMediaId);
        if (contents == null) {
            mParentIdToRequestMap.put(parentMediaId, result);
        }
            result.detach();
        } else {
            result.sendResult(contents);
        }

        return;
    }

    @Override
@@ -555,16 +552,8 @@ public class A2dpMediaBrowserService extends MediaBrowserService {

    private void msgFolderList(Intent intent) {
        // Parse the folder list for children list and id.
        List<Parcelable> extraParcelableList =
                (ArrayList<Parcelable>) intent.getParcelableArrayListExtra(
                        AvrcpControllerService.EXTRA_FOLDER_LIST);
        List<MediaItem> folderList = new ArrayList<MediaItem>();
        for (Parcelable p : extraParcelableList) {
            folderList.add((MediaItem) p);
        }

        String id = intent.getStringExtra(AvrcpControllerService.EXTRA_FOLDER_ID);
        if (VDBG) Log.d(TAG, "Parent: " + id + " Folder list: " + folderList);
        if (VDBG) Log.d(TAG, "Parent: " + id);
        synchronized (this) {
            // If we have a result object then we should send the result back
            // to client since it is blocking otherwise we may have gotten more items
@@ -572,10 +561,9 @@ public class A2dpMediaBrowserService extends MediaBrowserService {
            Result<List<MediaItem>> results = mParentIdToRequestMap.remove(id);
            if (results == null) {
                Log.w(TAG, "Request no longer exists, notifying that children changed.");
                if (!id.equals("__ROOT__")) {
                    notifyChildrenChanged(id);
                }
            } else {
                List<MediaItem> folderList = mAvrcpCtrlSrvc.getContents(mA2dpDevice, id);
                results.sendResult(folderList);
            }
        }
+7 −165
Original line number Diff line number Diff line
@@ -172,8 +172,8 @@ public class AvrcpControllerService extends ProfileService {
    /* Folder navigation directions
     * This is borrowed from AVRCP 1.6 spec and must be kept with same values
     */
    public static final int FOLDER_NAVIGATION_DIRECTION_UP = 0x00;
    public static final int FOLDER_NAVIGATION_DIRECTION_DOWN = 0x01;
    public static final byte FOLDER_NAVIGATION_DIRECTION_UP = 0x00;
    public static final byte FOLDER_NAVIGATION_DIRECTION_DOWN = 0x01;

    /* Folder/Media Item scopes.
     * Keep in sync with AVRCP 1.6 sec. 6.10.1
@@ -398,77 +398,12 @@ public class AvrcpControllerService extends ProfileService {
    }

    /**
     * Fetches the list of children for the parentID node.
     *
     * This function manages the overall tree for browsing structure.
     *
     * Arguments:
     * device - Device to browse content for.
     * parentMediaId - ID of the parent that we need to browse content for. Since most
     * of the players are database unware, fetching a root invalidates all the children.
     * start - number of item to start scanning from
     * items - number of items to fetch
     * Retreive the contents of the directory from the associated bluetooth device.
     */
    public synchronized boolean getChildren(BluetoothDevice device, String parentMediaId, int start,
            int items) {
        if (DBG) {
            Log.d(TAG, "getChildren device = " + device + " parent " + parentMediaId);
        }

        if (device == null) {
            Log.e(TAG, "getChildren device is null");
            return false;
        }

        if (!device.equals(mConnectedDevice)) {
            Log.e(TAG, "getChildren device " + device + " does not match " + mConnectedDevice);
            return false;
        }

        if (!mBrowseConnected) {
            Log.e(TAG, "getChildren browse not yet connected");
            return false;
        }

        if (!mAvrcpCtSm.isConnected()) {
            return false;
        }
        mAvrcpCtSm.getChildren(parentMediaId, start, items);
        return true;
    }

    public synchronized boolean getNowPlayingList(BluetoothDevice device, String id, int start,
            int items) {
        if (DBG) {
            Log.d(TAG, "getNowPlayingList device = " + device + " start = " + start + "items = "
                    + items);
        }

        if (device == null) {
            Log.e(TAG, "getNowPlayingList device is null");
            return false;
        }

        if (!device.equals(mConnectedDevice)) {
            Log.e(TAG,
                    "getNowPlayingList device " + device + " does not match " + mConnectedDevice);
            return false;
    public synchronized List<MediaItem> getContents(BluetoothDevice device, String parentMediaId) {
        return mAvrcpCtSm.getContents(parentMediaId);
    }

        if (!mBrowseConnected) {
            Log.e(TAG, "getNowPlayingList browse not yet connected");
            return false;
        }

        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");

        Message msg =
                mAvrcpCtSm.obtainMessage(AvrcpControllerStateMachine.MESSAGE_GET_NOW_PLAYING_LIST,
                        start, items, id);
        mAvrcpCtSm.sendMessage(msg);
        return true;
    }

/*
    public synchronized boolean getFolderList(BluetoothDevice device, String id, int start,
            int items) {
        if (DBG) {
@@ -499,100 +434,7 @@ public class AvrcpControllerService extends ProfileService {
        mAvrcpCtSm.sendMessage(msg);
        return true;
    }

    public synchronized boolean getPlayerList(BluetoothDevice device, int start, int items) {
        if (DBG) {
            Log.d(TAG,
                    "getPlayerList device = " + device + " start = " + start + "items = " + items);
        }

        if (device == null) {
            Log.e(TAG, "getPlayerList device is null");
            return false;
        }

        if (!device.equals(mConnectedDevice)) {
            Log.e(TAG, "getPlayerList device " + device + " does not match " + mConnectedDevice);
            return false;
        }

        if (!mBrowseConnected) {
            Log.e(TAG, "getPlayerList browse not yet connected");
            return false;
        }

        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");

        Message msg =
                mAvrcpCtSm.obtainMessage(AvrcpControllerStateMachine.MESSAGE_GET_PLAYER_LIST, start,
                        items);
        mAvrcpCtSm.sendMessage(msg);
        return true;
    }

    public synchronized boolean changeFolderPath(BluetoothDevice device, int direction, String uid,
            String fid) {
        if (DBG) {
            Log.d(TAG, "changeFolderPath device = " + device + " direction " + direction + " uid "
                    + uid);
        }

        if (device == null) {
            Log.e(TAG, "changeFolderPath device is null");
            return false;
        }

        if (!device.equals(mConnectedDevice)) {
            Log.e(TAG, "changeFolderPath device " + device + " does not match " + mConnectedDevice);
            return false;
        }

        if (!mBrowseConnected) {
            Log.e(TAG, "changeFolderPath browse not yet connected");
            return false;
        }

        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");

        Bundle b = new Bundle();
        b.putString(EXTRA_FOLDER_ID, fid);
        b.putString(EXTRA_FOLDER_BT_ID, uid);
        Message msg =
                mAvrcpCtSm.obtainMessage(AvrcpControllerStateMachine.MESSAGE_CHANGE_FOLDER_PATH,
                        direction, 0, b);
        mAvrcpCtSm.sendMessage(msg);
        return true;
    }

    public synchronized boolean setBrowsedPlayer(BluetoothDevice device, int id, String fid) {
        if (DBG) {
            Log.d(TAG, "setBrowsedPlayer device = " + device + " id" + id + " fid " + fid);
        }

        if (device == null) {
            Log.e(TAG, "setBrowsedPlayer device is null");
            return false;
        }

        if (!device.equals(mConnectedDevice)) {
            Log.e(TAG, "changeFolderPath device " + device + " does not match " + mConnectedDevice);
            return false;
        }

        if (!mBrowseConnected) {
            Log.e(TAG, "setBrowsedPlayer browse not yet connected");
            return false;
        }

        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");

        Message msg =
                mAvrcpCtSm.obtainMessage(AvrcpControllerStateMachine.MESSAGE_SET_BROWSED_PLAYER, id,
                        0, fid);
        mAvrcpCtSm.sendMessage(msg);
        return true;
    }

*/
    public synchronized void fetchAttrAndPlayItem(BluetoothDevice device, String uid) {
        if (DBG) {
            Log.d(TAG, "fetchAttrAndPlayItem device = " + device + " uid " + uid);