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

Commit 978c8e64 authored by Sal Savage's avatar Sal Savage
Browse files

Don't notify of changes to non-VFS state for inactive devices

There were three left over places where we could notifyChanged for
inactive devices:
(1) On Connected, we requestFocus() but ignored the status and updated
state anyway
(2) When browsing anything from the now playing scope we would always
notifyChanged for the node
(3) Cover art downloads for items in the now playing list would result
in notifyChanged calls even when inactive

Case (1) has been addressed by centralizing the state changes in
setActive() in a way thats safer and providers better testability in the
future. Case (2) was solved by checking the scope of a node before
updating anyone. Case (3) moved the notifications from the BrowseTree to
the state machine and piggy-backed off case (2)'s solution.

Tag: #compatibility
Bug: 154959439
Test: atest BluetoothInstrumentationTests, build/flash and test with
various target devices.
Merged-In: Id6967daaa057c4269186df3765ae760a7bb27ace
Change-Id: Id6967daaa057c4269186df3765ae760a7bb27ace

Change-Id: I48797d939f45e5a833a99da6fe4e4826ebe3c0a9
parent c1d0190d
Loading
Loading
Loading
Loading
+44 −28
Original line number Diff line number Diff line
@@ -42,6 +42,7 @@ import com.android.internal.annotations.VisibleForTesting;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

/**
 * Provides Bluetooth AVRCP Controller State Machine responsible for all remote control connections
@@ -231,25 +232,39 @@ class AvrcpControllerStateMachine extends StateMachine {
        if (sActiveDevice == null
                || BluetoothMediaBrowserService.getPlaybackState()
                != PlaybackStateCompat.STATE_PLAYING) {
            return setActive();
            return setActive(true);
        }
        return false;
    }

    /*
     * setActive
     *
     * Set this state machine as the active device and update media browse service
    /**
     * Attempt to set the active status for this device
     */
    private boolean setActive() {
        if (DBG) Log.d(TAG, "setActive" + mDevice);
        if (A2dpSinkService.getA2dpSinkService().setActiveDeviceNative(mDeviceAddress)) {
    boolean setActive(boolean becomeActive) {
        logD("setActive(" + becomeActive + ")");
        if (becomeActive) {
            if (isActive()) {
                return true;
            }

            A2dpSinkService a2dpSinkService = A2dpSinkService.getA2dpSinkService();
            if (a2dpSinkService == null) {
                return false;
            }

            if (a2dpSinkService.setActiveDeviceNative(mDeviceAddress)) {
                sActiveDevice = mDevice;
                BluetoothMediaBrowserService.addressedPlayerChanged(mSessionCallbacks);
                BluetoothMediaBrowserService.notifyChanged(mAddressedPlayer.getPlaybackState());
                BluetoothMediaBrowserService.notifyChanged(mBrowseTree.mNowPlayingNode);
            }
            return mDevice == sActiveDevice;
        } else if (isActive()) {
            sActiveDevice = null;
            BluetoothMediaBrowserService.trackChanged(null);
            BluetoothMediaBrowserService.addressedPlayerChanged(null);
        }
        return true;
    }

    @Override
@@ -303,8 +318,15 @@ class AvrcpControllerStateMachine extends StateMachine {
    }

    private void notifyChanged(BrowseTree.BrowseNode node) {
        // We should only notify now playing content updates if we're the active device. VFS
        // updates are fine at any time
        int scope = node.getScope();
        if (scope != AvrcpControllerService.BROWSE_SCOPE_NOW_PLAYING
                || (scope == AvrcpControllerService.BROWSE_SCOPE_NOW_PLAYING
                && isActive())) {
            BluetoothMediaBrowserService.notifyChanged(node);
        }
    }

    private void notifyChanged(PlaybackStateCompat state) {
        if (isActive()) {
@@ -372,8 +394,6 @@ class AvrcpControllerStateMachine extends StateMachine {
        public void enter() {
            if (mMostRecentState == BluetoothProfile.STATE_CONNECTING) {
                requestActive();
                BluetoothMediaBrowserService.addressedPlayerChanged(mSessionCallbacks);
                BluetoothMediaBrowserService.notifyChanged(mAddressedPlayer.getPlaybackState());
                broadcastConnectionStateChanged(BluetoothProfile.STATE_CONNECTED);
                connectCoverArt(); // only works if we have a valid PSM
            } else {
@@ -468,10 +488,7 @@ class AvrcpControllerStateMachine extends StateMachine {
                case MESSAGE_PROCESS_PLAY_POS_CHANGED:
                    if (msg.arg2 != -1) {
                        mAddressedPlayer.setPlayTime(msg.arg2);
                        if (isActive()) {
                            BluetoothMediaBrowserService.notifyChanged(
                                    mAddressedPlayer.getPlaybackState());
                        }
                        notifyChanged(mAddressedPlayer.getPlaybackState());
                    }
                    return true;

@@ -540,8 +557,11 @@ class AvrcpControllerStateMachine extends StateMachine {
                    }

                    // Let the browse tree know of the newly downloaded image so it can attach it to
                    // all the items that need it
                    mBrowseTree.notifyImageDownload(handle, uri);
                    // all the items that need it. Notify of changed nodes accordingly
                    Set<BrowseTree.BrowseNode> nodes = mBrowseTree.notifyImageDownload(handle, uri);
                    for (BrowseTree.BrowseNode node : nodes) {
                        notifyChanged(node);
                    }
                    return true;

                case DISCONNECT:
@@ -555,7 +575,7 @@ class AvrcpControllerStateMachine extends StateMachine {
        }

        private void processPlayItem(BrowseTree.BrowseNode node) {
            setActive();
            setActive(true);
            if (node == null) {
                Log.w(TAG, "Invalid item to play");
            } else {
@@ -872,11 +892,7 @@ class AvrcpControllerStateMachine extends StateMachine {
        public void enter() {
            disconnectCoverArt();
            onBrowsingDisconnected();
            if (isActive()) {
                sActiveDevice = null;
                BluetoothMediaBrowserService.trackChanged(null);
                BluetoothMediaBrowserService.addressedPlayerChanged(null);
            }
            setActive(false);
            broadcastConnectionStateChanged(BluetoothProfile.STATE_DISCONNECTING);
            transitionTo(mDisconnected);
        }
+6 −0
Original line number Diff line number Diff line
@@ -163,6 +163,11 @@ public class BluetoothMediaBrowserService extends MediaBrowserServiceCompat {
        mSession.setQueue(mMediaQueue);
    }

    private void clearNowPlayingQueue() {
        mMediaQueue.clear();
        mSession.setQueue(mMediaQueue);
    }

    static synchronized void notifyChanged(BrowseTree.BrowseNode node) {
        if (sBluetoothMediaBrowserService != null) {
            if (node.getScope() == AvrcpControllerService.BROWSE_SCOPE_NOW_PLAYING) {
@@ -177,6 +182,7 @@ public class BluetoothMediaBrowserService extends MediaBrowserServiceCompat {
        if (sBluetoothMediaBrowserService != null) {
            if (callback == null) {
                sBluetoothMediaBrowserService.setErrorPlaybackState();
                sBluetoothMediaBrowserService.clearNowPlayingQueue();
            }
            sBluetoothMediaBrowserService.mSession.setCallback(callback);
        } else {
+5 −7
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.UUID;

/**
@@ -451,8 +452,10 @@ public class BrowseTree {

    /**
     * Adds the Uri of a newly downloaded image to all tree nodes using that specific handle.
     * Returns the set of parent nodes that have children impacted by the new art so clients can
     * be notified of the change.
     */
    synchronized void notifyImageDownload(String handle, Uri uri) {
    synchronized Set<BrowseNode> notifyImageDownload(String handle, Uri uri) {
        if (DBG) Log.d(TAG, "Received downloaded image handle to cascade to BrowseNodes using it");
        ArrayList<String> nodes = getNodesUsingCoverArt(handle);
        HashSet<BrowseNode> parents = new HashSet<BrowseNode>();
@@ -468,12 +471,7 @@ public class BrowseTree {
                parents.add(node.mParent);
            }
        }

        // Update *parents* of changed nodes so applications will re-grab this node, now with art
        for (BrowseNode node : parents) {
            if (DBG) Log.d(TAG, "Notify node '" + node.getID() + "' that child has cover art now");
            BluetoothMediaBrowserService.notifyChanged(node);
        }
        return parents;
    }