From 76512a3d80dff2d32b68f3b3b6a14d4ed81ae90a Mon Sep 17 00:00:00 2001 From: Sungsoo Lim Date: Thu, 24 Aug 2017 10:25:06 +0900 Subject: [PATCH] Track the global setting of BT A2DP on/off The default phone speaker, bluetooth audio devices, and wired audio devices are handled as system audio routes. When an app starts to make sound to a system audio route, the system audio route will be selected with the following order. 1. The slected route by the app after the latest connection of an audio device. 2. The lastly connected audio device. 3. The default phone speaker if not connected. Bug: 64811580 Test: Passed MediaRouterTest, manual Change-Id: I77badb14596bc661c44237957504164f5476e595 --- media/java/android/media/IMediaRouterService.aidl | 1 + media/java/android/media/MediaRouter.java | 59 +++++++++----------- .../android/server/media/MediaRouterService.java | 64 ++++++++++++++++++---- 3 files changed, 80 insertions(+), 44 deletions(-) diff --git a/media/java/android/media/IMediaRouterService.aidl b/media/java/android/media/IMediaRouterService.aidl index 3308fc929b03..dc7fa8c00f82 100644 --- a/media/java/android/media/IMediaRouterService.aidl +++ b/media/java/android/media/IMediaRouterService.aidl @@ -28,6 +28,7 @@ interface IMediaRouterService { MediaRouterClientState getState(IMediaRouterClient client); boolean isPlaybackActive(IMediaRouterClient client); + boolean isGlobalBluetoothA2doOn(); void setDiscoveryRequest(IMediaRouterClient client, int routeTypes, boolean activeScan); void setSelectedRoute(IMediaRouterClient client, String routeId, boolean explicit); diff --git a/media/java/android/media/MediaRouter.java b/media/java/android/media/MediaRouter.java index 29b88a28294c..2894e8956c1c 100644 --- a/media/java/android/media/MediaRouter.java +++ b/media/java/android/media/MediaRouter.java @@ -88,7 +88,6 @@ public class MediaRouter { RouteInfo mBluetoothA2dpRoute; RouteInfo mSelectedRoute; - RouteInfo mSystemAudioRoute; final boolean mCanConfigureWifiDisplays; boolean mActivelyScanningWifiDisplays; @@ -150,7 +149,6 @@ public class MediaRouter { } addRouteStatic(mDefaultAudioVideo); - mSystemAudioRoute = mDefaultAudioVideo; // This will select the active wifi display route if there is one. updateWifiDisplayStatus(mDisplayService.getWifiDisplayStatus()); @@ -185,7 +183,7 @@ public class MediaRouter { } void updateAudioRoutes(AudioRoutesInfo newRoutes) { - boolean updated = false; + boolean audioRoutesChanged = false; if (newRoutes.mainType != mCurAudioRoutesInfo.mainType) { mCurAudioRoutesInfo.mainType = newRoutes.mainType; int name; @@ -201,11 +199,10 @@ public class MediaRouter { } mDefaultAudioVideo.mNameResId = name; dispatchRouteChanged(mDefaultAudioVideo); - updated = true; + audioRoutesChanged = true; } final int mainType = mCurAudioRoutesInfo.mainType; - if (!TextUtils.equals(newRoutes.bluetoothName, mCurAudioRoutesInfo.bluetoothName)) { mCurAudioRoutesInfo.bluetoothName = newRoutes.bluetoothName; if (mCurAudioRoutesInfo.bluetoothName != null) { @@ -219,8 +216,6 @@ public class MediaRouter { info.mDeviceType = RouteInfo.DEVICE_TYPE_BLUETOOTH; mBluetoothA2dpRoute = info; addRouteStatic(mBluetoothA2dpRoute); - mSystemAudioRoute = mBluetoothA2dpRoute; - selectRouteStatic(ROUTE_TYPE_LIVE_AUDIO, mSystemAudioRoute, false); } else { mBluetoothA2dpRoute.mName = mCurAudioRoutesInfo.bluetoothName; dispatchRouteChanged(mBluetoothA2dpRoute); @@ -229,30 +224,32 @@ public class MediaRouter { // BT disconnected removeRouteStatic(mBluetoothA2dpRoute); mBluetoothA2dpRoute = null; - mSystemAudioRoute = mDefaultAudioVideo; - selectRouteStatic(ROUTE_TYPE_LIVE_AUDIO, mSystemAudioRoute, false); - } - updated = true; - } - - if (mBluetoothA2dpRoute != null) { - final boolean a2dpEnabled = isBluetoothA2dpOn(); - if (mSelectedRoute == mBluetoothA2dpRoute && !a2dpEnabled) { - // A2DP off - mSystemAudioRoute = mDefaultAudioVideo; - updated = true; - } else if ((mSelectedRoute == mDefaultAudioVideo || mSelectedRoute == null) && - a2dpEnabled) { - // A2DP on or BT connected - mSystemAudioRoute = mBluetoothA2dpRoute; - updated = true; } + audioRoutesChanged = true; } - if (updated) { + + if (audioRoutesChanged) { + selectRouteStatic(ROUTE_TYPE_LIVE_AUDIO, getDefaultSystemAudioRoute(), false); Log.v(TAG, "Audio routes updated: " + newRoutes + ", a2dp=" + isBluetoothA2dpOn()); } } + RouteInfo getDefaultSystemAudioRoute() { + boolean globalBluetoothA2doOn = false; + try { + globalBluetoothA2doOn = mMediaRouterService.isGlobalBluetoothA2doOn(); + } catch (RemoteException ex) { + Log.e(TAG, "Unable to call isSystemBluetoothA2doOn.", ex); + } + return (globalBluetoothA2doOn && mBluetoothA2dpRoute != null) + ? mBluetoothA2dpRoute : mDefaultAudioVideo; + } + + RouteInfo getCurrentSystemAudioRoute() { + return (isBluetoothA2dpOn() && mBluetoothA2dpRoute != null) + ? mBluetoothA2dpRoute : mDefaultAudioVideo; + } + boolean isBluetoothA2dpOn() { try { return mAudioService.isBluetoothA2dpOn(); @@ -603,15 +600,13 @@ public class MediaRouter { @Override public void onRestoreRoute() { + // Skip restoring route if the selected route is not a system audio route, or + // MediaRouter is initializing. if ((mSelectedRoute != mDefaultAudioVideo && mSelectedRoute != mBluetoothA2dpRoute) - || mSelectedRoute == mSystemAudioRoute) { + || mSelectedRoute == null) { return; } - try { - sStatic.mAudioService.setBluetoothA2dpOn(mSelectedRoute == mBluetoothA2dpRoute); - } catch (RemoteException e) { - Log.e(TAG, "Error changing Bluetooth A2DP state", e); - } + mSelectedRoute.select(); } } } @@ -946,7 +941,7 @@ public class MediaRouter { boolean wasDefaultOrBluetoothRoute = (oldRoute == sStatic.mDefaultAudioVideo || oldRoute == sStatic.mBluetoothA2dpRoute); if (oldRoute == route - && (!wasDefaultOrBluetoothRoute || oldRoute == sStatic.mSystemAudioRoute)) { + && (!wasDefaultOrBluetoothRoute || route == sStatic.getCurrentSystemAudioRoute())) { return; } if (!route.matchesTypes(types)) { diff --git a/services/core/java/com/android/server/media/MediaRouterService.java b/services/core/java/com/android/server/media/MediaRouterService.java index 922df1e3dba8..3795b7f3091c 100644 --- a/services/core/java/com/android/server/media/MediaRouterService.java +++ b/services/core/java/com/android/server/media/MediaRouterService.java @@ -18,9 +18,7 @@ package com.android.server.media; import com.android.internal.util.DumpUtils; import com.android.server.Watchdog; -import com.android.server.media.AudioPlaybackMonitor.OnAudioPlayerActiveStateChangedListener; -import android.Manifest; import android.app.ActivityManager; import android.content.BroadcastReceiver; import android.content.Context; @@ -96,9 +94,10 @@ public final class MediaRouterService extends IMediaRouterService.Stub private final ArrayMap mAllClientRecords = new ArrayMap(); private int mCurrentUserId = -1; - private boolean mHasBluetoothRoute = false; + private boolean mGlobalBluetoothA2dpOn = false; private final IAudioService mAudioService; private final AudioPlaybackMonitor mAudioPlaybackMonitor; + private final AudioRoutesInfo mCurAudioRoutesInfo = new AudioRoutesInfo(); public MediaRouterService(Context context) { mContext = context; @@ -137,13 +136,39 @@ public final class MediaRouterService extends IMediaRouterService.Stub audioRoutes = mAudioService.startWatchingRoutes(new IAudioRoutesObserver.Stub() { @Override public void dispatchAudioRoutesChanged(final AudioRoutesInfo newRoutes) { - mHasBluetoothRoute = newRoutes.bluetoothName != null; + synchronized (mLock) { + if (newRoutes.mainType != mCurAudioRoutesInfo.mainType) { + if ((newRoutes.mainType & (AudioRoutesInfo.MAIN_HEADSET + | AudioRoutesInfo.MAIN_HEADPHONES + | AudioRoutesInfo.MAIN_USB)) == 0) { + // headset was plugged out. + mGlobalBluetoothA2dpOn = newRoutes.bluetoothName != null; + } else { + // headset was plugged in. + mGlobalBluetoothA2dpOn = false; + } + mCurAudioRoutesInfo.mainType = newRoutes.mainType; + } + if (!TextUtils.equals( + newRoutes.bluetoothName, mCurAudioRoutesInfo.bluetoothName)) { + if (newRoutes.bluetoothName == null) { + // BT was disconnected. + mGlobalBluetoothA2dpOn = false; + } else { + // BT was connected or changed. + mGlobalBluetoothA2dpOn = true; + } + mCurAudioRoutesInfo.bluetoothName = newRoutes.bluetoothName; + } + } } }); } catch (RemoteException e) { Slog.w(TAG, "RemoteException in the audio service."); } - mHasBluetoothRoute = (audioRoutes != null && audioRoutes.bluetoothName != null); + synchronized (mLock) { + mGlobalBluetoothA2dpOn = (audioRoutes != null && audioRoutes.bluetoothName != null); + } } public void systemRunning() { @@ -246,6 +271,14 @@ public final class MediaRouterService extends IMediaRouterService.Stub // Binder call @Override + public boolean isGlobalBluetoothA2doOn() { + synchronized (mLock) { + return mGlobalBluetoothA2dpOn; + } + } + + // Binder call + @Override public void setDiscoveryRequest(IMediaRouterClient client, int routeTypes, boolean activeScan) { if (client == null) { @@ -346,7 +379,12 @@ public final class MediaRouterService extends IMediaRouterService.Stub void restoreBluetoothA2dp() { try { - mAudioService.setBluetoothA2dpOn(mHasBluetoothRoute); + boolean a2dpOn = false; + synchronized (mLock) { + a2dpOn = mGlobalBluetoothA2dpOn; + } + Slog.v(TAG, "restoreBluetoothA2dp( " + a2dpOn + ")"); + mAudioService.setBluetoothA2dpOn(a2dpOn); } catch (RemoteException e) { Slog.w(TAG, "RemoteException while calling setBluetoothA2dpOn."); } @@ -354,12 +392,14 @@ public final class MediaRouterService extends IMediaRouterService.Stub void restoreRoute(int uid) { ClientRecord clientRecord = null; - UserRecord userRecord = mUserRecords.get(UserHandle.getUserId(uid)); - if (userRecord != null && userRecord.mClientRecords != null) { - for (ClientRecord cr : userRecord.mClientRecords) { - if (validatePackageName(uid, cr.mPackageName)) { - clientRecord = cr; - break; + synchronized (mLock) { + UserRecord userRecord = mUserRecords.get(UserHandle.getUserId(uid)); + if (userRecord != null && userRecord.mClientRecords != null) { + for (ClientRecord cr : userRecord.mClientRecords) { + if (validatePackageName(uid, cr.mPackageName)) { + clientRecord = cr; + break; + } } } } -- 2.11.0