diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java index 0dc73d9278a28..6df60d6bdd3af 100644 --- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java +++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java @@ -21,6 +21,8 @@ import static com.android.server.audio.AudioService.CONNECTION_STATE_DISCONNECTE import android.annotation.NonNull; import android.bluetooth.BluetoothA2dp; import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothHeadset; +import android.bluetooth.BluetoothHearingAid; import android.bluetooth.BluetoothProfile; import android.content.ContentResolver; import android.content.Context; @@ -424,11 +426,28 @@ import java.util.ArrayList; } /*package*/ void postDisconnectHearingAid() { - sendMsgNoDelay(MSG_DISCONNECT_HEARING_AID, SENDMSG_QUEUE); + sendMsgNoDelay(MSG_DISCONNECT_BT_HEARING_AID, SENDMSG_QUEUE); } /*package*/ void postDisconnectHeadset() { - sendMsgNoDelay(MSG_DISCONNECT_HEADSET, SENDMSG_QUEUE); + sendMsgNoDelay(MSG_DISCONNECT_BT_HEADSET, SENDMSG_QUEUE); + } + + /*package*/ void postBtA2dpProfileConnected(BluetoothA2dp a2dpProfile) { + sendLMsgNoDelay(MSG_L_BT_SERVICE_CONNECTED_PROFILE_A2DP, SENDMSG_QUEUE, a2dpProfile); + } + + /*package*/ void postBtA2dpSinkProfileConnected(BluetoothProfile profile) { + sendLMsgNoDelay(MSG_L_BT_SERVICE_CONNECTED_PROFILE_A2DP_SINK, SENDMSG_QUEUE, profile); + } + + /*package*/ void postBtHeasetProfileConnected(BluetoothHeadset headsetProfile) { + sendLMsgNoDelay(MSG_L_BT_SERVICE_CONNECTED_PROFILE_HEADSET, SENDMSG_QUEUE, headsetProfile); + } + + /*package*/ void postBtHearingAidProfileConnected(BluetoothHearingAid hearingAidProfile) { + sendLMsgNoDelay(MSG_L_BT_SERVICE_CONNECTED_PROFILE_HEARING_AID, SENDMSG_QUEUE, + hearingAidProfile); } //--------------------------------------------------------------------- @@ -460,16 +479,14 @@ import java.util.ArrayList; } } + @GuardedBy("mDeviceStateLock") /*package*/ void handleSetA2dpSinkConnectionState(@BluetoothProfile.BtProfileState int state, @NonNull BtHelper.BluetoothA2dpDeviceInfo btDeviceInfo) { final int intState = (state == BluetoothA2dp.STATE_CONNECTED) ? CONNECTION_STATE_CONNECTED : CONNECTION_STATE_DISCONNECTED; - final int delay; - synchronized (mDeviceStateLock) { - delay = mDeviceInventory.checkSendBecomingNoisyIntent( + final int delay = mDeviceInventory.checkSendBecomingNoisyIntent( AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, intState, AudioSystem.DEVICE_NONE); - } final String addr = btDeviceInfo == null ? "null" : btDeviceInfo.getBtDevice().getAddress(); if (AudioService.DEBUG_DEVICES) { @@ -719,16 +736,36 @@ import java.util.ArrayList; mDeviceInventory.disconnectA2dpSink(); } break; - case MSG_DISCONNECT_HEARING_AID: + case MSG_DISCONNECT_BT_HEARING_AID: synchronized (mDeviceStateLock) { mDeviceInventory.disconnectHearingAid(); } break; - case MSG_DISCONNECT_HEADSET: + case MSG_DISCONNECT_BT_HEADSET: synchronized (mDeviceStateLock) { mBtHelper.disconnectHeadset(); } break; + case MSG_L_BT_SERVICE_CONNECTED_PROFILE_A2DP: + synchronized (mDeviceStateLock) { + mBtHelper.onA2dpProfileConnected((BluetoothA2dp) msg.obj); + } + break; + case MSG_L_BT_SERVICE_CONNECTED_PROFILE_A2DP_SINK: + synchronized (mDeviceStateLock) { + mBtHelper.onA2dpSinkProfileConnected((BluetoothProfile) msg.obj); + } + break; + case MSG_L_BT_SERVICE_CONNECTED_PROFILE_HEARING_AID: + synchronized (mDeviceStateLock) { + mBtHelper.onHearingAidProfileConnected((BluetoothHearingAid) msg.obj); + } + break; + case MSG_L_BT_SERVICE_CONNECTED_PROFILE_HEADSET: + synchronized (mDeviceStateLock) { + mBtHelper.onHeadsetProfileConnected((BluetoothHeadset) msg.obj); + } + break; default: Log.wtf(TAG, "Invalid message " + msg.what); } @@ -766,8 +803,12 @@ import java.util.ArrayList; private static final int MSG_L_A2DP_ACTIVE_DEVICE_CHANGE = 18; private static final int MSG_DISCONNECT_A2DP = 19; private static final int MSG_DISCONNECT_A2DP_SINK = 20; - private static final int MSG_DISCONNECT_HEARING_AID = 21; - private static final int MSG_DISCONNECT_HEADSET = 22; + private static final int MSG_DISCONNECT_BT_HEARING_AID = 21; + private static final int MSG_DISCONNECT_BT_HEADSET = 22; + private static final int MSG_L_BT_SERVICE_CONNECTED_PROFILE_A2DP = 23; + private static final int MSG_L_BT_SERVICE_CONNECTED_PROFILE_A2DP_SINK = 24; + private static final int MSG_L_BT_SERVICE_CONNECTED_PROFILE_HEARING_AID = 25; + private static final int MSG_L_BT_SERVICE_CONNECTED_PROFILE_HEADSET = 26; private static boolean isMessageHandledUnderWakelock(int msgId) { diff --git a/services/core/java/com/android/server/audio/BtHelper.java b/services/core/java/com/android/server/audio/BtHelper.java index e9189974e988b..58c1882abf6f9 100644 --- a/services/core/java/com/android/server/audio/BtHelper.java +++ b/services/core/java/com/android/server/audio/BtHelper.java @@ -393,6 +393,84 @@ public class BtHelper { mBluetoothHeadset = null; } + /*package*/ synchronized void onA2dpProfileConnected(BluetoothA2dp a2dp) { + mA2dp = a2dp; + final List deviceList = mA2dp.getConnectedDevices(); + if (deviceList.isEmpty()) { + return; + } + final BluetoothDevice btDevice = deviceList.get(0); + final @BluetoothProfile.BtProfileState int state = mA2dp.getConnectionState(btDevice); + mDeviceBroker.handleSetA2dpSinkConnectionState( + state, new BluetoothA2dpDeviceInfo(btDevice)); + } + + /*package*/ synchronized void onA2dpSinkProfileConnected(BluetoothProfile profile) { + final List deviceList = profile.getConnectedDevices(); + if (deviceList.isEmpty()) { + return; + } + final BluetoothDevice btDevice = deviceList.get(0); + final @BluetoothProfile.BtProfileState int state = + profile.getConnectionState(btDevice); + mDeviceBroker.postSetA2dpSourceConnectionState( + state, new BluetoothA2dpDeviceInfo(btDevice)); + } + + /*package*/ synchronized void onHearingAidProfileConnected(BluetoothHearingAid hearingAid) { + mHearingAid = hearingAid; + final List deviceList = mHearingAid.getConnectedDevices(); + if (deviceList.isEmpty()) { + return; + } + final BluetoothDevice btDevice = deviceList.get(0); + final @BluetoothProfile.BtProfileState int state = + mHearingAid.getConnectionState(btDevice); + mDeviceBroker.setBluetoothHearingAidDeviceConnectionState( + btDevice, state, + /*suppressNoisyIntent*/ false, + /*musicDevice*/ android.media.AudioSystem.DEVICE_NONE, + /*eventSource*/ "mBluetoothProfileServiceListener"); + } + + /*package*/ synchronized void onHeadsetProfileConnected(BluetoothHeadset headset) { + // Discard timeout message + mDeviceBroker.handleCancelFailureToConnectToBtHeadsetService(); + mBluetoothHeadset = headset; + setBtScoActiveDevice(mBluetoothHeadset.getActiveDevice()); + // Refresh SCO audio state + checkScoAudioState(); + if (mScoAudioState != SCO_STATE_ACTIVATE_REQ + && mScoAudioState != SCO_STATE_DEACTIVATE_REQ) { + return; + } + boolean status = false; + if (mBluetoothHeadsetDevice != null) { + switch (mScoAudioState) { + case SCO_STATE_ACTIVATE_REQ: + status = connectBluetoothScoAudioHelper( + mBluetoothHeadset, + mBluetoothHeadsetDevice, mScoAudioMode); + if (status) { + mScoAudioState = SCO_STATE_ACTIVE_INTERNAL; + } + break; + case SCO_STATE_DEACTIVATE_REQ: + status = disconnectBluetoothScoAudioHelper( + mBluetoothHeadset, + mBluetoothHeadsetDevice, mScoAudioMode); + if (status) { + mScoAudioState = SCO_STATE_DEACTIVATING; + } + break; + } + } + if (!status) { + mScoAudioState = SCO_STATE_INACTIVE; + broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED); + } + } + //---------------------------------------------------------------------- private void broadcastScoConnectionState(int state) { mDeviceBroker.postBroadcastScoConnectionState(state); @@ -462,99 +540,36 @@ public class BtHelper { } } + // NOTE this listener is NOT called from AudioDeviceBroker event thread, only call async + // methods inside listener. private BluetoothProfile.ServiceListener mBluetoothProfileServiceListener = new BluetoothProfile.ServiceListener() { public void onServiceConnected(int profile, BluetoothProfile proxy) { - final BluetoothDevice btDevice; - List deviceList; switch(profile) { case BluetoothProfile.A2DP: - synchronized (BtHelper.this) { - mA2dp = (BluetoothA2dp) proxy; - deviceList = mA2dp.getConnectedDevices(); - if (deviceList.size() > 0) { - btDevice = deviceList.get(0); - if (btDevice == null) { - Log.e(TAG, "Invalid null device in BT profile listener"); - return; - } - final @BluetoothProfile.BtProfileState int state = - mA2dp.getConnectionState(btDevice); - mDeviceBroker.handleSetA2dpSinkConnectionState( - state, new BluetoothA2dpDeviceInfo(btDevice)); - } - } + AudioService.sDeviceLogger.log(new AudioEventLogger.StringEvent( + "BT profile service: connecting A2DP profile")); + mDeviceBroker.postBtA2dpProfileConnected((BluetoothA2dp) proxy); break; case BluetoothProfile.A2DP_SINK: - deviceList = proxy.getConnectedDevices(); - if (deviceList.size() > 0) { - btDevice = deviceList.get(0); - final @BluetoothProfile.BtProfileState int state = - proxy.getConnectionState(btDevice); - mDeviceBroker.postSetA2dpSourceConnectionState( - state, new BluetoothA2dpDeviceInfo(btDevice)); - } + AudioService.sDeviceLogger.log(new AudioEventLogger.StringEvent( + "BT profile service: connecting A2DP_SINK profile")); + mDeviceBroker.postBtA2dpSinkProfileConnected(proxy); break; case BluetoothProfile.HEADSET: - synchronized (BtHelper.this) { - // Discard timeout message - mDeviceBroker.handleCancelFailureToConnectToBtHeadsetService(); - mBluetoothHeadset = (BluetoothHeadset) proxy; - setBtScoActiveDevice(mBluetoothHeadset.getActiveDevice()); - // Refresh SCO audio state - checkScoAudioState(); - // Continue pending action if any - if (mScoAudioState == SCO_STATE_ACTIVATE_REQ - || mScoAudioState == SCO_STATE_DEACTIVATE_REQ) { - boolean status = false; - if (mBluetoothHeadsetDevice != null) { - switch (mScoAudioState) { - case SCO_STATE_ACTIVATE_REQ: - status = connectBluetoothScoAudioHelper( - mBluetoothHeadset, - mBluetoothHeadsetDevice, mScoAudioMode); - if (status) { - mScoAudioState = SCO_STATE_ACTIVE_INTERNAL; - } - break; - case SCO_STATE_DEACTIVATE_REQ: - status = disconnectBluetoothScoAudioHelper( - mBluetoothHeadset, - mBluetoothHeadsetDevice, mScoAudioMode); - if (status) { - mScoAudioState = SCO_STATE_DEACTIVATING; - } - break; - } - } - if (!status) { - mScoAudioState = SCO_STATE_INACTIVE; - broadcastScoConnectionState( - AudioManager.SCO_AUDIO_STATE_DISCONNECTED); - } - } - } + AudioService.sDeviceLogger.log(new AudioEventLogger.StringEvent( + "BT profile service: connecting HEADSET profile")); + mDeviceBroker.postBtHeasetProfileConnected((BluetoothHeadset) proxy); break; case BluetoothProfile.HEARING_AID: - synchronized (BtHelper.this) { - mHearingAid = (BluetoothHearingAid) proxy; - deviceList = mHearingAid.getConnectedDevices(); - if (deviceList.size() > 0) { - btDevice = deviceList.get(0); - final @BluetoothProfile.BtProfileState int state = - mHearingAid.getConnectionState(btDevice); - mDeviceBroker.setBluetoothHearingAidDeviceConnectionState( - btDevice, state, - /*suppressNoisyIntent*/ false, - /*musicDevice*/ android.media.AudioSystem.DEVICE_NONE, - /*eventSource*/ "mBluetoothProfileServiceListener"); - } - } + AudioService.sDeviceLogger.log(new AudioEventLogger.StringEvent( + "BT profile service: connecting HEARING_AID profile")); + mDeviceBroker.postBtHearingAidProfileConnected( + (BluetoothHearingAid) proxy); break; - default: break; }