Merge "MediaSessionService: Support managed profile" into nyc-mr1-dev
This commit is contained in:
@@ -454,7 +454,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return mPackageName + "/" + mTag;
|
||||
return mPackageName + "/" + mTag + " (uid=" + mUserId + ")";
|
||||
}
|
||||
|
||||
private void postAdjustLocalVolume(final int stream, final int direction, final int flags,
|
||||
|
||||
@@ -47,10 +47,12 @@ import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.os.Message;
|
||||
import android.os.PowerManager;
|
||||
import android.os.Process;
|
||||
import android.os.RemoteException;
|
||||
import android.os.ResultReceiver;
|
||||
import android.os.ServiceManager;
|
||||
import android.os.UserHandle;
|
||||
import android.os.UserManager;
|
||||
import android.provider.Settings;
|
||||
import android.speech.RecognizerIntent;
|
||||
import android.text.TextUtils;
|
||||
@@ -67,6 +69,7 @@ import com.android.server.Watchdog.Monitor;
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -97,7 +100,9 @@ public class MediaSessionService extends SystemService implements Monitor {
|
||||
private ContentResolver mContentResolver;
|
||||
private SettingsObserver mSettingsObserver;
|
||||
|
||||
private int mCurrentUserId = -1;
|
||||
// List of user IDs running in the foreground.
|
||||
// Multiple users can be in the foreground if the work profile is on.
|
||||
private final List<Integer> mCurrentUserIdList = new ArrayList<>();
|
||||
|
||||
// Used to notify system UI when remote volume was changed. TODO find a
|
||||
// better way to handle this.
|
||||
@@ -181,22 +186,26 @@ public class MediaSessionService extends SystemService implements Monitor {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStartUser(int userHandle) {
|
||||
public void onStartUser(int userId) {
|
||||
if (DEBUG) Log.d(TAG, "onStartUser: " + userId);
|
||||
updateUser();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSwitchUser(int userHandle) {
|
||||
public void onSwitchUser(int userId) {
|
||||
if (DEBUG) Log.d(TAG, "onSwitchUser: " + userId);
|
||||
updateUser();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStopUser(int userHandle) {
|
||||
public void onStopUser(int userId) {
|
||||
if (DEBUG) Log.d(TAG, "onStopUser: " + userId);
|
||||
synchronized (mLock) {
|
||||
UserRecord user = mUserRecords.get(userHandle);
|
||||
UserRecord user = mUserRecords.get(userId);
|
||||
if (user != null) {
|
||||
destroyUserLocked(user);
|
||||
}
|
||||
updateUser();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -228,18 +237,23 @@ public class MediaSessionService extends SystemService implements Monitor {
|
||||
|
||||
private void updateUser() {
|
||||
synchronized (mLock) {
|
||||
int userId = ActivityManager.getCurrentUser();
|
||||
if (mCurrentUserId != userId) {
|
||||
final int oldUserId = mCurrentUserId;
|
||||
mCurrentUserId = userId; // do this first
|
||||
|
||||
UserRecord oldUser = mUserRecords.get(oldUserId);
|
||||
if (oldUser != null) {
|
||||
oldUser.stopLocked();
|
||||
UserManager manager = (UserManager) getContext().getSystemService(Context.USER_SERVICE);
|
||||
int currentUser = ActivityManager.getCurrentUser();
|
||||
int[] userIds = manager.getEnabledProfileIds(currentUser);
|
||||
mCurrentUserIdList.clear();
|
||||
if (userIds != null && userIds.length > 0) {
|
||||
for (int userId : userIds) {
|
||||
mCurrentUserIdList.add(userId);
|
||||
}
|
||||
} else {
|
||||
// This shouldn't happen.
|
||||
Log.w(TAG, "Failed to get enabled profiles.");
|
||||
mCurrentUserIdList.add(currentUser);
|
||||
}
|
||||
for (int userId : mCurrentUserIdList) {
|
||||
if (mUserRecords.get(userId) == null) {
|
||||
mUserRecords.put(userId, new UserRecord(getContext(), userId));
|
||||
}
|
||||
|
||||
UserRecord newUser = getOrCreateUser(userId);
|
||||
newUser.startLocked();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -272,7 +286,6 @@ public class MediaSessionService extends SystemService implements Monitor {
|
||||
* @param user The user to dispose of
|
||||
*/
|
||||
private void destroyUserLocked(UserRecord user) {
|
||||
user.stopLocked();
|
||||
user.destroyLocked();
|
||||
mUserRecords.remove(user.mUserId);
|
||||
}
|
||||
@@ -436,9 +449,9 @@ public class MediaSessionService extends SystemService implements Monitor {
|
||||
}
|
||||
|
||||
mAllSessions.add(session);
|
||||
mPriorityStack.addSession(session);
|
||||
mPriorityStack.addSession(session, mCurrentUserIdList.contains(userId));
|
||||
|
||||
UserRecord user = getOrCreateUser(userId);
|
||||
UserRecord user = mUserRecords.get(userId);
|
||||
user.addSessionLocked(session);
|
||||
|
||||
mHandler.post(MessageHandler.MSG_SESSIONS_CHANGED, userId, 0);
|
||||
@@ -449,15 +462,6 @@ public class MediaSessionService extends SystemService implements Monitor {
|
||||
return session;
|
||||
}
|
||||
|
||||
private UserRecord getOrCreateUser(int userId) {
|
||||
UserRecord user = mUserRecords.get(userId);
|
||||
if (user == null) {
|
||||
user = new UserRecord(getContext(), userId);
|
||||
mUserRecords.put(userId, user);
|
||||
}
|
||||
return user;
|
||||
}
|
||||
|
||||
private int findIndexOfSessionsListenerLocked(IActiveSessionsListener listener) {
|
||||
for (int i = mSessionsListeners.size() - 1; i >= 0; i--) {
|
||||
if (mSessionsListeners.get(i).mListener.asBinder() == listener.asBinder()) {
|
||||
@@ -536,13 +540,6 @@ public class MediaSessionService extends SystemService implements Monitor {
|
||||
restoreMediaButtonReceiver();
|
||||
}
|
||||
|
||||
public void startLocked() {
|
||||
}
|
||||
|
||||
public void stopLocked() {
|
||||
// nothing for now
|
||||
}
|
||||
|
||||
public void destroyLocked() {
|
||||
for (int i = mSessions.size() - 1; i >= 0; i--) {
|
||||
MediaSessionRecord session = mSessions.get(i);
|
||||
@@ -578,7 +575,7 @@ public class MediaSessionService extends SystemService implements Monitor {
|
||||
|
||||
private void restoreMediaButtonReceiver() {
|
||||
String receiverName = Settings.Secure.getStringForUser(mContentResolver,
|
||||
Settings.System.MEDIA_BUTTON_RECEIVER, UserHandle.USER_CURRENT);
|
||||
Settings.System.MEDIA_BUTTON_RECEIVER, mUserId);
|
||||
if (!TextUtils.isEmpty(receiverName)) {
|
||||
ComponentName eventReceiver = ComponentName.unflattenFromString(receiverName);
|
||||
if (eventReceiver == null) {
|
||||
@@ -767,12 +764,22 @@ public class MediaSessionService extends SystemService implements Monitor {
|
||||
synchronized (mLock) {
|
||||
// If we don't have a media button receiver to fall back on
|
||||
// include non-playing sessions for dispatching
|
||||
UserRecord ur = mUserRecords.get(mCurrentUserId);
|
||||
boolean useNotPlayingSessions = (ur == null) ||
|
||||
(ur.mLastMediaButtonReceiver == null
|
||||
&& ur.mRestoredMediaButtonReceiver == null);
|
||||
MediaSessionRecord session = mPriorityStack
|
||||
.getDefaultMediaButtonSession(mCurrentUserId, useNotPlayingSessions);
|
||||
boolean useNotPlayingSessions = true;
|
||||
for (int userId : mCurrentUserIdList) {
|
||||
UserRecord ur = mUserRecords.get(userId);
|
||||
if (ur.mLastMediaButtonReceiver != null
|
||||
|| ur.mRestoredMediaButtonReceiver != null) {
|
||||
useNotPlayingSessions = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "dispatchMediaKeyEvent, useNotPlayingSessions="
|
||||
+ useNotPlayingSessions);
|
||||
}
|
||||
MediaSessionRecord session = mPriorityStack.getDefaultMediaButtonSession(
|
||||
mCurrentUserIdList, useNotPlayingSessions);
|
||||
if (isVoiceKey(keyEvent.getKeyCode())) {
|
||||
handleVoiceKeyEventLocked(keyEvent, needWakeLock, session);
|
||||
} else {
|
||||
@@ -786,13 +793,11 @@ public class MediaSessionService extends SystemService implements Monitor {
|
||||
|
||||
@Override
|
||||
public void dispatchAdjustVolume(int suggestedStream, int delta, int flags) {
|
||||
final int pid = Binder.getCallingPid();
|
||||
final int uid = Binder.getCallingUid();
|
||||
final long token = Binder.clearCallingIdentity();
|
||||
try {
|
||||
synchronized (mLock) {
|
||||
MediaSessionRecord session = mPriorityStack
|
||||
.getDefaultVolumeSession(mCurrentUserId);
|
||||
.getDefaultVolumeSession(mCurrentUserIdList);
|
||||
dispatchAdjustVolumeLocked(suggestedStream, delta, flags, session);
|
||||
}
|
||||
} finally {
|
||||
@@ -899,7 +904,7 @@ public class MediaSessionService extends SystemService implements Monitor {
|
||||
}
|
||||
} else {
|
||||
session.adjustVolume(direction, flags, getContext().getPackageName(),
|
||||
UserHandle.myUserId(), true);
|
||||
Process.SYSTEM_UID, true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -946,13 +951,16 @@ public class MediaSessionService extends SystemService implements Monitor {
|
||||
// won't release it later
|
||||
session.sendMediaButton(keyEvent,
|
||||
needWakeLock ? mKeyEventReceiver.mLastTimeoutId : -1,
|
||||
mKeyEventReceiver, getContext().getApplicationInfo().uid,
|
||||
mKeyEventReceiver, Process.SYSTEM_UID,
|
||||
getContext().getPackageName());
|
||||
} else {
|
||||
// Launch the last PendingIntent we had with priority
|
||||
UserRecord user = mUserRecords.get(mCurrentUserId);
|
||||
if (user != null && (user.mLastMediaButtonReceiver != null
|
||||
|| user.mRestoredMediaButtonReceiver != null)) {
|
||||
for (int userId : mCurrentUserIdList) {
|
||||
UserRecord user = mUserRecords.get(userId);
|
||||
if (user.mLastMediaButtonReceiver == null
|
||||
&& user.mRestoredMediaButtonReceiver == null) {
|
||||
continue;
|
||||
}
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "Sending media key to last known PendingIntent "
|
||||
+ user.mLastMediaButtonReceiver + " or restored Intent "
|
||||
@@ -972,30 +980,30 @@ public class MediaSessionService extends SystemService implements Monitor {
|
||||
} else {
|
||||
mediaButtonIntent.setComponent(user.mRestoredMediaButtonReceiver);
|
||||
getContext().sendBroadcastAsUser(mediaButtonIntent,
|
||||
new UserHandle(mCurrentUserId));
|
||||
UserHandle.of(userId));
|
||||
}
|
||||
} catch (CanceledException e) {
|
||||
Log.i(TAG, "Error sending key event to media button receiver "
|
||||
+ user.mLastMediaButtonReceiver, e);
|
||||
}
|
||||
} else {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "Sending media key ordered broadcast");
|
||||
}
|
||||
if (needWakeLock) {
|
||||
mMediaEventWakeLock.acquire();
|
||||
}
|
||||
// Fallback to legacy behavior
|
||||
Intent keyIntent = new Intent(Intent.ACTION_MEDIA_BUTTON, null);
|
||||
keyIntent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
|
||||
keyIntent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent);
|
||||
if (needWakeLock) {
|
||||
keyIntent.putExtra(EXTRA_WAKELOCK_ACQUIRED,
|
||||
WAKELOCK_RELEASE_ON_FINISHED);
|
||||
}
|
||||
getContext().sendOrderedBroadcastAsUser(keyIntent, UserHandle.CURRENT,
|
||||
null, mKeyEventDone, mHandler, Activity.RESULT_OK, null, null);
|
||||
return;
|
||||
}
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "Sending media key ordered broadcast");
|
||||
}
|
||||
if (needWakeLock) {
|
||||
mMediaEventWakeLock.acquire();
|
||||
}
|
||||
// Fallback to legacy behavior
|
||||
Intent keyIntent = new Intent(Intent.ACTION_MEDIA_BUTTON, null);
|
||||
keyIntent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
|
||||
keyIntent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent);
|
||||
if (needWakeLock) {
|
||||
keyIntent.putExtra(EXTRA_WAKELOCK_ACQUIRED, WAKELOCK_RELEASE_ON_FINISHED);
|
||||
}
|
||||
// Send broadcast only to the full user.
|
||||
getContext().sendOrderedBroadcastAsUser(keyIntent, UserHandle.CURRENT,
|
||||
null, mKeyEventDone, mHandler, Activity.RESULT_OK, null, null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1025,6 +1033,7 @@ public class MediaSessionService extends SystemService implements Monitor {
|
||||
if (voiceIntent != null) {
|
||||
voiceIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
|
||||
| Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
|
||||
if (DEBUG) Log.d(TAG, "voiceIntent: " + voiceIntent);
|
||||
getContext().startActivityAsUser(voiceIntent, UserHandle.CURRENT);
|
||||
}
|
||||
} catch (ActivityNotFoundException e) {
|
||||
|
||||
@@ -32,7 +32,7 @@ import java.util.List;
|
||||
* Keeps track of media sessions and their priority for notifications, media
|
||||
* button dispatch, etc.
|
||||
*/
|
||||
public class MediaSessionStack {
|
||||
class MediaSessionStack {
|
||||
/**
|
||||
* These are states that usually indicate the user took an action and should
|
||||
* bump priority regardless of the old state.
|
||||
@@ -68,13 +68,10 @@ public class MediaSessionStack {
|
||||
* Checks if a media session is created from the most recent app.
|
||||
*
|
||||
* @param record A media session record to be examined.
|
||||
* @return true if the media session's package name equals to the most recent app, false
|
||||
* otherwise.
|
||||
* @return {@code true} if the media session's package name equals to the most recent app, false
|
||||
* otherwise.
|
||||
*/
|
||||
private static boolean isFromMostRecentApp(MediaSessionRecord record) {
|
||||
if (ActivityManager.getCurrentUser() != record.getUserId()) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
List<ActivityManager.RecentTaskInfo> tasks =
|
||||
ActivityManagerNative.getDefault().getRecentTasks(1,
|
||||
@@ -84,9 +81,10 @@ public class MediaSessionStack {
|
||||
ActivityManager.RECENT_WITH_EXCLUDED, record.getUserId()).getList();
|
||||
if (tasks != null && !tasks.isEmpty()) {
|
||||
ActivityManager.RecentTaskInfo recentTask = tasks.get(0);
|
||||
if (recentTask.baseIntent != null)
|
||||
if (recentTask.userId == record.getUserId() && recentTask.baseIntent != null) {
|
||||
return recentTask.baseIntent.getComponent().getPackageName()
|
||||
.equals(record.getPackageName());
|
||||
}
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
return false;
|
||||
@@ -98,11 +96,12 @@ public class MediaSessionStack {
|
||||
* Add a record to the priority tracker.
|
||||
*
|
||||
* @param record The record to add.
|
||||
* @param fromForegroundUser {@code true} if the session is created by the foreground user.
|
||||
*/
|
||||
public void addSession(MediaSessionRecord record) {
|
||||
public void addSession(MediaSessionRecord record, boolean fromForegroundUser) {
|
||||
mSessions.add(record);
|
||||
clearCache();
|
||||
if (isFromMostRecentApp(record)) {
|
||||
if (fromForegroundUser && isFromMostRecentApp(record)) {
|
||||
mLastInterestingRecord = record;
|
||||
}
|
||||
}
|
||||
@@ -210,12 +209,13 @@ public class MediaSessionStack {
|
||||
/**
|
||||
* Get the highest priority session that can handle media buttons.
|
||||
*
|
||||
* @param userId The user to check.
|
||||
* @param userIdList The user lists to check.
|
||||
* @param includeNotPlaying Return a non-playing session if nothing else is
|
||||
* available
|
||||
* @return The default media button session or null.
|
||||
*/
|
||||
public MediaSessionRecord getDefaultMediaButtonSession(int userId, boolean includeNotPlaying) {
|
||||
public MediaSessionRecord getDefaultMediaButtonSession(
|
||||
List<Integer> userIdList, boolean includeNotPlaying) {
|
||||
if (mGlobalPrioritySession != null && mGlobalPrioritySession.isActive()) {
|
||||
return mGlobalPrioritySession;
|
||||
}
|
||||
@@ -223,7 +223,7 @@ public class MediaSessionStack {
|
||||
return mCachedButtonReceiver;
|
||||
}
|
||||
ArrayList<MediaSessionRecord> records = getPriorityListLocked(true,
|
||||
MediaSession.FLAG_HANDLES_MEDIA_BUTTONS, userId);
|
||||
MediaSession.FLAG_HANDLES_MEDIA_BUTTONS, userIdList);
|
||||
if (records.size() > 0) {
|
||||
MediaSessionRecord record = records.get(0);
|
||||
if (record.isPlaybackActive(false)) {
|
||||
@@ -248,14 +248,14 @@ public class MediaSessionStack {
|
||||
return mCachedButtonReceiver;
|
||||
}
|
||||
|
||||
public MediaSessionRecord getDefaultVolumeSession(int userId) {
|
||||
public MediaSessionRecord getDefaultVolumeSession(List<Integer> userIdList) {
|
||||
if (mGlobalPrioritySession != null && mGlobalPrioritySession.isActive()) {
|
||||
return mGlobalPrioritySession;
|
||||
}
|
||||
if (mCachedVolumeDefault != null) {
|
||||
return mCachedVolumeDefault;
|
||||
}
|
||||
ArrayList<MediaSessionRecord> records = getPriorityListLocked(true, 0, userId);
|
||||
ArrayList<MediaSessionRecord> records = getPriorityListLocked(true, 0, userIdList);
|
||||
int size = records.size();
|
||||
for (int i = 0; i < size; i++) {
|
||||
MediaSessionRecord record = records.get(i);
|
||||
@@ -298,6 +298,13 @@ public class MediaSessionStack {
|
||||
}
|
||||
}
|
||||
|
||||
private ArrayList<MediaSessionRecord> getPriorityListLocked(boolean activeOnly, int withFlags,
|
||||
int userId) {
|
||||
List<Integer> userIdList = new ArrayList<>();
|
||||
userIdList.add(userId);
|
||||
return getPriorityListLocked(activeOnly, withFlags, userIdList);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a priority sorted list of sessions. Can filter to only return active
|
||||
* sessions or sessions with specific flags.
|
||||
@@ -306,22 +313,23 @@ public class MediaSessionStack {
|
||||
* all sessions.
|
||||
* @param withFlags Only return sessions with all the specified flags set. 0
|
||||
* returns all sessions.
|
||||
* @param userId The user to get sessions for. {@link UserHandle#USER_ALL}
|
||||
* @param userIdList The user to get sessions for. {@link UserHandle#USER_ALL}
|
||||
* will return sessions for all users.
|
||||
* @return The priority sorted list of sessions.
|
||||
*/
|
||||
private ArrayList<MediaSessionRecord> getPriorityListLocked(boolean activeOnly, int withFlags,
|
||||
int userId) {
|
||||
List<Integer> userIdList) {
|
||||
ArrayList<MediaSessionRecord> result = new ArrayList<MediaSessionRecord>();
|
||||
int lastLocalIndex = 0;
|
||||
int lastActiveIndex = 0;
|
||||
int lastPublishedIndex = 0;
|
||||
|
||||
boolean filterUser = !userIdList.contains(UserHandle.USER_ALL);
|
||||
int size = mSessions.size();
|
||||
for (int i = 0; i < size; i++) {
|
||||
final MediaSessionRecord session = mSessions.get(i);
|
||||
|
||||
if (userId != UserHandle.USER_ALL && userId != session.getUserId()) {
|
||||
if (filterUser && !userIdList.contains(session.getUserId())) {
|
||||
// Filter out sessions for the wrong user
|
||||
continue;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user