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

Commit 41c693cc authored by Sal Savage's avatar Sal Savage Committed by Automerger Merge Worker
Browse files

Merge "Have AvrcpControllerService own the active device" am: c6332823

Original change: https://android-review.googlesource.com/c/platform/packages/apps/Bluetooth/+/1611493

MUST ONLY BE SUBMITTED BY AUTOMERGER

Change-Id: I527e86cbf3c0a6d0ee9bfbed5047c15da0a8b5c6
parents c8e95c42 c6332823
Loading
Loading
Loading
Loading
+86 −0
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@ import android.util.Log;

import com.android.bluetooth.R;
import com.android.bluetooth.Utils;
import com.android.bluetooth.a2dpsink.A2dpSinkService;
import com.android.bluetooth.btservice.ProfileService;

import java.util.ArrayList;
@@ -88,12 +89,18 @@ public class AvrcpControllerService extends ProfileService {
    public static final int KEY_STATE_PRESSED = 0;
    public static final int KEY_STATE_RELEASED = 1;

    /* Active Device State Variables */
    public static final int DEVICE_STATE_INACTIVE = 0;
    public static final int DEVICE_STATE_ACTIVE = 1;

    static BrowseTree sBrowseTree;
    private static AvrcpControllerService sService;
    private final BluetoothAdapter mAdapter;

    protected Map<BluetoothDevice, AvrcpControllerStateMachine> mDeviceStateMap =
            new ConcurrentHashMap<>(1);
    private BluetoothDevice mActiveDevice = null;
    private final Object mActiveDeviceLock = new Object();

    private boolean mCoverArtEnabled = false;
    protected AvrcpCoverArtManager mCoverArtManager;
@@ -139,11 +146,13 @@ public class AvrcpControllerService extends ProfileService {
        // Start the media browser service.
        Intent startIntent = new Intent(this, BluetoothMediaBrowserService.class);
        startService(startIntent);
        setActiveDevice(null);
        return true;
    }

    @Override
    protected synchronized boolean stop() {
        setActiveDevice(null);
        Intent stopIntent = new Intent(this, BluetoothMediaBrowserService.class);
        stopService(stopIntent);
        for (AvrcpControllerStateMachine stateMachine : mDeviceStateMap.values()) {
@@ -163,6 +172,56 @@ public class AvrcpControllerService extends ProfileService {
        return sService;
    }

    /**
     * Get the current active device
     */
    public BluetoothDevice getActiveDevice() {
        synchronized (mActiveDeviceLock) {
            return mActiveDevice;
        }
    }

    /**
     * Set the current active device, notify devices of activity status
     */
    private boolean setActiveDevice(BluetoothDevice device) {
        A2dpSinkService a2dpSinkService = A2dpSinkService.getA2dpSinkService();
        if (a2dpSinkService == null) {
            return false;
        }

        BluetoothDevice currentActiveDevice = getActiveDevice();
        if ((device == null && currentActiveDevice == null)
                || (device != null && device.equals(currentActiveDevice))) {
            return true;
        }

        // Try and update the active device
        synchronized (mActiveDeviceLock) {
            if (a2dpSinkService.setActiveDevice(device)) {
                mActiveDevice = device;

                // Pause the old active device
                if (currentActiveDevice != null) {
                    AvrcpControllerStateMachine oldStateMachine =
                            getStateMachine(currentActiveDevice);
                    if (oldStateMachine != null) {
                        oldStateMachine.setDeviceState(DEVICE_STATE_INACTIVE);
                    }
                }

                AvrcpControllerStateMachine stateMachine = getStateMachine(device);
                if (stateMachine != null) {
                    stateMachine.setDeviceState(DEVICE_STATE_ACTIVE);
                } else {
                    BluetoothMediaBrowserService.reset();
                }
                return true;
            }
        }
        return false;
    }

    protected AvrcpControllerStateMachine newStateMachine(BluetoothDevice device) {
        return new AvrcpControllerStateMachine(device, this);
    }
@@ -198,6 +257,10 @@ public class AvrcpControllerService extends ProfileService {
                requestedNode = stateMachine.findNode(parentMediaId);
                if (requestedNode != null) {
                    if (DBG) Log.d(TAG, "Found a node");
                    BluetoothDevice device = stateMachine.getDevice();
                    if (device != null) {
                        setActiveDevice(device);
                    }
                    stateMachine.playItem(requestedNode);
                    break;
                }
@@ -234,6 +297,12 @@ public class AvrcpControllerService extends ProfileService {
            if (DBG) Log.d(TAG, "Didn't find a node");
            return new ArrayList(0);
        } else {
            // If we found a node and it belongs to a device then go ahead and make it active
            BluetoothDevice device = requestedNode.getDevice();
            if (device != null) {
                setActiveDevice(device);
            }

            if (!requestedNode.isCached()) {
                if (DBG) Log.d(TAG, "node is not cached");
                refreshContents(requestedNode);
@@ -355,8 +424,15 @@ public class AvrcpControllerService extends ProfileService {
        AvrcpControllerStateMachine stateMachine = getOrCreateStateMachine(device);
        if (remoteControlConnected || browsingConnected) {
            stateMachine.connect(event);
            // The first device to connect gets to be the active device
            if (getActiveDevice() == null) {
                setActiveDevice(device);
            }
        } else {
            stateMachine.disconnect();
            if (device.equals(getActiveDevice())) {
                setActiveDevice(null);
            }
        }
    }

@@ -729,6 +805,10 @@ public class AvrcpControllerService extends ProfileService {
     * Remove state machine from device map once it is no longer needed.
     */
    public void removeStateMachine(AvrcpControllerStateMachine stateMachine) {
        BluetoothDevice device = stateMachine.getDevice();
        if (device.equals(getActiveDevice())) {
            setActiveDevice(null);
        }
        mDeviceStateMap.remove(stateMachine.getDevice());
    }

@@ -737,6 +817,9 @@ public class AvrcpControllerService extends ProfileService {
    }

    protected AvrcpControllerStateMachine getStateMachine(BluetoothDevice device) {
        if (device == null) {
            return null;
        }
        return mDeviceStateMap.get(device);
    }

@@ -783,6 +866,7 @@ public class AvrcpControllerService extends ProfileService {
    public void dump(StringBuilder sb) {
        super.dump(sb);
        ProfileService.println(sb, "Devices Tracked = " + mDeviceStateMap.size());
        ProfileService.println(sb, "Active Device = " + mActiveDevice);

        for (AvrcpControllerStateMachine stateMachine : mDeviceStateMap.values()) {
            ProfileService.println(sb,
@@ -795,6 +879,8 @@ public class AvrcpControllerService extends ProfileService {
        if (mCoverArtManager != null) {
            sb.append("\n  " + mCoverArtManager.toString());
        }

        sb.append("\n  " + BluetoothMediaBrowserService.dump() + "\n");
    }

    /*JNI*/
+30 −52
Original line number Diff line number Diff line
@@ -55,6 +55,7 @@ class AvrcpControllerStateMachine extends StateMachine {
    //0->99 Events from Outside
    public static final int CONNECT = 1;
    public static final int DISCONNECT = 2;
    public static final int ACTIVE_DEVICE_CHANGE = 3;

    //100->199 Internal Events
    protected static final int CLEANUP = 100;
@@ -184,7 +185,7 @@ class AvrcpControllerStateMachine extends StateMachine {
     *
     * @return device in focus
     */
    public synchronized BluetoothDevice getDevice() {
    public BluetoothDevice getDevice() {
        return mDevice;
    }

@@ -223,55 +224,20 @@ class AvrcpControllerStateMachine extends StateMachine {
        ProfileService.println(sb, "mDevice: " + mDevice.getAddress() + "("
                + mDevice.getName() + ") " + this.toString());
        ProfileService.println(sb, "isActive: " + isActive());
        ProfileService.println(sb, "Control: " + mRemoteControlConnected);
        ProfileService.println(sb, "Browsing: " + mBrowsingConnected);
    }

    @VisibleForTesting
    boolean isActive() {
        return mDevice == sActiveDevice;
    }

    /*
     * requestActive
     *
     * Set the current device active if nothing an already connected device isn't playing
     */
    private boolean requestActive() {
        if (sActiveDevice == null
                || BluetoothMediaBrowserService.getPlaybackState()
                != PlaybackStateCompat.STATE_PLAYING) {
            return setActive(true);
        }
        return false;
        return mDevice.equals(mService.getActiveDevice());
    }

    /**
     * Attempt to set the active status for this device
     */
    boolean setActive(boolean becomeActive) {
        logD("setActive(" + becomeActive + ")");
        A2dpSinkService a2dpSinkService = A2dpSinkService.getA2dpSinkService();
        if (a2dpSinkService == null) {
            return false;
        }
        if (becomeActive) {
            if (isActive()) {
                return true;
            }

            if (a2dpSinkService.setActiveDevice(mDevice)) {
                sActiveDevice = mDevice;
                BluetoothMediaBrowserService.addressedPlayerChanged(mSessionCallbacks);
                BluetoothMediaBrowserService.notifyChanged(mAddressedPlayer.getPlaybackState());
                BluetoothMediaBrowserService.notifyChanged(mBrowseTree.mNowPlayingNode);
            }
            return mDevice == sActiveDevice;
        } else if (isActive()) {
            sActiveDevice = null;
            a2dpSinkService.setActiveDevice(null);
            BluetoothMediaBrowserService.trackChanged(null);
            BluetoothMediaBrowserService.addressedPlayerChanged(null);
        }
        return true;
    public void setDeviceState(int state) {
        sendMessage(ACTIVE_DEVICE_CHANGE, state);
    }

    @Override
@@ -286,10 +252,6 @@ class AvrcpControllerStateMachine extends StateMachine {
    }

    synchronized void onBrowsingConnected() {
        if (mBrowsingConnected) return;
        mService.sBrowseTree.mRootNode.addChild(mBrowseTree.mRootNode);
        BluetoothMediaBrowserService.notifyChanged(mService
                .sBrowseTree.mRootNode);
        mBrowsingConnected = true;
    }

@@ -303,10 +265,6 @@ class AvrcpControllerStateMachine extends StateMachine {
        if (isActive()) {
            BluetoothMediaBrowserService.notifyChanged(mBrowseTree.mNowPlayingNode);
        }
        mService.sBrowseTree.mRootNode.removeChild(
                mBrowseTree.mRootNode);
        BluetoothMediaBrowserService.notifyChanged(mService
                .sBrowseTree.mRootNode);
        removeUnusedArtwork(previousTrackUuid);
        removeUnusedArtworkFromBrowseTree();
        mBrowsingConnected = false;
@@ -426,6 +384,10 @@ class AvrcpControllerStateMachine extends StateMachine {
                case CLEANUP:
                    mService.removeStateMachine(AvrcpControllerStateMachine.this);
                    break;
                case ACTIVE_DEVICE_CHANGE:
                    // Wait until we're connected to process this
                    deferMessage(message);
                    break;
            }
            return true;
        }
@@ -448,8 +410,9 @@ class AvrcpControllerStateMachine extends StateMachine {
        @Override
        public void enter() {
            if (mMostRecentState == BluetoothProfile.STATE_CONNECTING) {
                requestActive();
                broadcastConnectionStateChanged(BluetoothProfile.STATE_CONNECTED);
                mService.sBrowseTree.mRootNode.addChild(mBrowseTree.mRootNode);
                BluetoothMediaBrowserService.notifyChanged(mService.sBrowseTree.mRootNode);
                connectCoverArt(); // only works if we have a valid PSM
            } else {
                logD("ReEnteringConnected");
@@ -461,6 +424,21 @@ class AvrcpControllerStateMachine extends StateMachine {
        public boolean processMessage(Message msg) {
            logD(STATE_TAG + " processMessage " + msg.what);
            switch (msg.what) {
                case ACTIVE_DEVICE_CHANGE:
                    int state = msg.arg1;
                    if (state == AvrcpControllerService.DEVICE_STATE_ACTIVE) {
                        BluetoothMediaBrowserService.addressedPlayerChanged(mSessionCallbacks);
                        BluetoothMediaBrowserService.trackChanged(
                                mAddressedPlayer.getCurrentTrack());
                        BluetoothMediaBrowserService.notifyChanged(
                                mAddressedPlayer.getPlaybackState());
                        BluetoothMediaBrowserService.notifyChanged(mBrowseTree.mNowPlayingNode);
                    } else {
                        sendMessage(MSG_AVRCP_PASSTHRU,
                                AvrcpControllerService.PASS_THRU_CMD_ID_PAUSE);
                    }
                    return true;

                case MESSAGE_PROCESS_SET_ABS_VOL_CMD:
                    mVolumeChangedNotificationsToIgnore++;
                    removeMessages(MESSAGE_INTERNAL_ABS_VOL_TIMEOUT);
@@ -643,7 +621,6 @@ class AvrcpControllerStateMachine extends StateMachine {
        }

        private void processPlayItem(BrowseTree.BrowseNode node) {
            setActive(true);
            if (node == null) {
                Log.w(TAG, "Invalid item to play");
            } else {
@@ -970,7 +947,8 @@ class AvrcpControllerStateMachine extends StateMachine {
        public void enter() {
            disconnectCoverArt();
            onBrowsingDisconnected();
            setActive(false);
            mService.sBrowseTree.mRootNode.removeChild(mBrowseTree.mRootNode);
            BluetoothMediaBrowserService.notifyChanged(mService.sBrowseTree.mRootNode);
            broadcastConnectionStateChanged(BluetoothProfile.STATE_DISCONNECTING);
            transitionTo(mDisconnected);
        }
+62 −3
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@ import android.app.PendingIntent;
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.media.MediaBrowserCompat.MediaItem;
import android.support.v4.media.MediaMetadataCompat;
import android.support.v4.media.session.MediaControllerCompat;
import android.support.v4.media.session.MediaSessionCompat;
import android.support.v4.media.session.PlaybackStateCompat;
@@ -154,19 +155,21 @@ public class BluetoothMediaBrowserService extends MediaBrowserServiceCompat {
    private void updateNowPlayingQueue(BrowseTree.BrowseNode node) {
        List<MediaItem> songList = node.getContents();
        mMediaQueue.clear();
        if (songList != null) {
        if (songList != null && songList.size() > 0) {
            for (MediaItem song : songList) {
                mMediaQueue.add(new MediaSessionCompat.QueueItem(
                        song.getDescription(),
                        mMediaQueue.size()));
            }
        }
            mSession.setQueue(mMediaQueue);
        } else {
            mSession.setQueue(null);
        }
    }

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

    static synchronized void notifyChanged(BrowseTree.BrowseNode node) {
@@ -284,4 +287,60 @@ public class BluetoothMediaBrowserService extends MediaBrowserServiceCompat {
            return null;
        }
    }

    /**
     * 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);
            if (DBG) Log.d(TAG, "Service state has been reset");
        } else {
            Log.w(TAG, "reset unavailable");
        }
    }

    /**
     * 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();
            MediaControllerCompat controller = session.getController();
            MediaMetadataCompat metadata = controller == null ? null : controller.getMetadata();
            PlaybackStateCompat playbackState =
                    controller == null ? null : controller.getPlaybackState();
            List<MediaSessionCompat.QueueItem> queue =
                    controller == null ? null : controller.getQueue();
            if (metadata != null) {
                sb.append("\n    track={");
                sb.append("title=" + metadata.getString(MediaMetadataCompat.METADATA_KEY_TITLE));
                sb.append(", artist="
                        + metadata.getString(MediaMetadataCompat.METADATA_KEY_ARTIST));
                sb.append(", album=" + metadata.getString(MediaMetadataCompat.METADATA_KEY_ALBUM));
                sb.append(", track_number="
                        + metadata.getLong(MediaMetadataCompat.METADATA_KEY_TRACK_NUMBER));
                sb.append(", total_tracks="
                        + metadata.getLong(MediaMetadataCompat.METADATA_KEY_NUM_TRACKS));
                sb.append(", genre=" + metadata.getString(MediaMetadataCompat.METADATA_KEY_GENRE));
                sb.append(", album_art="
                        + metadata.getString(MediaMetadataCompat.METADATA_KEY_ALBUM_ART_URI));
                sb.append("}");
            } else {
                sb.append("\n    track=" + metadata);
            }
            sb.append("\n    playbackState=" + playbackState);
            sb.append("\n    queue=" + queue);
            sb.append("\n    internal_queue=" + sBluetoothMediaBrowserService.mMediaQueue);
        } else {
            Log.w(TAG, "dump Unavailable");
            sb.append(" null");
        }
        return sb.toString();
    }
}
+381 −186

File changed.

Preview size limit exceeded, changes collapsed.