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
This commit is contained in:
Sungsoo Lim
2017-08-24 10:25:06 +09:00
parent 8d1a86ca0f
commit 76512a3d80
3 changed files with 79 additions and 43 deletions

View File

@@ -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);

View File

@@ -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;
audioRoutesChanged = 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;
}
}
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)) {

View File

@@ -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<IBinder, ClientRecord> mAllClientRecords =
new ArrayMap<IBinder, ClientRecord>();
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() {
@@ -244,6 +269,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,
@@ -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;
}
}
}
}