Merge "Restore the selected route when an app starts to make sound"
This commit is contained in:
@@ -21,4 +21,5 @@ package android.media;
|
||||
*/
|
||||
oneway interface IMediaRouterClient {
|
||||
void onStateChanged();
|
||||
void onRestoreRoute();
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ interface IMediaRouterService {
|
||||
void unregisterClient(IMediaRouterClient client);
|
||||
|
||||
MediaRouterClientState getState(IMediaRouterClient client);
|
||||
boolean isPlaybackActive(IMediaRouterClient client);
|
||||
|
||||
void setDiscoveryRequest(IMediaRouterClient client, int routeTypes, boolean activeScan);
|
||||
void setSelectedRoute(IMediaRouterClient client, String routeId, boolean explicit);
|
||||
|
||||
@@ -88,6 +88,7 @@ public class MediaRouter {
|
||||
RouteInfo mBluetoothA2dpRoute;
|
||||
|
||||
RouteInfo mSelectedRoute;
|
||||
RouteInfo mSystemAudioRoute;
|
||||
|
||||
final boolean mCanConfigureWifiDisplays;
|
||||
boolean mActivelyScanningWifiDisplays;
|
||||
@@ -149,6 +150,7 @@ public class MediaRouter {
|
||||
}
|
||||
|
||||
addRouteStatic(mDefaultAudioVideo);
|
||||
mSystemAudioRoute = mDefaultAudioVideo;
|
||||
|
||||
// This will select the active wifi display route if there is one.
|
||||
updateWifiDisplayStatus(mDisplayService.getWifiDisplayStatus());
|
||||
@@ -197,8 +199,8 @@ public class MediaRouter {
|
||||
} else {
|
||||
name = com.android.internal.R.string.default_audio_route_name;
|
||||
}
|
||||
sStatic.mDefaultAudioVideo.mNameResId = name;
|
||||
dispatchRouteChanged(sStatic.mDefaultAudioVideo);
|
||||
mDefaultAudioVideo.mNameResId = name;
|
||||
dispatchRouteChanged(mDefaultAudioVideo);
|
||||
updated = true;
|
||||
}
|
||||
|
||||
@@ -207,22 +209,28 @@ public class MediaRouter {
|
||||
if (!TextUtils.equals(newRoutes.bluetoothName, mCurAudioRoutesInfo.bluetoothName)) {
|
||||
mCurAudioRoutesInfo.bluetoothName = newRoutes.bluetoothName;
|
||||
if (mCurAudioRoutesInfo.bluetoothName != null) {
|
||||
if (sStatic.mBluetoothA2dpRoute == null) {
|
||||
final RouteInfo info = new RouteInfo(sStatic.mSystemCategory);
|
||||
if (mBluetoothA2dpRoute == null) {
|
||||
// BT connected
|
||||
final RouteInfo info = new RouteInfo(mSystemCategory);
|
||||
info.mName = mCurAudioRoutesInfo.bluetoothName;
|
||||
info.mDescription = sStatic.mResources.getText(
|
||||
info.mDescription = mResources.getText(
|
||||
com.android.internal.R.string.bluetooth_a2dp_audio_route_name);
|
||||
info.mSupportedTypes = ROUTE_TYPE_LIVE_AUDIO;
|
||||
info.mDeviceType = RouteInfo.DEVICE_TYPE_BLUETOOTH;
|
||||
sStatic.mBluetoothA2dpRoute = info;
|
||||
addRouteStatic(sStatic.mBluetoothA2dpRoute);
|
||||
mBluetoothA2dpRoute = info;
|
||||
addRouteStatic(mBluetoothA2dpRoute);
|
||||
mSystemAudioRoute = mBluetoothA2dpRoute;
|
||||
selectRouteStatic(ROUTE_TYPE_LIVE_AUDIO, mSystemAudioRoute, false);
|
||||
} else {
|
||||
sStatic.mBluetoothA2dpRoute.mName = mCurAudioRoutesInfo.bluetoothName;
|
||||
dispatchRouteChanged(sStatic.mBluetoothA2dpRoute);
|
||||
mBluetoothA2dpRoute.mName = mCurAudioRoutesInfo.bluetoothName;
|
||||
dispatchRouteChanged(mBluetoothA2dpRoute);
|
||||
}
|
||||
} else if (sStatic.mBluetoothA2dpRoute != null) {
|
||||
removeRouteStatic(sStatic.mBluetoothA2dpRoute);
|
||||
sStatic.mBluetoothA2dpRoute = null;
|
||||
} else if (mBluetoothA2dpRoute != null) {
|
||||
// BT disconnected
|
||||
removeRouteStatic(mBluetoothA2dpRoute);
|
||||
mBluetoothA2dpRoute = null;
|
||||
mSystemAudioRoute = mDefaultAudioVideo;
|
||||
selectRouteStatic(ROUTE_TYPE_LIVE_AUDIO, mSystemAudioRoute, false);
|
||||
}
|
||||
updated = true;
|
||||
}
|
||||
@@ -230,11 +238,13 @@ public class MediaRouter {
|
||||
if (mBluetoothA2dpRoute != null) {
|
||||
final boolean a2dpEnabled = isBluetoothA2dpOn();
|
||||
if (mSelectedRoute == mBluetoothA2dpRoute && !a2dpEnabled) {
|
||||
selectRouteStatic(ROUTE_TYPE_LIVE_AUDIO, mDefaultAudioVideo, false);
|
||||
// A2DP off
|
||||
mSystemAudioRoute = mDefaultAudioVideo;
|
||||
updated = true;
|
||||
} else if ((mSelectedRoute == mDefaultAudioVideo || mSelectedRoute == null) &&
|
||||
a2dpEnabled) {
|
||||
selectRouteStatic(ROUTE_TYPE_LIVE_AUDIO, mBluetoothA2dpRoute, false);
|
||||
// A2DP on or BT connected
|
||||
mSystemAudioRoute = mBluetoothA2dpRoute;
|
||||
updated = true;
|
||||
}
|
||||
}
|
||||
@@ -471,7 +481,7 @@ public class MediaRouter {
|
||||
}
|
||||
|
||||
RouteInfo makeGlobalRoute(MediaRouterClientState.RouteInfo globalRoute) {
|
||||
RouteInfo route = new RouteInfo(sStatic.mSystemCategory);
|
||||
RouteInfo route = new RouteInfo(mSystemCategory);
|
||||
route.mGlobalRouteId = globalRoute.id;
|
||||
route.mName = globalRoute.name;
|
||||
route.mDescription = globalRoute.description;
|
||||
@@ -567,6 +577,17 @@ public class MediaRouter {
|
||||
return null;
|
||||
}
|
||||
|
||||
boolean isPlaybackActive() {
|
||||
if (mClient != null) {
|
||||
try {
|
||||
return mMediaRouterService.isPlaybackActive(mClient);
|
||||
} catch (RemoteException ex) {
|
||||
Log.e(TAG, "Unable to retrieve playback active state.", ex);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
final class Client extends IMediaRouterClient.Stub {
|
||||
@Override
|
||||
public void onStateChanged() {
|
||||
@@ -579,6 +600,19 @@ public class MediaRouter {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRestoreRoute() {
|
||||
if ((mSelectedRoute != mDefaultAudioVideo && mSelectedRoute != mBluetoothA2dpRoute)
|
||||
|| mSelectedRoute == mSystemAudioRoute) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
sStatic.mAudioService.setBluetoothA2dpOn(mSelectedRoute == mBluetoothA2dpRoute);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Error changing Bluetooth A2DP state", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -900,7 +934,12 @@ public class MediaRouter {
|
||||
Log.v(TAG, "Selecting route: " + route);
|
||||
assert(route != null);
|
||||
final RouteInfo oldRoute = sStatic.mSelectedRoute;
|
||||
if (oldRoute == route) return;
|
||||
boolean wasDefaultOrBluetoothRoute = (oldRoute == sStatic.mDefaultAudioVideo
|
||||
|| oldRoute == sStatic.mBluetoothA2dpRoute);
|
||||
if (oldRoute == route
|
||||
&& (!wasDefaultOrBluetoothRoute || oldRoute == sStatic.mSystemAudioRoute)) {
|
||||
return;
|
||||
}
|
||||
if (!route.matchesTypes(types)) {
|
||||
Log.w(TAG, "selectRoute ignored; cannot select route with supported types " +
|
||||
typesToString(route.getSupportedTypes()) + " into route types " +
|
||||
@@ -909,8 +948,8 @@ public class MediaRouter {
|
||||
}
|
||||
|
||||
final RouteInfo btRoute = sStatic.mBluetoothA2dpRoute;
|
||||
if (btRoute != null && (types & ROUTE_TYPE_LIVE_AUDIO) != 0 &&
|
||||
(route == btRoute || route == sStatic.mDefaultAudioVideo)) {
|
||||
if (sStatic.isPlaybackActive() && btRoute != null && (types & ROUTE_TYPE_LIVE_AUDIO) != 0
|
||||
&& (route == btRoute || route == sStatic.mDefaultAudioVideo)) {
|
||||
try {
|
||||
sStatic.mAudioService.setBluetoothA2dpOn(route == btRoute);
|
||||
} catch (RemoteException e) {
|
||||
|
||||
@@ -31,17 +31,22 @@ import android.util.SparseArray;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Monitors changes in audio playback and notify the newly started audio playback through the
|
||||
* {@link OnAudioPlaybackStartedListener}.
|
||||
* Monitors changes in audio playback, and notify the newly started audio playback through the
|
||||
* {@link OnAudioPlaybackStartedListener} and the activeness change through the
|
||||
* {@link OnAudioPlaybackActiveStateListener}.
|
||||
*/
|
||||
class AudioPlaybackMonitor extends IPlaybackConfigDispatcher.Stub {
|
||||
private static boolean DEBUG = MediaSessionService.DEBUG;
|
||||
private static String TAG = "AudioPlaybackMonitor";
|
||||
|
||||
private static AudioPlaybackMonitor sInstance;
|
||||
|
||||
/**
|
||||
* Called when audio playback is started for a given UID.
|
||||
*/
|
||||
@@ -49,22 +54,36 @@ class AudioPlaybackMonitor extends IPlaybackConfigDispatcher.Stub {
|
||||
void onAudioPlaybackStarted(int uid);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when audio player state is changed.
|
||||
*/
|
||||
interface OnAudioPlayerActiveStateChangedListener {
|
||||
void onAudioPlayerActiveStateChanged(int uid, boolean active);
|
||||
}
|
||||
|
||||
private final Object mLock = new Object();
|
||||
private final Context mContext;
|
||||
private final OnAudioPlaybackStartedListener mListener;
|
||||
|
||||
private Set<Integer> mActiveAudioPlaybackPlayerInterfaceIds = new HashSet<>();
|
||||
private Set<Integer> mActiveAudioPlaybackClientUids = new HashSet<>();
|
||||
private final List<OnAudioPlaybackStartedListener> mAudioPlaybackStartedListeners
|
||||
= new ArrayList<>();
|
||||
private final List<OnAudioPlayerActiveStateChangedListener>
|
||||
mAudioPlayerActiveStateChangedListeners = new ArrayList<>();
|
||||
private final Map<Integer, Integer> mAudioPlaybackStates = new HashMap<>();
|
||||
private final Set<Integer> mActiveAudioPlaybackClientUids = new HashSet<>();
|
||||
|
||||
// Sorted array of UIDs that had active audio playback. (i.e. playing an audio/video)
|
||||
// The UID whose audio playback becomes active at the last comes first.
|
||||
// TODO(b/35278867): Find and use unique identifier for apps because apps may share the UID.
|
||||
private final IntArray mSortedAudioPlaybackClientUids = new IntArray();
|
||||
|
||||
AudioPlaybackMonitor(Context context, IAudioService audioService,
|
||||
OnAudioPlaybackStartedListener listener) {
|
||||
static AudioPlaybackMonitor getInstance(Context context, IAudioService audioService) {
|
||||
if (sInstance == null) {
|
||||
sInstance = new AudioPlaybackMonitor(context, audioService);
|
||||
}
|
||||
return sInstance;
|
||||
}
|
||||
|
||||
private AudioPlaybackMonitor(Context context, IAudioService audioService) {
|
||||
mContext = context;
|
||||
mListener = listener;
|
||||
try {
|
||||
audioService.registerPlaybackCallback(this);
|
||||
} catch (RemoteException e) {
|
||||
@@ -84,9 +103,12 @@ class AudioPlaybackMonitor extends IPlaybackConfigDispatcher.Stub {
|
||||
public void dispatchPlaybackConfigChange(List<AudioPlaybackConfiguration> configs) {
|
||||
final long token = Binder.clearCallingIdentity();
|
||||
try {
|
||||
Set<Integer> newActiveAudioPlaybackPlayerInterfaceIds = new HashSet<>();
|
||||
List<Integer> newActiveAudioPlaybackClientUids = new ArrayList<>();
|
||||
List<OnAudioPlayerActiveStateChangedListener> audioPlayerActiveStateChangedListeners;
|
||||
List<OnAudioPlaybackStartedListener> audioPlaybackStartedListeners;
|
||||
synchronized (mLock) {
|
||||
// Update mActiveAudioPlaybackClientUids and mSortedAudioPlaybackClientUids,
|
||||
// and find newly activated audio playbacks.
|
||||
mActiveAudioPlaybackClientUids.clear();
|
||||
for (AudioPlaybackConfiguration config : configs) {
|
||||
// Ignore inactive (i.e. not playing) or PLAYER_TYPE_JAM_SOUNDPOOL
|
||||
@@ -94,16 +116,14 @@ class AudioPlaybackMonitor extends IPlaybackConfigDispatcher.Stub {
|
||||
// playback.
|
||||
// Note that we shouldn't ignore PLAYER_TYPE_UNKNOWN because it might be OEM
|
||||
// specific audio/video players.
|
||||
if (!config.isActive()
|
||||
|| config.getPlayerType()
|
||||
if (!config.isActive() || config.getPlayerType()
|
||||
== AudioPlaybackConfiguration.PLAYER_TYPE_JAM_SOUNDPOOL) {
|
||||
continue;
|
||||
}
|
||||
mActiveAudioPlaybackClientUids.add(config.getClientUid());
|
||||
|
||||
newActiveAudioPlaybackPlayerInterfaceIds.add(config.getPlayerInterfaceId());
|
||||
if (!mActiveAudioPlaybackPlayerInterfaceIds.contains(
|
||||
config.getPlayerInterfaceId())) {
|
||||
mActiveAudioPlaybackClientUids.add(config.getClientUid());
|
||||
Integer oldState = mAudioPlaybackStates.get(config.getPlayerInterfaceId());
|
||||
if (!isActiveState(oldState)) {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "Found a new active media playback. " +
|
||||
AudioPlaybackConfiguration.toLogFriendlyString(config));
|
||||
@@ -120,17 +140,76 @@ class AudioPlaybackMonitor extends IPlaybackConfigDispatcher.Stub {
|
||||
mSortedAudioPlaybackClientUids.add(0, config.getClientUid());
|
||||
}
|
||||
}
|
||||
mActiveAudioPlaybackPlayerInterfaceIds.clear();
|
||||
mActiveAudioPlaybackPlayerInterfaceIds = newActiveAudioPlaybackPlayerInterfaceIds;
|
||||
audioPlayerActiveStateChangedListeners = new ArrayList<>(
|
||||
mAudioPlayerActiveStateChangedListeners);
|
||||
audioPlaybackStartedListeners = new ArrayList<>(mAudioPlaybackStartedListeners);
|
||||
}
|
||||
// Notify the change of audio playback states.
|
||||
for (AudioPlaybackConfiguration config : configs) {
|
||||
boolean wasActive = isActiveState(
|
||||
mAudioPlaybackStates.get(config.getPlayerInterfaceId()));
|
||||
boolean isActive = config.isActive();
|
||||
if (wasActive != isActive) {
|
||||
for (OnAudioPlayerActiveStateChangedListener listener
|
||||
: audioPlayerActiveStateChangedListeners) {
|
||||
listener.onAudioPlayerActiveStateChanged(config.getClientUid(),
|
||||
isActive);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Notify the start of audio playback
|
||||
for (int uid : newActiveAudioPlaybackClientUids) {
|
||||
mListener.onAudioPlaybackStarted(uid);
|
||||
for (OnAudioPlaybackStartedListener listener : audioPlaybackStartedListeners) {
|
||||
listener.onAudioPlaybackStarted(uid);
|
||||
}
|
||||
}
|
||||
mAudioPlaybackStates.clear();
|
||||
for (AudioPlaybackConfiguration config : configs) {
|
||||
mAudioPlaybackStates.put(config.getPlayerInterfaceId(), config.getPlayerState());
|
||||
}
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(token);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers OnAudioPlaybackStartedListener.
|
||||
*/
|
||||
public void registerOnAudioPlaybackStartedListener(OnAudioPlaybackStartedListener listener) {
|
||||
synchronized (mLock) {
|
||||
mAudioPlaybackStartedListeners.add(listener);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregisters OnAudioPlaybackStartedListener.
|
||||
*/
|
||||
public void unregisterOnAudioPlaybackStartedListener(OnAudioPlaybackStartedListener listener) {
|
||||
synchronized (mLock) {
|
||||
mAudioPlaybackStartedListeners.remove(listener);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers OnAudioPlayerActiveStateChangedListener.
|
||||
*/
|
||||
public void registerOnAudioPlayerActiveStateChangedListener(
|
||||
OnAudioPlayerActiveStateChangedListener listener) {
|
||||
synchronized (mLock) {
|
||||
mAudioPlayerActiveStateChangedListeners.add(listener);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregisters OnAudioPlayerActiveStateChangedListener.
|
||||
*/
|
||||
public void unregisterOnAudioPlayerActiveStateChangedListener(
|
||||
OnAudioPlayerActiveStateChangedListener listener) {
|
||||
synchronized (mLock) {
|
||||
mAudioPlayerActiveStateChangedListeners.remove(listener);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the sorted list of UIDs that have had active audio playback. (i.e. playing an
|
||||
* audio/video) The UID whose audio playback becomes active at the last comes first.
|
||||
@@ -167,7 +246,8 @@ class AudioPlaybackMonitor extends IPlaybackConfigDispatcher.Stub {
|
||||
if (mSortedAudioPlaybackClientUids.get(i) == mediaButtonSessionUid) {
|
||||
break;
|
||||
}
|
||||
if (userId == UserHandle.getUserId(mSortedAudioPlaybackClientUids.get(i))) {
|
||||
int uid = mSortedAudioPlaybackClientUids.get(i);
|
||||
if (userId == UserHandle.getUserId(uid) && !isPlaybackActive(uid)) {
|
||||
// Clean up unnecessary UIDs.
|
||||
// It doesn't need to be managed profile aware because it's just to prevent
|
||||
// the list from increasing indefinitely. The media button session updating
|
||||
@@ -198,4 +278,8 @@ class AudioPlaybackMonitor extends IPlaybackConfigDispatcher.Stub {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isActiveState(Integer state) {
|
||||
return state != null && state.equals(AudioPlaybackConfiguration.PLAYER_STATE_STARTED);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +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;
|
||||
@@ -26,7 +27,10 @@ import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.media.AudioRoutesInfo;
|
||||
import android.media.AudioSystem;
|
||||
import android.media.IAudioRoutesObserver;
|
||||
import android.media.IAudioService;
|
||||
import android.media.IMediaRouterClient;
|
||||
import android.media.IMediaRouterService;
|
||||
import android.media.MediaRouter;
|
||||
@@ -39,9 +43,12 @@ import android.os.IBinder;
|
||||
import android.os.Looper;
|
||||
import android.os.Message;
|
||||
import android.os.RemoteException;
|
||||
import android.os.ServiceManager;
|
||||
import android.os.SystemClock;
|
||||
import android.os.UserHandle;
|
||||
import android.text.TextUtils;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.IntArray;
|
||||
import android.util.Log;
|
||||
import android.util.Slog;
|
||||
import android.util.SparseArray;
|
||||
@@ -89,10 +96,54 @@ 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 final IAudioService mAudioService;
|
||||
private final AudioPlaybackMonitor mAudioPlaybackMonitor;
|
||||
|
||||
public MediaRouterService(Context context) {
|
||||
mContext = context;
|
||||
Watchdog.getInstance().addMonitor(this);
|
||||
|
||||
mAudioService = IAudioService.Stub.asInterface(
|
||||
ServiceManager.getService(Context.AUDIO_SERVICE));
|
||||
|
||||
mAudioPlaybackMonitor = AudioPlaybackMonitor.getInstance(context, mAudioService);
|
||||
mAudioPlaybackMonitor.registerOnAudioPlayerActiveStateChangedListener(
|
||||
new AudioPlaybackMonitor.OnAudioPlayerActiveStateChangedListener() {
|
||||
@Override
|
||||
public void onAudioPlayerActiveStateChanged(int uid, boolean active) {
|
||||
if (active) {
|
||||
restoreRoute(uid);
|
||||
} else {
|
||||
IntArray sortedAudioPlaybackClientUids =
|
||||
mAudioPlaybackMonitor.getSortedAudioPlaybackClientUids();
|
||||
boolean restored = false;
|
||||
for (int i = 0; i < sortedAudioPlaybackClientUids.size(); i++) {
|
||||
if (mAudioPlaybackMonitor.isPlaybackActive(
|
||||
sortedAudioPlaybackClientUids.get(i))) {
|
||||
restoreRoute(sortedAudioPlaybackClientUids.get(i));
|
||||
restored = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!restored) {
|
||||
restoreBluetoothA2dp();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
AudioRoutesInfo audioRoutes = null;
|
||||
try {
|
||||
audioRoutes = mAudioService.startWatchingRoutes(new IAudioRoutesObserver.Stub() {
|
||||
@Override
|
||||
public void dispatchAudioRoutesChanged(final AudioRoutesInfo newRoutes) {
|
||||
mHasBluetoothRoute = newRoutes.bluetoothName != null;
|
||||
}
|
||||
});
|
||||
} catch (RemoteException e) {
|
||||
Slog.w(TAG, "RemoteException in the audio service.");
|
||||
}
|
||||
mHasBluetoothRoute = (audioRoutes != null && audioRoutes.bluetoothName != null);
|
||||
}
|
||||
|
||||
public void systemRunning() {
|
||||
@@ -135,7 +186,7 @@ public final class MediaRouterService extends IMediaRouterService.Stub
|
||||
final long token = Binder.clearCallingIdentity();
|
||||
try {
|
||||
synchronized (mLock) {
|
||||
registerClientLocked(client, pid, packageName, resolvedUserId, trusted);
|
||||
registerClientLocked(client, uid, pid, packageName, resolvedUserId, trusted);
|
||||
}
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(token);
|
||||
@@ -176,6 +227,23 @@ public final class MediaRouterService extends IMediaRouterService.Stub
|
||||
}
|
||||
}
|
||||
|
||||
// Binder call
|
||||
@Override
|
||||
public boolean isPlaybackActive(IMediaRouterClient client) {
|
||||
if (client == null) {
|
||||
throw new IllegalArgumentException("client must not be null");
|
||||
}
|
||||
|
||||
final long token = Binder.clearCallingIdentity();
|
||||
try {
|
||||
synchronized (mLock) {
|
||||
return isPlaybackActiveLocked(client);
|
||||
}
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(token);
|
||||
}
|
||||
}
|
||||
|
||||
// Binder call
|
||||
@Override
|
||||
public void setDiscoveryRequest(IMediaRouterClient client,
|
||||
@@ -276,6 +344,36 @@ public final class MediaRouterService extends IMediaRouterService.Stub
|
||||
}
|
||||
}
|
||||
|
||||
void restoreBluetoothA2dp() {
|
||||
try {
|
||||
mAudioService.setBluetoothA2dpOn(mHasBluetoothRoute);
|
||||
} catch (RemoteException e) {
|
||||
Slog.w(TAG, "RemoteException while calling setBluetoothA2dpOn.");
|
||||
}
|
||||
}
|
||||
|
||||
void restoreRoute(int uid) {
|
||||
ClientRecord clientRecord = null;
|
||||
UserRecord userRecord = mUserRecords.get(UserHandle.getUserId(uid));
|
||||
if (userRecord.mClientRecords != null) {
|
||||
for (ClientRecord cr : userRecord.mClientRecords) {
|
||||
if (validatePackageName(uid, cr.mPackageName)) {
|
||||
clientRecord = cr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (clientRecord != null) {
|
||||
try {
|
||||
clientRecord.mClient.onRestoreRoute();
|
||||
} catch (RemoteException e) {
|
||||
Slog.w(TAG, "Failed to call onRestoreRoute. Client probably died.");
|
||||
}
|
||||
} else {
|
||||
restoreBluetoothA2dp();
|
||||
}
|
||||
}
|
||||
|
||||
void switchUser() {
|
||||
synchronized (mLock) {
|
||||
int userId = ActivityManager.getCurrentUser();
|
||||
@@ -304,7 +402,7 @@ public final class MediaRouterService extends IMediaRouterService.Stub
|
||||
}
|
||||
|
||||
private void registerClientLocked(IMediaRouterClient client,
|
||||
int pid, String packageName, int userId, boolean trusted) {
|
||||
int uid, int pid, String packageName, int userId, boolean trusted) {
|
||||
final IBinder binder = client.asBinder();
|
||||
ClientRecord clientRecord = mAllClientRecords.get(binder);
|
||||
if (clientRecord == null) {
|
||||
@@ -314,7 +412,7 @@ public final class MediaRouterService extends IMediaRouterService.Stub
|
||||
userRecord = new UserRecord(userId);
|
||||
newUser = true;
|
||||
}
|
||||
clientRecord = new ClientRecord(userRecord, client, pid, packageName, trusted);
|
||||
clientRecord = new ClientRecord(userRecord, client, uid, pid, packageName, trusted);
|
||||
try {
|
||||
binder.linkToDeath(clientRecord, 0);
|
||||
} catch (RemoteException ex) {
|
||||
@@ -350,6 +448,14 @@ public final class MediaRouterService extends IMediaRouterService.Stub
|
||||
return null;
|
||||
}
|
||||
|
||||
private boolean isPlaybackActiveLocked(IMediaRouterClient client) {
|
||||
ClientRecord clientRecord = mAllClientRecords.get(client.asBinder());
|
||||
if (clientRecord != null) {
|
||||
return mAudioPlaybackMonitor.isPlaybackActive(clientRecord.mUid);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void setDiscoveryRequestLocked(IMediaRouterClient client,
|
||||
int routeTypes, boolean activeScan) {
|
||||
final IBinder binder = client.asBinder();
|
||||
@@ -489,6 +595,7 @@ public final class MediaRouterService extends IMediaRouterService.Stub
|
||||
final class ClientRecord implements DeathRecipient {
|
||||
public final UserRecord mUserRecord;
|
||||
public final IMediaRouterClient mClient;
|
||||
public final int mUid;
|
||||
public final int mPid;
|
||||
public final String mPackageName;
|
||||
public final boolean mTrusted;
|
||||
@@ -498,9 +605,10 @@ public final class MediaRouterService extends IMediaRouterService.Stub
|
||||
public String mSelectedRouteId;
|
||||
|
||||
public ClientRecord(UserRecord userRecord, IMediaRouterClient client,
|
||||
int pid, String packageName, boolean trusted) {
|
||||
int uid, int pid, String packageName, boolean trusted) {
|
||||
mUserRecord = userRecord;
|
||||
mClient = client;
|
||||
mUid = uid;
|
||||
mPid = pid;
|
||||
mPackageName = packageName;
|
||||
mTrusted = trusted;
|
||||
@@ -997,7 +1105,7 @@ public final class MediaRouterService extends IMediaRouterService.Stub
|
||||
try {
|
||||
mTempClients.get(i).onStateChanged();
|
||||
} catch (RemoteException ex) {
|
||||
// ignore errors, client probably died
|
||||
Slog.w(TAG, "Failed to call onStateChanged. Client probably died.");
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
|
||||
@@ -136,19 +136,20 @@ public class MediaSessionService extends SystemService implements Monitor {
|
||||
mKeyguardManager =
|
||||
(KeyguardManager) getContext().getSystemService(Context.KEYGUARD_SERVICE);
|
||||
mAudioService = getAudioService();
|
||||
mAudioPlaybackMonitor = new AudioPlaybackMonitor(getContext(), mAudioService,
|
||||
mAudioPlaybackMonitor = AudioPlaybackMonitor.getInstance(getContext(), mAudioService);
|
||||
mAudioPlaybackMonitor.registerOnAudioPlaybackStartedListener(
|
||||
new AudioPlaybackMonitor.OnAudioPlaybackStartedListener() {
|
||||
@Override
|
||||
public void onAudioPlaybackStarted(int uid) {
|
||||
synchronized (mLock) {
|
||||
FullUserRecord user =
|
||||
getFullUserRecordLocked(UserHandle.getUserId(uid));
|
||||
if (user != null) {
|
||||
user.mPriorityStack.updateMediaButtonSessionIfNeeded();
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void onAudioPlaybackStarted(int uid) {
|
||||
synchronized (mLock) {
|
||||
FullUserRecord user =
|
||||
getFullUserRecordLocked(UserHandle.getUserId(uid));
|
||||
if (user != null) {
|
||||
user.mPriorityStack.updateMediaButtonSessionIfNeeded();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
mAudioManagerInternal = LocalServices.getService(AudioManagerInternal.class);
|
||||
mContentResolver = getContext().getContentResolver();
|
||||
mSettingsObserver = new SettingsObserver();
|
||||
|
||||
Reference in New Issue
Block a user