Merge "Restore the selected route when an app starts to make sound"

This commit is contained in:
Sungsoo Lim
2017-06-22 00:11:47 +00:00
committed by Android (Google) Code Review
6 changed files with 288 additions and 54 deletions

View File

@@ -21,4 +21,5 @@ package android.media;
*/
oneway interface IMediaRouterClient {
void onStateChanged();
void onRestoreRoute();
}

View File

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

View File

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

View File

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

View File

@@ -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 {

View File

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