BluetoothAvrcpController,没有提供协议连接断开的接口,A2DP断开成功后,BT协议栈(BT Stack)会主动发起AVRCP的断开,具体可以查看android部分源码。
蓝牙协议栈(BT Stack)相关我们不再这里分析,我们从JNI开始分析:
//packages/modules/Bluetooth/android/app/jni/com_android_bluetooth_avrcp_controller.cpp
static void btavrcp_connection_state_callback(bool rc_connect, bool br_connect,
const RawAddress& bd_addr) {
ALOGI("%s: conn state: rc: %d br: %d", __func__, rc_connect, br_connect);
std::shared_lock<std::shared_timed_mutex> lock(sCallbacks_mutex);
CallbackEnv sCallbackEnv(__func__);
if (!sCallbackEnv.valid()) return;
if (!sCallbacksObj) {
ALOGE("%s: sCallbacksObj is null", __func__);
return;
}
ScopedLocalRef<jbyteArray> addr(
sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress)));
if (!addr.get()) {
ALOGE("%s: Failed to allocate a new byte array", __func__);
return;
}
sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),
(jbyte*)bd_addr.address); //设置字节数组区域
sCallbackEnv->CallVoidMethod(sCallbacksObj, method_onConnectionStateChanged,
(jboolean)rc_connect, (jboolean)br_connect,
addr.get()); //调用 void 方法
}
通过sCallbackEnv->CallVoidMethod调用method_onConnectionStateChanged方法,通过classInitNative对应的JAVA方法:
//packages/modules/Bluetooth/android/app/jni/com_android_bluetooth_avrcp_controller.cpp
static void classInitNative(JNIEnv* env, jclass clazz) {
method_onConnectionStateChanged =
env->GetMethodID(clazz, "onConnectionStateChanged", "(ZZ[B)V");
}
AvrcpControllerService onConnectionStateChanged
调用AvrcpControllerService的onConnectionStateChanged方法:
//packages/modules/Bluetooth/abdriid/app/src/com/android/bluetooth/avrcpcontroller/AvrcpControllerService.java
public class AvrcpControllerService extends ProfileService {
// Called by JNI when a device has connected or disconnected.
private synchronized void onConnectionStateChanged(boolean remoteControlConnected,
boolean browsingConnected, byte[] address) {
BluetoothDevice device = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(address);
if (DBG) {
Log.d(TAG, "onConnectionStateChanged " + remoteControlConnected + " "
+ browsingConnected + device);
}
if (device == null) {
Log.e(TAG, "onConnectionStateChanged Device is null");
return;
}
StackEvent event =
StackEvent.connectionStateChanged(remoteControlConnected, browsingConnected);
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);
}
}
}
}
上面方法的处理处理如下:
1、调用AvrcpControllerStateMachine的disconnect方法,进行状态迁移处理
2、调用AvrcpControllerService的setActiveDevice方法,用于设置活动设备
下面分别进行分析:
AvrcpControllerStateMachine disconnect
调用StackEvent的connectionStateChanged方法,创建EVENT_TYPE_CONNECTION_STATE_CHANGED的StackEvent:
//packages/modules/Bluetooth/abdriid/app/src/com/android/bluetooth/avrcpcontroller/StackEvent.java
final class StackEvent {
static StackEvent connectionStateChanged(boolean remoteControlConnected,
boolean browsingConnected) {
StackEvent event = new StackEvent(EVENT_TYPE_CONNECTION_STATE_CHANGED);
event.mRemoteControlConnected = remoteControlConnected;
event.mBrowsingConnected = browsingConnected;
return event;
}
}
调用AvrcpControllerStateMachine的disconnect方法:
//packages/modules/Bluetooth/abdriid/app/src/com/android/bluetooth/avrcpcontroller/AvrcpControllerStateMachine.java
class AvrcpControllerStateMachine extends StateMachine {
public void disconnect() {
sendMessage(DISCONNECT);
}
}
发送DISCONNECT消息,在AvrcpControllerStateMachine的内部状态类connected的processMessage方法中处理:
//packages/modules/Bluetooth/abdriid/app/src/com/android/bluetooth/avrcpcontroller/AvrcpControllerStateMachine.java
class AvrcpControllerStateMachine extends StateMachine {
class Connected extends State {
private static final String STATE_TAG = "Avrcp.ConnectedAvrcpController";
private int mCurrentlyHeldKey = 0;
@Override
public boolean processMessage(Message msg) {
logD(STATE_TAG + " processMessage " + msg.what);
switch (msg.what) {
case DISCONNECT:
transitionTo(mDisconnecting); //迁移到Disconnecting状态
return true;
}
}
}
}
迁移到Disconnecting状态,会运行Disconnecting的enter方法:
//packages/modules/Bluetooth/abdriid/app/src/com/android/bluetooth/avrcpcontroller/AvrcpControllerStateMachine.java
class AvrcpControllerStateMachine extends StateMachine {
protected final AvrcpControllerService mService;
protected class Disconnecting extends State {
@Override
public void enter() {
disconnectCoverArt();
onBrowsingDisconnected();
if (mService.sBrowseTree != null) {
mService.sBrowseTree.mRootNode.removeChild(mBrowseTree.mRootNode); //删除媒体浏览树的所有子节点
BluetoothMediaBrowserService.notifyChanged(mService.sBrowseTree.mRootNode); //通过
}
broadcastConnectionStateChanged(BluetoothProfile.STATE_DISCONNECTING); //发送Avrcp变化为STATE_DISCONNECTING状态的广播
transitionTo(mDisconnected); //迁移到Disconnected状态
}
}
上面方法主要处理如下:
调用disconnectCoverArt方法,断开艺术封面的连接
调用onBrowsingDisconnected方法,用于处理Avrcp浏览断开连接
调用BluetoothMediaBrowserService的notifyChanged方法,通知MediaSession播放队列变化
迁移到Disconnected状态
下面分别进行分析:
AvrcpControllerStateMachine disconnectCoverArt
调用AvrcpControllerStateMachine的disconnectCoverArt方法:
//packages/modules/Bluetooth/abdriid/app/src/com/android/bluetooth/avrcpcontroller/AvrcpControllerStateMachine.java
class AvrcpControllerStateMachine extends StateMachine {
protected final AvrcpCoverArtManager mCoverArtManager;
synchronized void disconnectCoverArt() {
// Safe to call even if we're not connected
if (mCoverArtManager != null) {
logD("Disconnect BIP cover artwork");
mCoverArtManager.disconnect(mDevice);
}
}
}
调用AvrcpCoverArtManager的disconnect方法:
//packages/modules/Bluetooth/abdriid/app/src/com/android/bluetooth/avrcpcontroller/AvrcpCoverArtManager.java
public class AvrcpCoverArtManager {
protected final Map<BluetoothDevice, AvrcpBipClient> mClients = new ConcurrentHashMap<>(1);
private Map<BluetoothDevice, AvrcpBipSession> mBipSessions = new ConcurrentHashMap<>(1);
private final AvrcpCoverArtStorage mCoverArtStorage;
public synchronized boolean disconnect(BluetoothDevice device) {
debug("Disconnect " + device.getAddress());
AvrcpBipClient client = getClient(device);
if (client == null) {
warn("No client for " + device.getAddress());
return false;
}
client.shutdown();
mClients.remove(device);
mBipSessions.remove(device);
mCoverArtStorage.removeImagesForDevice(device);
return true;
}
}
调用AvrcpCoverArtStorage的removeImagesForDevice方法:
//packages/modules/Bluetooth/abdriid/app/src/com/android/bluetooth/avrcpcontroller/AvrcpCoverArtStorage.java
public class AvrcpCoverArtStorage {
private final Map<BluetoothDevice, Map<String, Bitmap>> mDeviceImages =
new ConcurrentHashMap<>(1);
public void removeImagesForDevice(BluetoothDevice device) {
if (device == null) return;
debug("Remove cover art for device " + device.getAddress());
mDeviceImages.remove(device);
}
}
AvrcpControllerStateMachine onBrowsingDisconnected
调用AvrcpControllerStateMachine的onBrowsingDisconnected方法:
//packages/modules/Bluetooth/abdriid/app/src/com/android/bluetooth/avrcpcontroller/AvrcpControllerStateMachine.java
class AvrcpControllerStateMachine extends StateMachine {
private AvrcpPlayer mAddressedPlayer;
final BrowseTree mBrowseTree;
synchronized void onBrowsingDisconnected() {
if (!mBrowsingConnected) return;
mAddressedPlayer.setPlayStatus(PlaybackStateCompat.STATE_ERROR);
AvrcpItem previousTrack = mAddressedPlayer.getCurrentTrack();
String previousTrackUuid = previousTrack != null ? previousTrack.getCoverArtUuid() : null;
mAddressedPlayer.updateCurrentTrack(null);
mBrowseTree.mNowPlayingNode.setCached(false);
mBrowseTree.mRootNode.setCached(false);
if (isActive()) {
BluetoothMediaBrowserService.notifyChanged(mBrowseTree.mNowPlayingNode);
BluetoothMediaBrowserService.notifyChanged(mBrowseTree.mRootNode);
}
removeUnusedArtwork(previousTrackUuid);
removeUnusedArtworkFromBrowseTree();
mBrowsingConnected = false;
}
}
BluetoothMediaBrowserService notifyChanged
调用BluetoothMediaBrowserService的notifyChanged方法:
//packages/modules/Bluetooth/abdriid/app/src/com/android/bluetooth/avrcpcontroller/BluetoothMediaBrowserService.java
public class BluetoothMediaBrowserService extends MediaBrowserServiceCompat {
private static BluetoothMediaBrowserService sBluetoothMediaBrowserService;
static synchronized void notifyChanged(BrowseTree.BrowseNode node) {
if (sBluetoothMediaBrowserService != null) {
if (node.getScope() == AvrcpControllerService.BROWSE_SCOPE_NOW_PLAYING) {
sBluetoothMediaBrowserService.updateNowPlayingQueue(node); //更新当前播放队列
} else {
sBluetoothMediaBrowserService.notifyChildrenChanged(node.getID()); //
}
}
}
}
调用BluetoothMediaBrowserService的updateNowPlayingQueue方法:
//packages/modules/Bluetooth/abdriid/app/src/com/android/bluetooth/avrcpcontroller/BluetoothMediaBrowserService.java
public class BluetoothMediaBrowserService extends MediaBrowserServiceCompat {
private MediaSessionCompat mSession;
private List<MediaSessionCompat.QueueItem> mMediaQueue = new ArrayList<>();
private void updateNowPlayingQueue(BrowseTree.BrowseNode node) {
List<MediaItem> songList = node.getContents();
mMediaQueue.clear();
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);
}
}
}
调用MediaSession的setQueue方法, 设置播放队列,这部分属于Media相关内容:
待更新
AvrcpControllerService setActiveDevice
调用AvrcpControllerService setActiveDevice方法:
//packages/modules/Bluetooth/abdriid/app/src/com/android/bluetooth/avrcpcontroller/AvrcpControllerService.java
public class AvrcpControllerService extends ProfileService {
private boolean setActiveDevice(BluetoothDevice device) {
A2dpSinkService a2dpSinkService = A2dpSinkService.getA2dpSinkService();
if (a2dpSinkService == null) {
return false;
}
BluetoothDevice currentActiveDevice = getActiveDevice();
if ((device == null && currentActiveDevice == null) //由于是disconnect,传入的device 为null,因此直接返回true
|| (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;
}
}
到这里BluetoothAvrcp disconnect流程就介绍完了。