From 7dafa9acffbddb37bc227fcc2312f35eb2de0b1d Mon Sep 17 00:00:00 2001 From: Sungsoo Lim Date: Thu, 7 Dec 2017 20:14:24 +0900 Subject: [PATCH] Use broadcast receiver to update BT A2DP status Audio routes observer in AudioService could have several seconds delay. To mitigate the issue because of the delay, this CL uses a BroadcastReceiver to get the Bluetooth device connection events. Bug: 70175199 Test: manually and passed Media CTS Change-Id: Ic1e9db1b8d5759070962011d7f2fc4f940ce8497 --- .../server/media/MediaRouterService.java | 66 +++++++++++-------- 1 file changed, 37 insertions(+), 29 deletions(-) diff --git a/services/core/java/com/android/server/media/MediaRouterService.java b/services/core/java/com/android/server/media/MediaRouterService.java index 0b089fbc61292..384efdda88d75 100644 --- a/services/core/java/com/android/server/media/MediaRouterService.java +++ b/services/core/java/com/android/server/media/MediaRouterService.java @@ -21,6 +21,9 @@ import com.android.server.Watchdog; import android.annotation.NonNull; import android.app.ActivityManager; +import android.bluetooth.BluetoothA2dp; +import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothProfile; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; @@ -96,21 +99,23 @@ public final class MediaRouterService extends IMediaRouterService.Stub private final ArrayMap mAllClientRecords = new ArrayMap(); private int mCurrentUserId = -1; - private boolean mGlobalBluetoothA2dpOn = false; private final IAudioService mAudioService; private final AudioPlayerStateMonitor mAudioPlayerStateMonitor; private final Handler mHandler = new Handler(); - private final AudioRoutesInfo mAudioRoutesInfo = new AudioRoutesInfo(); private final IntArray mActivePlayerMinPriorityQueue = new IntArray(); private final IntArray mActivePlayerUidMinPriorityQueue = new IntArray(); + private final BroadcastReceiver mReceiver = new MediaRouterServiceBroadcastReceiver(); + BluetoothDevice mBluetoothDevice; + int mAudioRouteMainType = AudioRoutesInfo.MAIN_SPEAKER; + boolean mGlobalBluetoothA2dpOn = false; + public MediaRouterService(Context context) { mContext = context; Watchdog.getInstance().addMonitor(this); mAudioService = IAudioService.Stub.asInterface( ServiceManager.getService(Context.AUDIO_SERVICE)); - mAudioPlayerStateMonitor = AudioPlayerStateMonitor.getInstance(); mAudioPlayerStateMonitor.registerListener( new AudioPlayerStateMonitor.OnAudioPlayerActiveStateChangedListener() { @@ -170,44 +175,30 @@ public final class MediaRouterService extends IMediaRouterService.Stub @Override public void dispatchAudioRoutesChanged(final AudioRoutesInfo newRoutes) { synchronized (mLock) { - if (newRoutes.mainType != mAudioRoutesInfo.mainType) { + if (newRoutes.mainType != mAudioRouteMainType) { if ((newRoutes.mainType & (AudioRoutesInfo.MAIN_HEADSET | AudioRoutesInfo.MAIN_HEADPHONES | AudioRoutesInfo.MAIN_USB)) == 0) { // headset was plugged out. - mGlobalBluetoothA2dpOn = newRoutes.bluetoothName != null; + mGlobalBluetoothA2dpOn = mBluetoothDevice != null; } else { // headset was plugged in. mGlobalBluetoothA2dpOn = false; } - mAudioRoutesInfo.mainType = newRoutes.mainType; + mAudioRouteMainType = newRoutes.mainType; } - if (!TextUtils.equals( - newRoutes.bluetoothName, mAudioRoutesInfo.bluetoothName)) { - if (newRoutes.bluetoothName == null) { - // BT was disconnected. - mGlobalBluetoothA2dpOn = false; - } else { - // BT was connected or changed. - mGlobalBluetoothA2dpOn = true; - } - mAudioRoutesInfo.bluetoothName = newRoutes.bluetoothName; - } - // Although a Bluetooth device is connected before a new audio playback is - // started, dispatchAudioRoutChanged() can be called after - // onAudioPlayerActiveStateChanged(). That causes restoreBluetoothA2dp() - // is called before mGlobalBluetoothA2dpOn is updated. - // Calling restoreBluetoothA2dp() here could prevent that. - restoreBluetoothA2dp(); + // The new audio routes info could be delivered with several seconds delay. + // In order to avoid such delay, Bluetooth device info will be updated + // via MediaRouterServiceBroadcastReceiver. } } }); } catch (RemoteException e) { Slog.w(TAG, "RemoteException in the audio service."); } - synchronized (mLock) { - mGlobalBluetoothA2dpOn = (audioRoutes != null && audioRoutes.bluetoothName != null); - } + + IntentFilter intentFilter = new IntentFilter(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED); + context.registerReceiverAsUser(mReceiver, UserHandle.ALL, intentFilter, null, null); } public void systemRunning() { @@ -415,14 +406,12 @@ public final class MediaRouterService extends IMediaRouterService.Stub void restoreBluetoothA2dp() { try { - boolean btConnected = false; boolean a2dpOn = false; synchronized (mLock) { - btConnected = mAudioRoutesInfo.bluetoothName != null; a2dpOn = mGlobalBluetoothA2dpOn; } // We don't need to change a2dp status when bluetooth is not connected. - if (btConnected) { + if (mBluetoothDevice != null) { Slog.v(TAG, "restoreBluetoothA2dp(" + a2dpOn + ")"); mAudioService.setBluetoothA2dpOn(a2dpOn); } @@ -661,6 +650,25 @@ public final class MediaRouterService extends IMediaRouterService.Stub return false; } + final class MediaRouterServiceBroadcastReceiver extends BroadcastReceiver { + @Override + public void onReceive(Context context, Intent intent) { + if (intent.getAction().equals(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED)) { + int state = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, + BluetoothProfile.STATE_DISCONNECTED); + if (state == BluetoothProfile.STATE_DISCONNECTED) { + mGlobalBluetoothA2dpOn = false; + mBluetoothDevice = null; + } else if (state == BluetoothProfile.STATE_CONNECTED) { + mGlobalBluetoothA2dpOn = true; + mBluetoothDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); + // To ensure that BT A2DP is on, call restoreBluetoothA2dp(). + restoreBluetoothA2dp(); + } + } + } + } + /** * Information about a particular client of the media router. * The contents of this object is guarded by mLock.