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

Commit 5184257f authored by Android Build Coastguard Worker's avatar Android Build Coastguard Worker
Browse files

Snap for 12304452 from 9520cdc1 to 24Q4-release

Change-Id: If98d02ed457bdb2e04d607ed15929713570484af
parents 527e0784 9520cdc1
Loading
Loading
Loading
Loading
+26 −1
Original line number Diff line number Diff line
@@ -41,6 +41,7 @@ import com.android.bluetooth.a2dpsink.A2dpSinkService;
import com.android.bluetooth.btservice.AdapterService;
import com.android.bluetooth.btservice.MetricsLogger;
import com.android.bluetooth.btservice.ProfileService;
import com.android.bluetooth.flags.Flags;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.State;
import com.android.internal.util.StateMachine;
@@ -262,6 +263,7 @@ class AvrcpControllerStateMachine extends StateMachine {
                        + (mCoverArtManager.getState(mDevice) == BluetoothProfile.STATE_CONNECTED));

        ProfileService.println(sb, "Addressed Player ID: " + mAddressedPlayerId);
        ProfileService.println(sb, "Browsed Player ID: " + mBrowseTree.getCurrentBrowsedPlayer());
        ProfileService.println(sb, "Available Players (" + mAvailablePlayerList.size() + "): ");
        for (int i = 0; i < mAvailablePlayerList.size(); i++) {
            AvrcpPlayer player = mAvailablePlayerList.valueAt(i);
@@ -1119,11 +1121,34 @@ class AvrcpControllerStateMachine extends StateMachine {
                fetchContents(mNextStep);
            } else if (mNextStep.isPlayer()) {
                debug("GetFolderList: NAVIGATING Player " + mNextStep.toString());
                BrowseTree.BrowseNode currentBrowsedPlayer = mBrowseTree.getCurrentBrowsedPlayer();
                if (Flags.uncachePlayerWhenBrowsedPlayerChanges()) {
                    if (currentBrowsedPlayer != null) {
                        debug(
                                "GetFolderList: Uncache current browsed player, player="
                                        + currentBrowsedPlayer);
                        mBrowseTree.getCurrentBrowsedPlayer().setCached(false);
                    } else {
                        debug(
                                "GetFolderList: Browsed player unset, no need to uncache the"
                                        + " previous player");
                    }
                } else {
                    debug(
                            "GetFolderList: Feature not available: uncache current browsed player"
                                    + " on switch");
                }

                if (mNextStep.isBrowsable()) {
                    debug(
                            "GetFolderList: Set browsed player, old="
                                    + currentBrowsedPlayer
                                    + ", new="
                                    + mNextStep);
                    mNativeInterface.setBrowsedPlayer(
                            mDeviceAddress, (int) mNextStep.getBluetoothID());
                } else {
                    debug("GetFolderList: Player doesn't support browsing");
                    debug("GetFolderList: Target player doesn't support browsing");
                    mNextStep.setCached(true);
                    transitionTo(mConnected);
                }
+3 −1
Original line number Diff line number Diff line
@@ -170,6 +170,8 @@ public class BluetoothMediaBrowserService extends MediaBrowserServiceCompat {
        super.onDestroy();
        unregisterReceiver(mReceiver);
        mReceiver = null;
        mSession.release();
        mSession = null;
        setInstance(null);
    }

@@ -559,7 +561,7 @@ public class BluetoothMediaBrowserService extends MediaBrowserServiceCompat {
                sb.append(", album=")
                        .append(metadata.getString(MediaMetadataCompat.METADATA_KEY_ALBUM));
                sb.append(", duration=")
                        .append(metadata.getString(MediaMetadataCompat.METADATA_KEY_DURATION));
                        .append(metadata.getLong(MediaMetadataCompat.METADATA_KEY_DURATION));
                sb.append(", track_number=")
                        .append(metadata.getLong(MediaMetadataCompat.METADATA_KEY_TRACK_NUMBER));
                sb.append(", total_tracks=")
+14 −8
Original line number Diff line number Diff line
@@ -182,12 +182,13 @@ public class BrowseTree {
        }

        BrowseNode(BluetoothDevice device) {
            mIsPlayer = true;
            String playerKey = PLAYER_PREFIX + device.getAddress().toString();

            AvrcpItem.Builder aid = new AvrcpItem.Builder();
            aid.setDevice(device);
            aid.setUuid(playerKey);
            if (Flags.randomizeDeviceLevelMediaIds()) {
                aid.setUuid(ROOT + device.getAddress().toString() + UUID.randomUUID().toString());
            } else {
                aid.setUuid(PLAYER_PREFIX + device.getAddress().toString());
            }
            aid.setDisplayableName(Utils.getName(device));
            aid.setTitle(Utils.getName(device));
            aid.setBrowsable(true);
@@ -304,10 +305,13 @@ public class BrowseTree {
        }

        synchronized void setCached(boolean cached) {
            Log.d(TAG, "Set Cache" + cached + "Node" + toString());
            Log.d(TAG, "Set cached=" + cached + ", node=" + toString());
            mCached = cached;
            if (!cached) {
                for (BrowseNode child : mChildren) {
                    if (Flags.uncachePlayerWhenBrowsedPlayerChanges()) {
                        child.setCached(false);
                    }
                    mBrowseMap.remove(child.getID());
                    indicateCoverArtUnused(child.getID(), child.getCoverArtUuid());
                }
@@ -373,11 +377,13 @@ public class BrowseTree {

        @Override
        public synchronized String toString() {
            return "[Id: "
            return "[id="
                    + getID()
                    + " Name: "
                    + ", name="
                    + getMediaItem().getDescription().getTitle()
                    + " Size: "
                    + ", cached="
                    + isCached()
                    + ", size="
                    + mChildren.size()
                    + "]";
        }
+3 −155
Original line number Diff line number Diff line
@@ -22,25 +22,18 @@ import android.util.Pair;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.MissingResourceException;
import java.util.Set;

/** Helper class to parse the Broadcast Announcement BASE data */
class BaseData {
    private static final String TAG = "Bassclient-BaseData";
    private static final byte UNKNOWN_CODEC = (byte) 0xFE;
    private static final int METADATA_LEVEL1 = 1;
    private static final int METADATA_LEVEL2 = 2;
    private static final int METADATA_LEVEL3 = 3;
    private static final int METADATA_PRESENTATIONDELAY_LENGTH = 3;
    private static final int METADATA_CODEC_LENGTH = 5;
    private static final int METADATA_UNKNOWN_CODEC_LENGTH = 1;
    private static final int CODEC_CONFIGURATION_SAMPLE_RATE_TYPE = 0x01;
    private static final int CODEC_CONFIGURATION_FRAME_DURATION_TYPE = 0x02;
    private static final int CODEC_CONFIGURATION_CHANNEL_ALLOCATION_TYPE = 0x03;
@@ -71,19 +64,9 @@ class BaseData {
        public int metaDataLength;
        public byte[] metaData;
        public byte numSubGroups;
        public byte[] bisIndices;
        public byte index;
        public int subGroupId;
        public int level;
        public LinkedHashSet<String> keyCodecCfgDiff;
        public LinkedHashSet<String> keyMetadataDiff;
        public String diffText;
        public String description;
        public byte[] consolidatedCodecId;
        public Set<String> consolidatedMetadata;
        public Set<String> consolidatedCodecInfo;
        public HashMap<Integer, String> consolidatedUniqueCodecInfo;
        public HashMap<Integer, String> consolidatedUniqueMetadata;

        BaseInformation() {
            presentationDelay = new byte[3];
@@ -93,25 +76,11 @@ class BaseData {
            metaDataLength = 0;
            metaData = new byte[0];
            numSubGroups = 0;
            bisIndices = null;
            index = (byte) 0xFF;
            level = 0;
            keyCodecCfgDiff = new LinkedHashSet<String>();
            keyMetadataDiff = new LinkedHashSet<String>();
            consolidatedMetadata = new LinkedHashSet<String>();
            consolidatedCodecInfo = new LinkedHashSet<String>();
            consolidatedCodecId = new byte[5];
            consolidatedUniqueMetadata = new HashMap<Integer, String>();
            consolidatedUniqueCodecInfo = new HashMap<Integer, String>();
            diffText = new String("");
            description = new String("");
            log("BaseInformation is Initialized");
        }

        boolean isCodecIdUnknown() {
            return (codecId != null && codecId[4] == (byte) UNKNOWN_CODEC);
        }

        void print() {
            log("**BEGIN: Base Information**");
            log("**Level: " + level + "***");
@@ -137,49 +106,6 @@ class BaseData {
                    log("numSubGroups: " + numSubGroups);
                }
            }
            if (level == 2) {
                log("Level2: Key Metadata differentiators");
                if (keyMetadataDiff != null) {
                    Iterator<String> itr = keyMetadataDiff.iterator();
                    for (int k = 0; itr.hasNext(); k++) {
                        log(
                                "keyMetadataDiff:["
                                        + k
                                        + "]:"
                                        + Arrays.toString(itr.next().getBytes()));
                    }
                }
                log("END: Level2: Key Metadata differentiators");
                log("Level2: Key CodecConfig differentiators");
                if (keyCodecCfgDiff != null) {
                    Iterator<String> itr = keyCodecCfgDiff.iterator();
                    for (int k = 0; itr.hasNext(); k++) {
                        log(
                                "LEVEL2: keyCodecCfgDiff:["
                                        + k
                                        + "]:"
                                        + Arrays.toString(itr.next().getBytes()));
                    }
                }
                log("END: Level2: Key CodecConfig differentiators");
                log("LEVEL2: diffText: " + diffText);
            }
            if (level == 3) {
                log("Level3: Key CodecConfig differentiators");
                if (keyCodecCfgDiff != null) {
                    Iterator<String> itr = keyCodecCfgDiff.iterator();
                    for (int k = 0; itr.hasNext(); k++) {
                        log(
                                "LEVEL3: keyCodecCfgDiff:["
                                        + k
                                        + "]:"
                                        + Arrays.toString(itr.next().getBytes()));
                    }
                }
                log("END: Level3: Key CodecConfig differentiators");
                log("index: " + index);
                log("LEVEL3: diffText: " + diffText);
            }
            log("**END: Base Information****");
        }
    }
@@ -247,21 +173,9 @@ class BaseData {
        BaseInformation node = new BaseInformation();
        node.level = METADATA_LEVEL2;
        node.subGroupId = groupIndex;
        node.numSubGroups = serviceData[offset++];
        if (serviceData[offset] == (byte) UNKNOWN_CODEC) {
            // Place It in the last byte of codecID
            System.arraycopy(
                    serviceData,
                    offset,
                    node.codecId,
                    METADATA_CODEC_LENGTH - 1,
                    METADATA_UNKNOWN_CODEC_LENGTH);
            offset += METADATA_UNKNOWN_CODEC_LENGTH;
            log("codecId is FE");
        } else {
        node.numSubGroups = serviceData[offset++]; // NumBis
        System.arraycopy(serviceData, offset, node.codecId, 0, METADATA_CODEC_LENGTH);
        offset += METADATA_CODEC_LENGTH;
        }
        node.codecConfigLength = serviceData[offset++] & 0xff;
        if (node.codecConfigLength != 0) {
            node.codecConfigInfo = new byte[node.codecConfigLength];
@@ -301,53 +215,6 @@ class BaseData {
            consolidateBaseofLevelThree(
                    levelTwo, levelThree, i, startIdx, levelTwo.get(i).numSubGroups);
        }
        // Eliminate Duplicates at Level 3
        for (int i = 0; i < levelThree.size(); i++) {
            Map<Integer, String> uniqueMds = new HashMap<Integer, String>();
            Map<Integer, String> uniqueCcis = new HashMap<Integer, String>();
            Set<String> Csfs = levelThree.get(i).consolidatedCodecInfo;
            if (Csfs.size() > 0) {
                for (String codecInfo : Csfs) {
                    byte[] ltvEntries = codecInfo.getBytes();
                    int k = 0;
                    byte length = ltvEntries[k++];
                    byte[] ltv = new byte[length + 1];
                    ltv[0] = length;
                    System.arraycopy(ltvEntries, k, ltv, 1, length);
                    int type = (int) ltv[1];
                    String s = uniqueCcis.get(type);
                    String ltvS = new String(ltv);
                    if (s == null) {
                        uniqueCcis.put(type, ltvS);
                    } else {
                        // if same type exists, replace
                        uniqueCcis.replace(type, ltvS);
                    }
                }
            }
            Set<String> Mds = levelThree.get(i).consolidatedMetadata;
            if (Mds.size() > 0) {
                for (String metadata : Mds) {
                    byte[] ltvEntries = metadata.getBytes();
                    int k = 0;
                    byte length = ltvEntries[k++];
                    byte[] ltv = new byte[length + 1];
                    ltv[0] = length;
                    System.arraycopy(ltvEntries, k, ltv, 1, length);
                    int type = (int) ltv[1];
                    String s = uniqueCcis.get(type);
                    String ltvS = new String(ltv);
                    if (s == null) {
                        uniqueMds.put(type, ltvS);
                    } else {
                        uniqueMds.replace(type, ltvS);
                    }
                }
            }
            levelThree.get(i).consolidatedUniqueMetadata = new HashMap<Integer, String>(uniqueMds);
            levelThree.get(i).consolidatedUniqueCodecInfo =
                    new HashMap<Integer, String>(uniqueCcis);
        }
    }

    static void consolidateBaseofLevelThree(
@@ -358,25 +225,6 @@ class BaseData {
            int numNodes) {
        for (int i = startIdx; i < startIdx + numNodes || i < levelThree.size(); i++) {
            levelThree.get(i).subGroupId = levelTwo.get(parentSubgroup).subGroupId;
            log("Copy Codec Id from Level2 Parent" + parentSubgroup);
            System.arraycopy(
                    levelTwo.get(parentSubgroup).consolidatedCodecId,
                    0,
                    levelThree.get(i).consolidatedCodecId,
                    0,
                    5);
            // Metadata clone from Parent
            levelThree.get(i).consolidatedMetadata =
                    new LinkedHashSet<String>(levelTwo.get(parentSubgroup).consolidatedMetadata);
            // CCI clone from Parent
            levelThree.get(i).consolidatedCodecInfo =
                    new LinkedHashSet<String>(levelTwo.get(parentSubgroup).consolidatedCodecInfo);
            // Append Level 2 Codec Config
            if (levelThree.get(i).codecConfigLength != 0) {
                log("append level 3 cci to level 3 cons:" + i);
                String s = new String(levelThree.get(i).codecConfigInfo);
                levelThree.get(i).consolidatedCodecInfo.add(s);
            }
        }
    }

+99 −0
Original line number Diff line number Diff line
@@ -2077,4 +2077,103 @@ public class AvrcpControllerStateMachineTest {
        TestUtils.waitForLooperToBeIdle(mAvrcpStateMachine.getHandler().getLooper());
        verify(mNativeInterface, times(1)).getPlayerList(eq(mTestAddress), eq(0), eq(19));
    }

    @Test
    @EnableFlags(Flags.FLAG_UNCACHE_PLAYER_WHEN_BROWSED_PLAYER_CHANGES)
    public void testBrowsingContentsOfOtherBrowsablePlayer_browsedPlayerUncached() {
        setUpConnectedState(true, true);
        sendAudioFocusUpdate(AudioManager.AUDIOFOCUS_GAIN);

        BrowseTree.BrowseNode results = mAvrcpStateMachine.mBrowseTree.mRootNode;

        // Request fetch the list of players
        BrowseTree.BrowseNode playerNodes = mAvrcpStateMachine.findNode(results.getID());
        mAvrcpStateMachine.requestContents(playerNodes);
        verify(mNativeInterface, timeout(ASYNC_CALL_TIMEOUT_MILLIS).times(1))
                .getPlayerList(eq(mTestAddress), eq(0), eq(19));

        // Provide back two player objects
        byte[] playerFeatures =
                new byte[] {0, 0, 0, 0, 0, (byte) 0xb7, 0x01, 0x0c, 0x0a, 0, 0, 0, 0, 0, 0, 0};
        AvrcpPlayer playerOne = makePlayer(mTestDevice, 1, "player 1", playerFeatures, 1);
        AvrcpPlayer playerTwo = makePlayer(mTestDevice, 2, "player 2", playerFeatures, 1);
        List<AvrcpPlayer> testPlayers = new ArrayList<>();
        testPlayers.add(playerOne);
        testPlayers.add(playerTwo);
        mAvrcpStateMachine.sendMessage(
                AvrcpControllerStateMachine.MESSAGE_PROCESS_GET_PLAYER_ITEMS, testPlayers);
        TestUtils.waitForLooperToFinishScheduledTask(mAvrcpStateMachine.getHandler().getLooper());

        // Verify that the player objects are both available and properly formatted
        playerNodes = mAvrcpStateMachine.findNode(results.getID());
        assertThat(playerNodes.isCached()).isTrue();
        assertThat(playerNodes.getChildren()).isNotNull();
        assertThat(playerNodes.getChildren().size()).isEqualTo(2);
        assertThat(playerNodes.getChildren().get(0).getMediaItem().toString())
                .isEqualTo("MediaItem{mFlags=1, mDescription=player 1, null, null}");
        assertThat(playerNodes.getChildren().get(1).getMediaItem().toString())
                .isEqualTo("MediaItem{mFlags=1, mDescription=player 2, null, null}");

        // Fetch contents of the first player object
        BrowseTree.BrowseNode playerOneNode =
                mAvrcpStateMachine.findNode(results.getChildren().get(0).getID());
        mAvrcpStateMachine.requestContents(playerOneNode);
        verify(mNativeInterface, timeout(ASYNC_CALL_TIMEOUT_MILLIS).times(1))
                .setBrowsedPlayer(eq(mTestAddress), eq(1));
        mAvrcpStateMachine.sendMessage(
                AvrcpControllerStateMachine.MESSAGE_PROCESS_SET_BROWSED_PLAYER,
                /* items= */ 5,
                /* depth= */ 0);
        verify(mNativeInterface, timeout(ASYNC_CALL_TIMEOUT_MILLIS).times(1))
                .getFolderList(eq(mTestAddress), eq(0), eq(4));

        // Return some results for Player One
        List<AvrcpItem> testFolderContents = new ArrayList<AvrcpItem>();
        for (int i = 0; i < 5; i++) {
            String title = "Song " + Integer.toString(i);
            testFolderContents.add(makeNowPlayingItem(i, title));
        }
        mAvrcpStateMachine.sendMessage(
                AvrcpControllerStateMachine.MESSAGE_PROCESS_GET_FOLDER_ITEMS, testFolderContents);
        mAvrcpStateMachine.sendMessage(
                AvrcpControllerStateMachine.MESSAGE_PROCESS_GET_FOLDER_ITEMS_OUT_OF_RANGE);
        TestUtils.waitForLooperToFinishScheduledTask(mAvrcpStateMachine.getHandler().getLooper());

        // Make sure the player/folder is cached
        playerOneNode = mAvrcpStateMachine.findNode(results.getChildren().get(0).getID());
        assertThat(playerOneNode.isCached()).isTrue();

        // Browse to the Player Two
        BrowseTree.BrowseNode playerTwoNode =
                mAvrcpStateMachine.findNode(results.getChildren().get(1).getID());
        mAvrcpStateMachine.requestContents(playerTwoNode);
        verify(mNativeInterface, timeout(ASYNC_CALL_TIMEOUT_MILLIS).times(1))
                .setBrowsedPlayer(eq(mTestAddress), eq(2));
        mAvrcpStateMachine.sendMessage(
                AvrcpControllerStateMachine.MESSAGE_PROCESS_SET_BROWSED_PLAYER,
                /* items= */ 5,
                /* depth= */ 0);
        verify(mNativeInterface, timeout(ASYNC_CALL_TIMEOUT_MILLIS).times(2))
                .getFolderList(eq(mTestAddress), eq(0), eq(4));

        // Make sure the first player is uncached
        playerOneNode = mAvrcpStateMachine.findNode(results.getChildren().get(0).getID());
        assertThat(playerOneNode.isCached()).isFalse();

        // Send items for Player Two
        testFolderContents = new ArrayList<AvrcpItem>();
        for (int i = 5; i < 10; i++) {
            String title = "Song " + Integer.toString(i);
            testFolderContents.add(makeNowPlayingItem(i, title));
        }
        mAvrcpStateMachine.sendMessage(
                AvrcpControllerStateMachine.MESSAGE_PROCESS_GET_FOLDER_ITEMS, testFolderContents);
        mAvrcpStateMachine.sendMessage(
                AvrcpControllerStateMachine.MESSAGE_PROCESS_GET_FOLDER_ITEMS_OUT_OF_RANGE);
        TestUtils.waitForLooperToFinishScheduledTask(mAvrcpStateMachine.getHandler().getLooper());

        // make sure the second player is cached now
        playerTwoNode = mAvrcpStateMachine.findNode(results.getChildren().get(1).getID());
        assertThat(playerTwoNode.isCached()).isTrue();
    }
}
Loading