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

Commit 66730e3c authored by Sal Savage's avatar Sal Savage Committed by Myles Watson
Browse files

Request current track metadata when BIP connects

AVRCP Targets are not supposed to give image handles over with metadata
until an AVRCP BIP client connects from a particular controller. Because
this connection can happen any time and there's nothing forcing a target
to send us a track changed notification to inform us of the new handle,
the best thing we can do to work with all devices is to request it when
we connect on BIP. Otherwise, we risk a race condition between the BIP
connection and any amount of track changed notifications that might
happen organically.

This change, paired with one in /system/bt/, adds a method to the native
interface to allow us to request for current track metadata whenever we
want. We then call it when we learn of a BIP client connection.

Bug: 152655644
Test: Build, flash, atest
Change-Id: Ife75cd08a3affe1cc14a4254d1896c4299114f9f
Merged-In: Ife75cd08a3affe1cc14a4254d1896c4299114f9f
parent 456141d4
Loading
Loading
Loading
Loading
+22 −0
Original line number Diff line number Diff line
@@ -1087,6 +1087,27 @@ static void sendRegisterAbsVolRspNative(JNIEnv* env, jobject object,
  env->ReleaseByteArrayElements(address, addr, 0);
}

static void getCurrentMetadataNative(JNIEnv* env, jobject object,
                                     jbyteArray address) {
  if (!sBluetoothAvrcpInterface) return;

  jbyte* addr = env->GetByteArrayElements(address, NULL);
  if (!addr) {
    jniThrowIOException(env, EINVAL);
    return;
  }
  ALOGV("%s: sBluetoothAvrcpInterface: %p", __func__, sBluetoothAvrcpInterface);
  RawAddress rawAddress;
  rawAddress.FromOctets((uint8_t*)addr);

  bt_status_t status =
      sBluetoothAvrcpInterface->get_current_metadata_cmd(rawAddress);
  if (status != BT_STATUS_SUCCESS) {
    ALOGE("Failed sending getCurrentMetadataNative command, status: %d", status);
  }
  env->ReleaseByteArrayElements(address, addr, 0);
}

static void getPlaybackStateNative(JNIEnv* env, jobject object,
                                   jbyteArray address) {
  if (!sBluetoothAvrcpInterface) return;
@@ -1276,6 +1297,7 @@ static JNINativeMethod sMethods[] = {
    {"sendAbsVolRspNative", "([BII)V", (void*)sendAbsVolRspNative},
    {"sendRegisterAbsVolRspNative", "([BBII)V",
     (void*)sendRegisterAbsVolRspNative},
    {"getCurrentMetadataNative", "([B)V", (void*)getCurrentMetadataNative},
    {"getPlaybackStateNative", "([B)V", (void*)getPlaybackStateNative},
    {"getNowPlayingListNative", "([BII)V", (void*)getNowPlayingListNative},
    {"getFolderListNative", "([BII)V", (void*)getFolderListNative},
+9 −0
Original line number Diff line number Diff line
@@ -829,6 +829,15 @@ public class AvrcpControllerService extends ProfileService {
    public native void sendRegisterAbsVolRspNative(byte[] address, byte rspType, int absVol,
            int label);

    /**
     * Fetch the current track's metadata
     *
     * This method is specifically meant to allow us to fetch image handles that may not have been
     * sent to us yet, prior to having a BIP client connection. See the AVRCP 1.6+ specification,
     * section 4.1.7, for more details.
     */
    public native void getCurrentMetadataNative(byte[] address);

    /**
     * Fetch the playback state
     */
+11 −6
Original line number Diff line number Diff line
@@ -18,11 +18,12 @@ package com.android.bluetooth.avrcpcontroller;

import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothProfile;
import android.content.Context;
import android.net.Uri;
import android.os.SystemProperties;
import android.util.Log;

import com.android.bluetooth.Utils;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@@ -45,7 +46,7 @@ public class AvrcpCoverArtManager {
    public static final String SCHEME_NATIVE = "native";
    public static final String SCHEME_THUMBNAIL = "thumbnail";

    private final Context mContext;
    private final AvrcpControllerService mService;
    protected final Map<BluetoothDevice, AvrcpBipClient> mClients = new ConcurrentHashMap<>(1);
    private final AvrcpCoverArtStorage mCoverArtStorage;
    private final Callback mCallback;
@@ -81,9 +82,9 @@ public class AvrcpCoverArtManager {
        void onImageDownloadComplete(BluetoothDevice device, DownloadEvent event);
    }

    public AvrcpCoverArtManager(Context context, Callback callback) {
        mContext = context;
        mCoverArtStorage = new AvrcpCoverArtStorage(mContext);
    public AvrcpCoverArtManager(AvrcpControllerService service, Callback callback) {
        mService = service;
        mCoverArtStorage = new AvrcpCoverArtStorage(mService);
        mCallback = callback;
        mDownloadScheme =
                SystemProperties.get(AVRCP_CONTROLLER_COVER_ART_SCHEME, SCHEME_THUMBNAIL);
@@ -260,7 +261,11 @@ public class AvrcpCoverArtManager {
        @Override
        public void onConnectionStateChanged(int oldState, int newState) {
            debug(mDevice.getAddress() + ": " + oldState + " -> " + newState);
            if (newState == BluetoothProfile.STATE_DISCONNECTED) {
            if (newState == BluetoothProfile.STATE_CONNECTED) {
                // Once we're connected fetch the current metadata again in case the target has an
                // image handle they can now give us
                mService.getCurrentMetadataNative(Utils.getByteAddress(mDevice));
            } else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
                disconnect(mDevice);
            }
        }