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

Commit 53925721 authored by Treehugger Robot's avatar Treehugger Robot Committed by Automerger Merge Worker
Browse files

Merge "Clean up BluetoothMediaBrowserService interfaces" into main am: c2f15288 am: 3337581d

parents 97526cc2 3337581d
Loading
Loading
Loading
Loading
+33 −27
Original line number Diff line number Diff line
@@ -309,8 +309,8 @@ class AvrcpControllerStateMachine extends StateMachine {
        mBrowseTree.mNowPlayingNode.setCached(false);
        mBrowseTree.mRootNode.setCached(false);
        if (isActive()) {
            BluetoothMediaBrowserService.notifyChanged(mBrowseTree.mNowPlayingNode);
            BluetoothMediaBrowserService.notifyChanged(mBrowseTree.mRootNode);
            BluetoothMediaBrowserService.onNowPlayingQueueChanged(mBrowseTree.mNowPlayingNode);
            BluetoothMediaBrowserService.onBrowseNodeChanged(mBrowseTree.mRootNode);
        }
        removeUnusedArtwork(previousTrackUuid);
        removeUnusedArtworkFromBrowseTree();
@@ -378,19 +378,22 @@ class AvrcpControllerStateMachine extends StateMachine {
        }
    }

    private void notifyChanged(BrowseTree.BrowseNode node) {
    private void notifyNodeChanged(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);
        if (scope == AvrcpControllerService.BROWSE_SCOPE_NOW_PLAYING) {
            if (isActive()) {
                BluetoothMediaBrowserService.onNowPlayingQueueChanged(node);
            }
        } else {
            BluetoothMediaBrowserService.onBrowseNodeChanged(node);
        }
    }

    private void notifyChanged(PlaybackStateCompat state) {
    private void notifyPlaybackStateChanged(PlaybackStateCompat state) {
        if (isActive()) {
            BluetoothMediaBrowserService.notifyChanged(state);
            BluetoothMediaBrowserService.onPlaybackStateChanged(state);
        }
    }

@@ -458,7 +461,7 @@ class AvrcpControllerStateMachine extends StateMachine {
            if (mMostRecentState == BluetoothProfile.STATE_CONNECTING) {
                broadcastConnectionStateChanged(BluetoothProfile.STATE_CONNECTED);
                mService.sBrowseTree.mRootNode.addChild(mBrowseTree.mRootNode);
                BluetoothMediaBrowserService.notifyChanged(mService.sBrowseTree.mRootNode);
                BluetoothMediaBrowserService.onBrowseNodeChanged(mService.sBrowseTree.mRootNode);
                connectCoverArt(); // only works if we have a valid PSM
            } else {
                debug("Connected: Re-entering Connected ");
@@ -473,12 +476,13 @@ class AvrcpControllerStateMachine extends StateMachine {
                case ACTIVE_DEVICE_CHANGE:
                    int state = msg.arg1;
                    if (state == AvrcpControllerService.DEVICE_STATE_ACTIVE) {
                        BluetoothMediaBrowserService.addressedPlayerChanged(mSessionCallbacks);
                        BluetoothMediaBrowserService.trackChanged(
                        BluetoothMediaBrowserService.onAddressedPlayerChanged(mSessionCallbacks);
                        BluetoothMediaBrowserService.onTrackChanged(
                                mAddressedPlayer.getCurrentTrack());
                        BluetoothMediaBrowserService.notifyChanged(
                        BluetoothMediaBrowserService.onPlaybackStateChanged(
                                mAddressedPlayer.getPlaybackState());
                        BluetoothMediaBrowserService.notifyChanged(mBrowseTree.mNowPlayingNode);
                        BluetoothMediaBrowserService.onNowPlayingQueueChanged(
                                mBrowseTree.mNowPlayingNode);

                        // If we switch to a device that is playing and we don't have focus, pause
                        int focusState = getFocusState();
@@ -583,8 +587,8 @@ class AvrcpControllerStateMachine extends StateMachine {
                    downloadImageIfNeeded(track);
                    mAddressedPlayer.updateCurrentTrack(track);
                    if (isActive()) {
                        BluetoothMediaBrowserService.trackChanged(track);
                        BluetoothMediaBrowserService.notifyChanged(
                        BluetoothMediaBrowserService.onTrackChanged(track);
                        BluetoothMediaBrowserService.onPlaybackStateChanged(
                                mAddressedPlayer.getPlaybackState());
                    }
                    if (previousTrack != null) {
@@ -604,7 +608,8 @@ class AvrcpControllerStateMachine extends StateMachine {
                        return true;
                    }

                    BluetoothMediaBrowserService.notifyChanged(mAddressedPlayer.getPlaybackState());
                    BluetoothMediaBrowserService.onPlaybackStateChanged(
                            mAddressedPlayer.getPlaybackState());

                    int focusState = getFocusState();
                    if (focusState == AudioManager.ERROR) {
@@ -629,7 +634,7 @@ class AvrcpControllerStateMachine extends StateMachine {
                case MESSAGE_PROCESS_PLAY_POS_CHANGED:
                    if (msg.arg2 != -1) {
                        mAddressedPlayer.setPlayTime(msg.arg2);
                        notifyChanged(mAddressedPlayer.getPlaybackState());
                        notifyPlaybackStateChanged(mAddressedPlayer.getPlaybackState());
                    }
                    return true;

@@ -650,7 +655,8 @@ class AvrcpControllerStateMachine extends StateMachine {
                        debug(
                                "Connected: Addressed player change has invalidated the now playing"
                                        + " list");
                        BluetoothMediaBrowserService.notifyChanged(mBrowseTree.mNowPlayingNode);
                        BluetoothMediaBrowserService.onNowPlayingQueueChanged(
                                mBrowseTree.mNowPlayingNode);
                    }
                    removeUnusedArtworkFromBrowseTree();

@@ -691,13 +697,13 @@ class AvrcpControllerStateMachine extends StateMachine {
                case MESSAGE_PROCESS_SUPPORTED_APPLICATION_SETTINGS:
                    mAddressedPlayer.setSupportedPlayerApplicationSettings(
                            (PlayerApplicationSettings) msg.obj);
                    notifyChanged(mAddressedPlayer.getPlaybackState());
                    notifyPlaybackStateChanged(mAddressedPlayer.getPlaybackState());
                    return true;

                case MESSAGE_PROCESS_CURRENT_APPLICATION_SETTINGS:
                    mAddressedPlayer.setCurrentPlayerApplicationSettings(
                            (PlayerApplicationSettings) msg.obj);
                    notifyChanged(mAddressedPlayer.getPlaybackState());
                    notifyPlaybackStateChanged(mAddressedPlayer.getPlaybackState());
                    return true;

                case MESSAGE_PROCESS_AVAILABLE_PLAYER_CHANGED:
@@ -720,7 +726,7 @@ class AvrcpControllerStateMachine extends StateMachine {
                    // track now has cover artwork
                    boolean addedArtwork = mAddressedPlayer.notifyImageDownload(uuid, uri);
                    if (addedArtwork && isActive()) {
                        BluetoothMediaBrowserService.trackChanged(
                        BluetoothMediaBrowserService.onTrackChanged(
                                mAddressedPlayer.getCurrentTrack());
                    }

@@ -728,7 +734,7 @@ class AvrcpControllerStateMachine extends StateMachine {
                    // all the items that need it. Notify of changed nodes accordingly
                    Set<BrowseTree.BrowseNode> nodes = mBrowseTree.notifyImageDownload(uuid, uri);
                    for (BrowseTree.BrowseNode node : nodes) {
                        notifyChanged(node);
                        notifyNodeChanged(node);
                    }

                    // Delete images that were downloaded and entirely unused
@@ -825,7 +831,7 @@ class AvrcpControllerStateMachine extends StateMachine {
            debug("Connected: processAvailablePlayerChanged");
            mBrowseTree.mRootNode.setCached(false);
            mBrowseTree.mRootNode.setExpectedChildren(BrowseTree.DEFAULT_FOLDER_SIZE);
            BluetoothMediaBrowserService.notifyChanged(mBrowseTree.mRootNode);
            BluetoothMediaBrowserService.onBrowseNodeChanged(mBrowseTree.mRootNode);
            removeUnusedArtworkFromBrowseTree();
            requestContents(mBrowseTree.mRootNode);
        }
@@ -891,7 +897,7 @@ class AvrcpControllerStateMachine extends StateMachine {
                    // for the list to populate.
                    int newSize = mBrowseNode.addChildren(folderList);
                    debug("GetFolderList: Added " + newSize + " items to the browse tree");
                    notifyChanged(mBrowseNode);
                    notifyNodeChanged(mBrowseNode);

                    if (mBrowseNode.getChildrenCount() >= endIndicator
                            || folderList.size() == 0
@@ -990,7 +996,7 @@ class AvrcpControllerStateMachine extends StateMachine {
                        mBrowseTree.setCurrentBrowsedFolder(BrowseTree.ROOT);
                        rootNode.setExpectedChildren(playerList.size());
                        rootNode.setCached(true);
                        notifyChanged(rootNode);
                        notifyNodeChanged(rootNode);
                    }
                    transitionTo(mConnected);
                    break;
@@ -1145,7 +1151,7 @@ class AvrcpControllerStateMachine extends StateMachine {
            // Whatever we have, notify on it so the UI doesn't hang
            if (mBrowseNode != null) {
                mBrowseNode.setCached(true);
                notifyChanged(mBrowseNode);
                notifyNodeChanged(mBrowseNode);
            }

            mBrowseNode = null;
@@ -1161,7 +1167,7 @@ class AvrcpControllerStateMachine extends StateMachine {
            onBrowsingDisconnected();
            if (mService.sBrowseTree != null) {
                mService.sBrowseTree.mRootNode.removeChild(mBrowseTree.mRootNode);
                BluetoothMediaBrowserService.notifyChanged(mService.sBrowseTree.mRootNode);
                BluetoothMediaBrowserService.onBrowseNodeChanged(mService.sBrowseTree.mRootNode);
            }
            broadcastConnectionStateChanged(BluetoothProfile.STATE_DISCONNECTING);
            transitionTo(mDisconnected);
+150 −89
Original line number Diff line number Diff line
@@ -33,6 +33,7 @@ import androidx.media.MediaBrowserServiceCompat;

import com.android.bluetooth.BluetoothPrefs;
import com.android.bluetooth.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;

import java.util.ArrayList;
@@ -54,6 +55,9 @@ import java.util.List;
public class BluetoothMediaBrowserService extends MediaBrowserServiceCompat {
    private static final String TAG = BluetoothMediaBrowserService.class.getSimpleName();

    private static final Object INSTANCE_LOCK = new Object();

    @GuardedBy("INSTANCE_LOCK")
    private static BluetoothMediaBrowserService sBluetoothMediaBrowserService;

    private MediaSessionCompat mSession;
@@ -84,8 +88,14 @@ public class BluetoothMediaBrowserService extends MediaBrowserServiceCompat {
            String action = intent.getAction();
            if (action.equals(Intent.ACTION_LOCALE_CHANGED)) {
                Log.d(TAG, "Locale has updated");
                if (sBluetoothMediaBrowserService == null) return;
                MediaSessionCompat session = sBluetoothMediaBrowserService.getSession();

                BluetoothMediaBrowserService service = BluetoothMediaBrowserService.getInstance();
                if (service == null) {
                    Log.w(TAG, "onReceive(): Got locale update, but service isn't active");
                    return;
                }

                MediaSessionCompat session = service.getSession();

                // Update playback state error message under new locale, if applicable
                MediaControllerCompat controller = session.getController();
@@ -103,6 +113,27 @@ public class BluetoothMediaBrowserService extends MediaBrowserServiceCompat {

    private LocaleChangedReceiver mReceiver;

    /**
     * Set the BluetoothMediaBrowserService instance
     *
     * <p>This object is a singleton, as their can only be one service instance active for a process
     * at a time.
     */
    private static void setInstance(BluetoothMediaBrowserService service) {
        synchronized (INSTANCE_LOCK) {
            sBluetoothMediaBrowserService = service;
            Log.i(TAG, "Service set to " + service);
        }
    }

    /** Get the BluetoothMediaBrowserService instance */
    @VisibleForTesting
    public static BluetoothMediaBrowserService getInstance() {
        synchronized (INSTANCE_LOCK) {
            return sBluetoothMediaBrowserService;
        }
    }

    /**
     * Initialize this BluetoothMediaBrowserService, creating our MediaSessionCompat, MediaPlayer
     * and MediaMetaData, and setting up mechanisms to talk with the AvrcpControllerService.
@@ -121,20 +152,23 @@ public class BluetoothMediaBrowserService extends MediaBrowserServiceCompat {
        mSession.setQueueTitle(getString(R.string.bluetooth_a2dp_sink_queue_name));
        mSession.setQueue(mMediaQueue);
        setErrorPlaybackState();
        sBluetoothMediaBrowserService = this;

        mReceiver = new LocaleChangedReceiver();
        IntentFilter filter = new IntentFilter();
        filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
        filter.addAction(Intent.ACTION_LOCALE_CHANGED);
        registerReceiver(mReceiver, filter);

        setInstance(this);
    }

    @Override
    public void onDestroy() {
        Log.d(TAG, "Service Destroyed");
        super.onDestroy();
        unregisterReceiver(mReceiver);
        mReceiver = null;
        setInstance(null);
    }

    /**
@@ -259,8 +293,27 @@ public class BluetoothMediaBrowserService extends MediaBrowserServiceCompat {
        return new BrowserRoot(BrowseTree.ROOT, style);
    }

    private void updateNowPlayingQueue(BrowseTree.BrowseNode node) {
        List<MediaItem> songList = node.getContents();
    static synchronized void onNowPlayingQueueChanged(BrowseTree.BrowseNode node) {
        BluetoothMediaBrowserService service = BluetoothMediaBrowserService.getInstance();
        if (service == null) {
            Log.w(TAG, "onNowPlayingQueueChanged(node=" + node + "): Service not available");
            return;
        }

        if (node == null) {
            Log.w(TAG, "Received now playing update for null node");
            return;
        }

        if (node.getScope() != AvrcpControllerService.BROWSE_SCOPE_NOW_PLAYING) {
            Log.w(TAG, "Received now playing update for node not in now playing scope.");
            return;
        }

        service.setNowPlayingQueue(node.getContents());
    }

    private void setNowPlayingQueue(List<MediaItem> songList) {
        mMediaQueue.clear();
        if (songList != null && songList.size() > 0) {
            for (MediaItem song : songList) {
@@ -280,104 +333,107 @@ public class BluetoothMediaBrowserService extends MediaBrowserServiceCompat {
        mSession.setQueue(null);
    }

    static synchronized void notifyChanged(BrowseTree.BrowseNode node) {
        if (sBluetoothMediaBrowserService != null) {
            if (node.getScope() == AvrcpControllerService.BROWSE_SCOPE_NOW_PLAYING) {
                sBluetoothMediaBrowserService.updateNowPlayingQueue(node);
            } else {
    static synchronized void onBrowseNodeChanged(BrowseTree.BrowseNode node) {
        BluetoothMediaBrowserService service = BluetoothMediaBrowserService.getInstance();
        if (service == null) {
            Log.w(TAG, "onBrowseNodeChanged(node=" + node + "): Service not available");
            return;
        }

        if (node == null) {
            Log.w(TAG, "Received browse node update for null node");
            return;
        }

        Log.d(TAG, "Browse Node contents changed, node=" + node);
                sBluetoothMediaBrowserService.notifyChildrenChanged(node.getID());

        int scope = node.getScope();
        if (scope != AvrcpControllerService.BROWSE_SCOPE_VFS
                && scope != AvrcpControllerService.BROWSE_SCOPE_PLAYER_LIST) {
            Log.w(TAG, "Received browse tree update for node outside of player or VFS scope");
            return;
        }
        service.notifyChildrenChanged(node.getID());
    }

    static synchronized void onAddressedPlayerChanged(MediaSessionCompat.Callback callback) {
        BluetoothMediaBrowserService service = BluetoothMediaBrowserService.getInstance();
        if (service == null) {
            Log.w(TAG, "addressedPlayerChanged(callback=" + callback + "): Service not available");
            return;
        }

    static synchronized void addressedPlayerChanged(MediaSessionCompat.Callback callback) {
        if (sBluetoothMediaBrowserService != null) {
        if (callback == null) {
                sBluetoothMediaBrowserService.setErrorPlaybackState();
                sBluetoothMediaBrowserService.clearNowPlayingQueue();
            service.setErrorPlaybackState();
            service.clearNowPlayingQueue();
        }
            sBluetoothMediaBrowserService.mSession.setCallback(callback);
        } else {
            Log.w(TAG, "addressedPlayerChanged Unavailable");
        service.mSession.setCallback(callback);
    }

    static synchronized void onTrackChanged(AvrcpItem track) {
        BluetoothMediaBrowserService service = BluetoothMediaBrowserService.getInstance();
        if (service == null) {
            Log.w(TAG, "trackChanged(track=" + track + "): Service not available");
            return;
        }

    static synchronized void trackChanged(AvrcpItem track) {
        Log.d(TAG, "Track Changed, track=" + track);
        if (sBluetoothMediaBrowserService != null) {
        if (track != null) {
                sBluetoothMediaBrowserService.mSession.setMetadata(track.toMediaMetadata());
            service.mSession.setMetadata(track.toMediaMetadata());
        } else {
                sBluetoothMediaBrowserService.mSession.setMetadata(null);
            service.mSession.setMetadata(null);
        }

        } else {
            Log.w(TAG, "trackChanged Unavailable");
    }

    static synchronized void onPlaybackStateChanged(PlaybackStateCompat state) {
        BluetoothMediaBrowserService service = BluetoothMediaBrowserService.getInstance();
        if (service == null) {
            Log.w(TAG, "onPlaybackStateChanged(state=" + state + "): Service not available");
            return;
        }

    static synchronized void notifyChanged(PlaybackStateCompat playbackState) {
        Log.d(
                TAG,
                "Playback State Changed, state="
                        + AvrcpControllerUtils.playbackStateCompatToString(playbackState));
        if (sBluetoothMediaBrowserService != null) {
            sBluetoothMediaBrowserService.mSession.setPlaybackState(playbackState);
        } else {
            Log.w(TAG, "notifyChanged Unavailable");
        }
    }

    /** Send AVRCP Play command */
    public static synchronized void play() {
        if (sBluetoothMediaBrowserService != null) {
            sBluetoothMediaBrowserService.mSession.getController().getTransportControls().play();
        } else {
            Log.w(TAG, "play Unavailable");
        }
    }

    /** Send AVRCP Pause command */
    public static synchronized void pause() {
        if (sBluetoothMediaBrowserService != null) {
            sBluetoothMediaBrowserService.mSession.getController().getTransportControls().pause();
        } else {
            Log.w(TAG, "pause Unavailable");
        }
                        + AvrcpControllerUtils.playbackStateCompatToString(state));
        service.mSession.setPlaybackState(state);
    }

    /** Get playback state */
    public static synchronized PlaybackStateCompat getPlaybackState() {
        if (sBluetoothMediaBrowserService != null) {
            MediaSessionCompat session = sBluetoothMediaBrowserService.getSession();
        BluetoothMediaBrowserService service = BluetoothMediaBrowserService.getInstance();
        if (service == null) {
            Log.w(TAG, "getPlaybackState(): Service not available");
            return null;
        }

        MediaSessionCompat session = service.getSession();
        if (session == null) return null;
        MediaControllerCompat controller = session.getController();
        PlaybackStateCompat playbackState =
                controller == null ? null : controller.getPlaybackState();
        return playbackState;
    }
        return null;
    }

    /** Get object for controlling playback */
    public static synchronized MediaControllerCompat.TransportControls getTransportControls() {
        if (sBluetoothMediaBrowserService != null) {
            return sBluetoothMediaBrowserService.mSession.getController().getTransportControls();
        } else {
            Log.w(TAG, "transportControls Unavailable");
        BluetoothMediaBrowserService service = BluetoothMediaBrowserService.getInstance();
        if (service == null) {
            Log.w(TAG, "getTransportControls(): Service not available");
            return null;
        }
        return service.mSession.getController().getTransportControls();
    }

    /** Set Media session active whenever we have Focus of any kind */
    public static synchronized void setActive(boolean active) {
        if (sBluetoothMediaBrowserService != null) {
            Log.d(TAG, "Setting the session active state to:" + active);
            sBluetoothMediaBrowserService.mSession.setActive(active);
        } else {
            Log.w(TAG, "setActive Unavailable");
        BluetoothMediaBrowserService service = BluetoothMediaBrowserService.getInstance();
        if (service == null) {
            Log.w(TAG, "setActive(active=" + active + "): Service not available");
            return;
        }
        Log.d(TAG, "Setting the session active state to:" + active);
        service.mSession.setActive(active);
    }

    /**
@@ -387,41 +443,46 @@ public class BluetoothMediaBrowserService extends MediaBrowserServiceCompat {
     */
    @VisibleForTesting
    public static synchronized boolean isActive() {
        if (sBluetoothMediaBrowserService != null) {
            return sBluetoothMediaBrowserService.mSession.isActive();
        }
        BluetoothMediaBrowserService service = BluetoothMediaBrowserService.getInstance();
        if (service == null) {
            Log.w(TAG, "isActive(): Service not available");
            return false;
        }
        return service.mSession.isActive();
    }

    /** Get Media session for updating state */
    public static synchronized MediaSessionCompat getSession() {
        if (sBluetoothMediaBrowserService != null) {
            return sBluetoothMediaBrowserService.mSession;
        } else {
            Log.w(TAG, "getSession Unavailable");
        BluetoothMediaBrowserService service = BluetoothMediaBrowserService.getInstance();
        if (service == null) {
            Log.w(TAG, "getSession(): Service not available");
            return null;
        }
        return service.mSession;
    }

    /** Reset the state of BluetoothMediaBrowserService to that before a device connected */
    public static synchronized void reset() {
        if (sBluetoothMediaBrowserService != null) {
            sBluetoothMediaBrowserService.clearNowPlayingQueue();
            sBluetoothMediaBrowserService.mSession.setMetadata(null);
            sBluetoothMediaBrowserService.setErrorPlaybackState();
            sBluetoothMediaBrowserService.mSession.setCallback(null);
            Log.d(TAG, "Service state has been reset");
        } else {
            Log.w(TAG, "reset unavailable");
        BluetoothMediaBrowserService service = BluetoothMediaBrowserService.getInstance();
        if (service == null) {
            Log.w(TAG, "reset(): Service not available");
            return;
        }

        service.clearNowPlayingQueue();
        service.mSession.setMetadata(null);
        service.setErrorPlaybackState();
        service.mSession.setCallback(null);
        Log.d(TAG, "Service state has been reset");
    }

    /** Get the state of the BluetoothMediaBrowserService as a debug string */
    public static synchronized String dump() {
        StringBuilder sb = new StringBuilder();
        sb.append(TAG + ":");
        if (sBluetoothMediaBrowserService != null) {
            MediaSessionCompat session = sBluetoothMediaBrowserService.getSession();
        BluetoothMediaBrowserService service = BluetoothMediaBrowserService.getInstance();
        if (service != null) {
            MediaSessionCompat session = service.getSession();
            MediaControllerCompat controller = session.getController();
            MediaMetadataCompat metadata = controller == null ? null : controller.getMetadata();
            PlaybackStateCompat playbackState =
@@ -456,7 +517,7 @@ public class BluetoothMediaBrowserService extends MediaBrowserServiceCompat {
                    "\n    playbackState="
                            + AvrcpControllerUtils.playbackStateCompatToString(playbackState));
            sb.append("\n    queue=" + queue);
            sb.append("\n    internal_queue=" + sBluetoothMediaBrowserService.mMediaQueue);
            sb.append("\n    internal_queue=" + service.mMediaQueue);
            sb.append("\n    session active state=").append(isActive());
        } else {
            Log.w(TAG, "dump Unavailable");